Skip to content

Commit 41f52da

Browse files
authored
feat(optimization): merge pull request #22
2 parents acfa3c5 + 3d7b8a5 commit 41f52da

File tree

13 files changed

+155
-29
lines changed

13 files changed

+155
-29
lines changed

src/ast.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ typedef struct AstStmt
159159
int is_array;
160160
size_t array_size;
161161
AstExpr *array_init;
162+
163+
int is_used;
162164
} decl;
163165
struct
164166
{

src/codegen_lua.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ static void emit_string_literal(FILE *out, const char *value);
2020
static void emit_array_declaration(FILE *out, const AstStmt *stmt, const FunctionTable *functions, int indent);
2121
static void emit_array_literal_expr(FILE *out, const AstExprList *elements, const FunctionTable *functions);
2222
static void emit_array_index(FILE *out, const AstExpr *expr, const FunctionTable *functions);
23+
static int expr_has_side_effects(const AstExpr *expr);
2324
static void emit_array_default_value(FILE *out, TypeKind type);
2425
static const FunctionSignature *lookup_signature(const FunctionTable *functions, const char *name);
2526
static const char *binary_op_token(AstBinaryOp op);
@@ -163,6 +164,19 @@ static void emit_statement(FILE *out, const AstStmt *stmt, const FunctionTable *
163164
emit_block(out, &stmt->data.block, functions, signature, indent, 1);
164165
break;
165166
case STMT_DECL:
167+
if (!stmt->data.decl.is_used && !stmt->data.decl.is_array)
168+
{
169+
if (!stmt->data.decl.init || !expr_has_side_effects(stmt->data.decl.init))
170+
{
171+
return; // Dead Code Elimination: remove unused locals without side effects
172+
}
173+
// Unused variable with initializer that has side effects: emit only the initializer as a statement
174+
emit_indent(out, indent);
175+
emit_expression_expected(out, stmt->data.decl.init, functions, stmt->data.decl.type);
176+
fputc('\n', out);
177+
return;
178+
}
179+
166180
if (stmt->data.decl.is_array)
167181
{
168182
emit_array_declaration(out, stmt, functions, indent);
@@ -391,6 +405,43 @@ static void emit_expression_raw(FILE *out, const AstExpr *expr, const FunctionTa
391405
}
392406
}
393407

408+
static int expr_has_side_effects(const AstExpr *expr)
409+
{
410+
if (!expr)
411+
{
412+
return 0;
413+
}
414+
415+
switch (expr->kind)
416+
{
417+
case EXPR_CALL:
418+
return 1;
419+
case EXPR_BINARY:
420+
return expr_has_side_effects(expr->data.binary.left) || expr_has_side_effects(expr->data.binary.right);
421+
case EXPR_UNARY:
422+
return expr_has_side_effects(expr->data.unary.operand);
423+
case EXPR_SUBSCRIPT:
424+
return expr_has_side_effects(expr->data.subscript.array) || expr_has_side_effects(expr->data.subscript.index);
425+
case EXPR_ARRAY_LITERAL:
426+
for (size_t i = 0; i < expr->data.array_literal.elements.count; ++i)
427+
{
428+
if (expr_has_side_effects(expr->data.array_literal.elements.items[i]))
429+
{
430+
return 1;
431+
}
432+
}
433+
return 0;
434+
case EXPR_IDENTIFIER:
435+
case EXPR_INT_LITERAL:
436+
case EXPR_FLOAT_LITERAL:
437+
case EXPR_BOOL_LITERAL:
438+
case EXPR_STRING_LITERAL:
439+
return 0;
440+
default:
441+
return 0;
442+
}
443+
}
444+
394445
static void emit_expression_as_bool(FILE *out, const AstExpr *expr, const FunctionTable *functions)
395446
{
396447
if (!expr)

src/optimizer.c

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ typedef struct
88
{
99
AstExpr **location;
1010
size_t stmt_index;
11+
AstStmt *stmt;
1112
} CseOccurrence;
1213

1314
typedef struct
@@ -32,15 +33,15 @@ static void optimize_block(AstBlock *block);
3233
static void optimize_statement_children(AstStmt *stmt);
3334
static void collect_block_candidates(AstBlock *block, CseEntryList *entries);
3435
static void collect_statement_candidates(AstStmt *stmt, size_t stmt_index, CseEntryList *entries);
35-
static void collect_expr_candidates(AstExpr **expr_ptr, size_t stmt_index, CseEntryList *entries);
36+
static void collect_expr_candidates(AstExpr **expr_ptr, size_t stmt_index, AstStmt *owner, CseEntryList *entries);
3637
static int expr_is_constant(const AstExpr *expr);
3738
static int expr_is_candidate(const AstExpr *expr);
3839
static char *expr_make_key(const AstExpr *expr);
39-
static void register_candidate(CseEntryList *entries, AstExpr **expr_ptr, size_t stmt_index);
40+
static void register_candidate(CseEntryList *entries, AstExpr **expr_ptr, size_t stmt_index, AstStmt *owner);
4041
static CseEntry *find_entry(CseEntryList *entries, const char *key);
4142
static void ensure_entry_capacity(CseEntryList *list, size_t needed);
4243
static void ensure_occ_capacity(CseEntry *entry, size_t needed);
43-
static void add_occurrence(CseEntry *entry, AstExpr **location, size_t stmt_index);
44+
static void add_occurrence(CseEntry *entry, AstExpr **location, size_t stmt_index, AstStmt *stmt);
4445
static void apply_cse(AstBlock *block, CseEntryList *entries);
4546
static void insert_statement(AstStmtList *list, size_t index, AstStmt *stmt);
4647
static AstExpr *make_temp_identifier(const char *name, TypeKind type);
@@ -49,6 +50,7 @@ static void free_entries(CseEntryList *entries);
4950
static char *dup_string(const char *value);
5051
static void *xmalloc(size_t size);
5152
static int compare_entries_by_index(const void *lhs, const void *rhs);
53+
static int occurrence_survives_dce(const CseOccurrence *occ);
5254

5355
void optimize_program(AstProgram *program)
5456
{
@@ -138,20 +140,20 @@ static void collect_statement_candidates(AstStmt *stmt, size_t stmt_index, CseEn
138140
case STMT_DECL:
139141
if (!stmt->data.decl.is_array && stmt->data.decl.init)
140142
{
141-
collect_expr_candidates(&stmt->data.decl.init, stmt_index, entries);
143+
collect_expr_candidates(&stmt->data.decl.init, stmt_index, stmt, entries);
142144
}
143145
break;
144146
case STMT_ASSIGN:
145-
collect_expr_candidates(&stmt->data.assign.value, stmt_index, entries);
147+
collect_expr_candidates(&stmt->data.assign.value, stmt_index, stmt, entries);
146148
break;
147149
case STMT_ARRAY_ASSIGN:
148-
collect_expr_candidates(&stmt->data.array_assign.value, stmt_index, entries);
150+
collect_expr_candidates(&stmt->data.array_assign.value, stmt_index, stmt, entries);
149151
break;
150152
case STMT_EXPR:
151153
case STMT_RETURN:
152154
if (stmt->data.expr)
153155
{
154-
collect_expr_candidates(&stmt->data.expr, stmt_index, entries);
156+
collect_expr_candidates(&stmt->data.expr, stmt_index, stmt, entries);
155157
}
156158
break;
157159
case STMT_WHILE:
@@ -164,7 +166,7 @@ static void collect_statement_candidates(AstStmt *stmt, size_t stmt_index, CseEn
164166
}
165167
}
166168

167-
static void collect_expr_candidates(AstExpr **expr_ptr, size_t stmt_index, CseEntryList *entries)
169+
static void collect_expr_candidates(AstExpr **expr_ptr, size_t stmt_index, AstStmt *owner, CseEntryList *entries)
168170
{
169171
if (!expr_ptr || !*expr_ptr)
170172
{
@@ -176,35 +178,35 @@ static void collect_expr_candidates(AstExpr **expr_ptr, size_t stmt_index, CseEn
176178
switch (expr->kind)
177179
{
178180
case EXPR_BINARY:
179-
collect_expr_candidates(&expr->data.binary.left, stmt_index, entries);
180-
collect_expr_candidates(&expr->data.binary.right, stmt_index, entries);
181+
collect_expr_candidates(&expr->data.binary.left, stmt_index, owner, entries);
182+
collect_expr_candidates(&expr->data.binary.right, stmt_index, owner, entries);
181183
break;
182184
case EXPR_UNARY:
183-
collect_expr_candidates(&expr->data.unary.operand, stmt_index, entries);
185+
collect_expr_candidates(&expr->data.unary.operand, stmt_index, owner, entries);
184186
break;
185187
case EXPR_CALL:
186188
for (size_t i = 0; i < expr->data.call.args.count; ++i)
187189
{
188-
collect_expr_candidates(&expr->data.call.args.items[i], stmt_index, entries);
190+
collect_expr_candidates(&expr->data.call.args.items[i], stmt_index, owner, entries);
189191
}
190192
break;
191193
case EXPR_ARRAY_LITERAL:
192194
for (size_t i = 0; i < expr->data.array_literal.elements.count; ++i)
193195
{
194-
collect_expr_candidates(&expr->data.array_literal.elements.items[i], stmt_index, entries);
196+
collect_expr_candidates(&expr->data.array_literal.elements.items[i], stmt_index, owner, entries);
195197
}
196198
break;
197199
case EXPR_SUBSCRIPT:
198-
collect_expr_candidates(&expr->data.subscript.array, stmt_index, entries);
199-
collect_expr_candidates(&expr->data.subscript.index, stmt_index, entries);
200+
collect_expr_candidates(&expr->data.subscript.array, stmt_index, owner, entries);
201+
collect_expr_candidates(&expr->data.subscript.index, stmt_index, owner, entries);
200202
break;
201203
default:
202204
break;
203205
}
204206

205207
if (expr_is_candidate(expr))
206208
{
207-
register_candidate(entries, expr_ptr, stmt_index);
209+
register_candidate(entries, expr_ptr, stmt_index, owner);
208210
}
209211
}
210212

@@ -244,7 +246,7 @@ static int expr_is_candidate(const AstExpr *expr)
244246
return expr_is_constant(expr);
245247
}
246248

247-
static void register_candidate(CseEntryList *entries, AstExpr **expr_ptr, size_t stmt_index)
249+
static void register_candidate(CseEntryList *entries, AstExpr **expr_ptr, size_t stmt_index, AstStmt *owner)
248250
{
249251
if (!entries || !expr_ptr || !*expr_ptr)
250252
{
@@ -273,7 +275,7 @@ static void register_candidate(CseEntryList *entries, AstExpr **expr_ptr, size_t
273275
entry->first_stmt_index = stmt_index;
274276
}
275277
}
276-
add_occurrence(entry, expr_ptr, stmt_index);
278+
add_occurrence(entry, expr_ptr, stmt_index, owner);
277279
}
278280

279281
static CseEntry *find_entry(CseEntryList *entries, const char *key)
@@ -342,7 +344,7 @@ static void ensure_occ_capacity(CseEntry *entry, size_t needed)
342344
entry->occurrence_capacity = new_capacity;
343345
}
344346

345-
static void add_occurrence(CseEntry *entry, AstExpr **location, size_t stmt_index)
347+
static void add_occurrence(CseEntry *entry, AstExpr **location, size_t stmt_index, AstStmt *stmt)
346348
{
347349
if (!entry)
348350
{
@@ -351,6 +353,7 @@ static void add_occurrence(CseEntry *entry, AstExpr **location, size_t stmt_inde
351353
ensure_occ_capacity(entry, entry->occurrence_count + 1);
352354
entry->occurrences[entry->occurrence_count].location = location;
353355
entry->occurrences[entry->occurrence_count].stmt_index = stmt_index;
356+
entry->occurrences[entry->occurrence_count].stmt = stmt;
354357
entry->occurrence_count++;
355358
}
356359

@@ -411,7 +414,21 @@ static void apply_cse(AstBlock *block, CseEntryList *entries)
411414
}
412415
}
413416

417+
int has_live_use = 0;
418+
for (size_t j = 0; j < entry->occurrence_count; ++j)
419+
{
420+
if (occurrence_survives_dce(&entry->occurrences[j]))
421+
{
422+
has_live_use = 1;
423+
break;
424+
}
425+
}
426+
414427
AstStmt *decl = ast_stmt_make_decl(entry->type, dup_string(temp_name), init_expr);
428+
if (has_live_use)
429+
{
430+
decl->data.decl.is_used = 1; /* mark as live so DCE keeps this temp */
431+
}
415432
insert_statement(&block->statements, entry->first_stmt_index + inserted, decl);
416433
inserted++;
417434
free(temp_name);
@@ -520,6 +537,19 @@ static int compare_entries_by_index(const void *lhs, const void *rhs)
520537
return 0;
521538
}
522539

540+
static int occurrence_survives_dce(const CseOccurrence *occ)
541+
{
542+
if (!occ || !occ->stmt)
543+
{
544+
return 1;
545+
}
546+
if (occ->stmt->kind != STMT_DECL)
547+
{
548+
return 1;
549+
}
550+
return occ->stmt->data.decl.is_used != 0;
551+
}
552+
523553
static char *expr_make_key(const AstExpr *expr)
524554
{
525555
if (!expr)
@@ -531,9 +561,12 @@ static char *expr_make_key(const AstExpr *expr)
531561
{
532562
case EXPR_INT_LITERAL:
533563
// Include type information in the key to distinguish between int and char literals
534-
if (expr->type == TYPE_CHAR) {
564+
if (expr->type == TYPE_CHAR)
565+
{
535566
snprintf(buffer, sizeof(buffer), "C:%lld", expr->data.int_value);
536-
} else {
567+
}
568+
else
569+
{
537570
snprintf(buffer, sizeof(buffer), "I:%lld", expr->data.int_value);
538571
}
539572
return dup_string(buffer);

src/semantic.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static int analyze_function(SemanticInfo *info, AstFunction *fn)
8888
symbol_table_free(&symbols);
8989
return 0;
9090
}
91-
if (!symbol_table_add(&symbols, param->name, param->type, 0, 0, TYPE_UNKNOWN))
91+
if (!symbol_table_add(&symbols, param->name, param->type, 0, 0, TYPE_UNKNOWN, NULL))
9292
{
9393
semantic_error("duplicate parameter '%s' in function '%s'", param->name, fn->name);
9494
symbol_table_free(&symbols);
@@ -184,7 +184,8 @@ static int analyze_statement(SemanticInfo *info, AstFunction *fn, SymbolTable *s
184184
TYPE_ARRAY,
185185
1,
186186
stmt->data.decl.array_size,
187-
stmt->data.decl.type))
187+
stmt->data.decl.type,
188+
stmt))
188189
{
189190
semantic_error("duplicate declaration of '%s' in function '%s'", stmt->data.decl.name, fn->name);
190191
return 0;
@@ -222,7 +223,7 @@ static int analyze_statement(SemanticInfo *info, AstFunction *fn, SymbolTable *s
222223
}
223224
else
224225
{
225-
if (!symbol_table_add(symbols, stmt->data.decl.name, stmt->data.decl.type, 0, 0, TYPE_UNKNOWN))
226+
if (!symbol_table_add(symbols, stmt->data.decl.name, stmt->data.decl.type, 0, 0, TYPE_UNKNOWN, stmt))
226227
{
227228
semantic_error("duplicate declaration of '%s' in function '%s'", stmt->data.decl.name, fn->name);
228229
return 0;
@@ -448,6 +449,11 @@ static TypeKind analyze_expression(SemanticInfo *info, SymbolTable *symbols, Ast
448449
expr->type = TYPE_UNKNOWN;
449450
return expr->type;
450451
}
452+
if (symbol->stmt_ref)
453+
{
454+
symbol->stmt_ref->data.decl.is_used = 1;
455+
}
456+
451457
expr->type = symbol->type;
452458
return expr->type;
453459
}

src/symbol_table.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ void symbol_table_pop_scope(SymbolTable *table)
109109
table->depth--;
110110
}
111111

112-
int symbol_table_add(SymbolTable *table, const char *name, TypeKind type, int is_array, size_t array_size, TypeKind element_type)
112+
int symbol_table_add(SymbolTable *table, const char *name, TypeKind type, int is_array, size_t array_size, TypeKind element_type, AstStmt *stmt_ref)
113113
{
114114
if (!table || table->depth == 0 || !name)
115115
{
@@ -129,6 +129,8 @@ int symbol_table_add(SymbolTable *table, const char *name, TypeKind type, int is
129129
scope->items[scope->count].is_array = is_array ? 1 : 0;
130130
scope->items[scope->count].array_size = array_size;
131131
scope->items[scope->count].element_type = element_type;
132+
scope->items[scope->count].stmt_ref = stmt_ref;
133+
132134
scope->count++;
133135
return 1;
134136
}

src/symbol_table.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ typedef struct
1010
int is_array;
1111
size_t array_size;
1212
TypeKind element_type;
13+
struct AstStmt *stmt_ref;
1314
} Symbol;
1415

1516
typedef struct
@@ -44,7 +45,7 @@ void symbol_table_init(SymbolTable *table);
4445
void symbol_table_free(SymbolTable *table);
4546
void symbol_table_push_scope(SymbolTable *table);
4647
void symbol_table_pop_scope(SymbolTable *table);
47-
int symbol_table_add(SymbolTable *table, const char *name, TypeKind type, int is_array, size_t array_size, TypeKind element_type);
48+
int symbol_table_add(SymbolTable *table, const char *name, TypeKind type, int is_array, size_t array_size, TypeKind element_type, struct AstStmt *stmt_ref);
4849
const Symbol *symbol_table_lookup(const SymbolTable *table, const char *name);
4950

5051
void function_table_init(FunctionTable *table);

tests/pass/arith.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ int main()
66
int x = 7;
77
int y = 3;
88
int z = x % y; // ok: % em inteiros
9-
return x;
9+
printf("%f %d\n", c, z);
10+
return 0;
1011
}

tests/pass/arith.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ os.exit((function(args)
55
local x = 7
66
local y = 3
77
local z = (x % y)
8-
return x
8+
print(string.format("%f %d", c, z))
9+
return 0
910
end)(arg))

tests/pass/dead_variable.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
int main()
2+
{
3+
int a = 10;
4+
int b = 5 + 1;
5+
int c = 5 + 1;
6+
return 0;
7+
}

tests/pass/dead_variable.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
os.exit((function(args)
2+
return 0
3+
end)(arg))

0 commit comments

Comments
 (0)