Skip to content

Commit 999b021

Browse files
committed
Add parse-time constant folding
This implements constant folding during expression parsing to evaluate compile-time constants like "2 + 3" → "5" before IR generation, covering arithmetic, bitwise, and comparison operations with proper error handling. It complement existing SSA optimizer without conflicts.
1 parent b09e0e5 commit 999b021

File tree

5 files changed

+98
-12
lines changed

5 files changed

+98
-12
lines changed

src/parser.c

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,10 +2266,96 @@ void read_expr(block_t *parent, basic_block_t **bb)
22662266
opcode_t top_op = oper_stack[--oper_stack_idx];
22672267
rs2 = opstack_pop();
22682268
rs1 = opstack_pop();
2269-
vd = require_var(parent);
2270-
gen_name_to(vd->var_name);
2271-
opstack_push(vd);
2272-
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2269+
2270+
/* Constant folding for binary operations */
2271+
if (rs1 && rs2 && rs1->init_val && !rs1->is_ptr && !rs1->is_global &&
2272+
rs2->init_val && !rs2->is_ptr && !rs2->is_global) {
2273+
/* Both operands are compile-time constants */
2274+
int result = 0;
2275+
bool folded = true;
2276+
2277+
switch (top_op) {
2278+
case OP_add:
2279+
result = rs1->init_val + rs2->init_val;
2280+
break;
2281+
case OP_sub:
2282+
result = rs1->init_val - rs2->init_val;
2283+
break;
2284+
case OP_mul:
2285+
result = rs1->init_val * rs2->init_val;
2286+
break;
2287+
case OP_div:
2288+
if (rs2->init_val != 0)
2289+
result = rs1->init_val / rs2->init_val;
2290+
else
2291+
folded = false; /* Division by zero */
2292+
break;
2293+
case OP_mod:
2294+
if (rs2->init_val != 0)
2295+
result = rs1->init_val % rs2->init_val;
2296+
else
2297+
folded = false; /* Modulo by zero */
2298+
break;
2299+
case OP_bit_and:
2300+
result = rs1->init_val & rs2->init_val;
2301+
break;
2302+
case OP_bit_or:
2303+
result = rs1->init_val | rs2->init_val;
2304+
break;
2305+
case OP_bit_xor:
2306+
result = rs1->init_val ^ rs2->init_val;
2307+
break;
2308+
case OP_lshift:
2309+
result = rs1->init_val << rs2->init_val;
2310+
break;
2311+
case OP_rshift:
2312+
result = rs1->init_val >> rs2->init_val;
2313+
break;
2314+
case OP_eq:
2315+
result = rs1->init_val == rs2->init_val;
2316+
break;
2317+
case OP_neq:
2318+
result = rs1->init_val != rs2->init_val;
2319+
break;
2320+
case OP_lt:
2321+
result = rs1->init_val < rs2->init_val;
2322+
break;
2323+
case OP_leq:
2324+
result = rs1->init_val <= rs2->init_val;
2325+
break;
2326+
case OP_gt:
2327+
result = rs1->init_val > rs2->init_val;
2328+
break;
2329+
case OP_geq:
2330+
result = rs1->init_val >= rs2->init_val;
2331+
break;
2332+
default:
2333+
folded = false;
2334+
break;
2335+
}
2336+
2337+
if (folded) {
2338+
/* Create constant result */
2339+
vd = require_var(parent);
2340+
gen_name_to(vd->var_name);
2341+
vd->init_val = result;
2342+
opstack_push(vd);
2343+
add_insn(parent, *bb, OP_load_constant, vd, NULL, NULL, 0,
2344+
NULL);
2345+
} else {
2346+
/* Normal operation - folding failed or not supported */
2347+
vd = require_var(parent);
2348+
gen_name_to(vd->var_name);
2349+
opstack_push(vd);
2350+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2351+
}
2352+
} else {
2353+
/* Normal operation */
2354+
vd = require_var(parent);
2355+
gen_name_to(vd->var_name);
2356+
opstack_push(vd);
2357+
add_insn(parent, *bb, top_op, vd, rs1, rs2, 0, NULL);
2358+
}
22732359
}
22742360
while (has_prev_log_op) {
22752361
finalize_logical(
@@ -3038,16 +3124,16 @@ int eval_expression_imm(opcode_t op, int op1, int op2)
30383124
res = op1 != op2;
30393125
break;
30403126
case OP_lt:
3041-
res = op1 < op2 ? 1 : 0;
3127+
res = op1 < op2;
30423128
break;
30433129
case OP_gt:
3044-
res = op1 > op2 ? 1 : 0;
3130+
res = op1 > op2;
30453131
break;
30463132
case OP_leq:
3047-
res = op1 <= op2 ? 1 : 0;
3133+
res = op1 <= op2;
30483134
break;
30493135
case OP_geq:
3050-
res = op1 >= op2 ? 1 : 0;
3136+
res = op1 >= op2;
30513137
break;
30523138
default:
30533139
error("The requested operation is not supported.");

tests/snapshots/fib-arm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/fib-riscv.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello-arm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/snapshots/hello-riscv.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)