Skip to content

Commit e38ad55

Browse files
Liviarodrigues1BeyondMagic
authored andcommitted
feat(optimizer): eliminar if com condição constante
1 parent c92c6e2 commit e38ad55

File tree

5 files changed

+162
-6
lines changed

5 files changed

+162
-6
lines changed

src/optimizer.c

Lines changed: 129 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,126 @@ static char *dup_string(const char *value);
5151
static void *xmalloc(size_t size);
5252
static int compare_entries_by_index(const void *lhs, const void *rhs);
5353
static int occurrence_survives_dce(const CseOccurrence *occ);
54+
55+
static int expr_is_constant_bool(const AstExpr *expr, int *out_value)
56+
{
57+
if (!expr)
58+
return 0;
59+
60+
switch (expr->kind)
61+
{
62+
case EXPR_BOOL_LITERAL:
63+
*out_value = expr->data.bool_value ? 1 : 0;
64+
return 1;
65+
66+
case EXPR_INT_LITERAL:
67+
*out_value = (expr->data.int_value != 0);
68+
return 1;
69+
70+
case EXPR_FLOAT_LITERAL:
71+
*out_value = (expr->data.float_value != 0.0);
72+
return 1;
73+
74+
case EXPR_UNARY:
75+
if (expr->data.unary.op == UN_OP_NOT)
76+
{
77+
int v;
78+
if (!expr_is_constant_bool(expr->data.unary.operand, &v))
79+
return 0;
80+
*out_value = !v;
81+
return 1;
82+
}
83+
return expr_is_constant_bool(expr->data.unary.operand, out_value);
84+
85+
case EXPR_BINARY:
86+
{
87+
int l, r;
88+
if (!expr_is_constant_bool(expr->data.binary.left, &l))
89+
return 0;
90+
if (!expr_is_constant_bool(expr->data.binary.right, &r))
91+
return 0;
92+
93+
switch (expr->data.binary.op)
94+
{
95+
case BIN_OP_AND:
96+
*out_value = l && r;
97+
return 1;
98+
case BIN_OP_OR:
99+
*out_value = l || r;
100+
return 1;
101+
case BIN_OP_EQ:
102+
*out_value = (l == r);
103+
return 1;
104+
case BIN_OP_NEQ:
105+
*out_value = (l != r);
106+
return 1;
107+
default:
108+
return 0;
109+
}
110+
}
111+
112+
default:
113+
return 0;
114+
}
115+
}
116+
117+
static void optimize_if_constants(AstBlock *block)
118+
{
119+
if (!block)
120+
return;
121+
122+
for (size_t i = 0; i < block->statements.count;)
123+
{
124+
AstStmt *stmt = block->statements.items[i];
125+
if (!stmt)
126+
{
127+
i++;
128+
continue;
129+
}
130+
131+
if (stmt->kind == STMT_IF)
132+
{
133+
int cond;
134+
if (expr_is_constant_bool(stmt->data.if_stmt.condition, &cond))
135+
{
136+
AstStmt *replacement = NULL;
137+
138+
if (cond)
139+
{
140+
replacement = stmt->data.if_stmt.then_branch;
141+
stmt->data.if_stmt.then_branch = NULL;
142+
}
143+
else
144+
{
145+
replacement = stmt->data.if_stmt.else_branch;
146+
stmt->data.if_stmt.else_branch = NULL;
147+
}
148+
149+
ast_expr_list_destroy(NULL);
150+
{
151+
}
152+
free(stmt->data.if_stmt.condition);
153+
free(stmt);
154+
155+
if (replacement)
156+
{
157+
block->statements.items[i] = replacement;
158+
continue;
159+
}
160+
else
161+
{
162+
memmove(&block->statements.items[i],
163+
&block->statements.items[i + 1],
164+
(block->statements.count - i - 1) * sizeof(AstStmt *));
165+
block->statements.count--;
166+
continue;
167+
}
168+
}
169+
}
170+
171+
i++;
172+
}
173+
}
54174
static void eliminate_unreachable(AstStmtList *list);
55175

56176
void optimize_program(AstProgram *program)
@@ -81,6 +201,8 @@ static void optimize_block(AstBlock *block)
81201
return;
82202
}
83203

204+
optimize_if_constants(block);
205+
84206
CseEntryList entries = {0};
85207
collect_block_candidates(block, &entries);
86208
apply_cse(block, &entries);
@@ -113,6 +235,11 @@ static void optimize_statement_children(AstStmt *stmt)
113235
optimize_statement_children(stmt->data.for_stmt.body);
114236
optimize_statement_children(stmt->data.for_stmt.post);
115237
break;
238+
case STMT_IF:
239+
optimize_statement_children(stmt->data.if_stmt.then_branch);
240+
if (stmt->data.if_stmt.else_branch)
241+
optimize_statement_children(stmt->data.if_stmt.else_branch);
242+
break;
116243
default:
117244
break;
118245
}
@@ -160,9 +287,9 @@ static void collect_statement_candidates(AstStmt *stmt, size_t stmt_index, CseEn
160287
break;
161288
case STMT_WHILE:
162289
case STMT_FOR:
163-
/* Loop conditions must be evaluated every iteration, so skip them. */
164290
break;
165291
case STMT_BLOCK:
292+
case STMT_IF:
166293
default:
167294
break;
168295
}
@@ -429,7 +556,7 @@ static void apply_cse(AstBlock *block, CseEntryList *entries)
429556
AstStmt *decl = ast_stmt_make_decl(entry->type, dup_string(temp_name), init_expr);
430557
if (has_live_use)
431558
{
432-
decl->data.decl.is_used = 1; /* mark as live so DCE keeps this temp */
559+
decl->data.decl.is_used = 1;
433560
}
434561
insert_statement(&block->statements, entry->first_stmt_index + inserted, decl);
435562
inserted++;
@@ -562,7 +689,6 @@ static char *expr_make_key(const AstExpr *expr)
562689
switch (expr->kind)
563690
{
564691
case EXPR_INT_LITERAL:
565-
// Include type information in the key to distinguish between int and char literals
566692
if (expr->type == TYPE_CHAR)
567693
{
568694
snprintf(buffer, sizeof(buffer), "C:%lld", expr->data.int_value);
@@ -610,7 +736,6 @@ static char *expr_make_key(const AstExpr *expr)
610736
return dup_string("<unsupported>");
611737
}
612738
}
613-
614739
static void eliminate_unreachable(AstStmtList *list)
615740
{
616741
if (!list)

tests/fail/bad_if.err

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
tests/fail/bad_if.c:4:2: syntax error: syntax error
1+
semantic error: if condition in function 'main' must be boolean-compatible but found string

tests/fail/missing_return.err

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
tests/fail/missing_return.c:4:5: syntax error: syntax error
1+
semantic error: function 'f' must return a value

tests/pass/if.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
int main()
2+
{
3+
int a = 1;
4+
if (a == 1)
5+
{
6+
printf("numero: %d\n", a);
7+
}
8+
if (1)
9+
{
10+
printf("verdadeiro: %d\n", a);
11+
}
12+
if (0)
13+
{
14+
printf("falso: %d\n", a);
15+
}
16+
puts("fim");
17+
return 0;
18+
}

tests/pass/if.lua

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
os.exit((function(args)
2+
local a = 1
3+
if (a == 1) then
4+
do
5+
print(string.format("numero: %d", a))
6+
end
7+
end
8+
do
9+
print(string.format("verdadeiro: %d", a))
10+
end
11+
print("fim")
12+
return 0
13+
end)(arg))

0 commit comments

Comments
 (0)