Skip to content

Commit d5dcdbd

Browse files
authored
Implement constant optimization (#116)
Consider the following scenario: int a = 2; /* constant assignment */ int b = a; /* assignment via constant representation */ int c = a + b; int d = c + 8; /* mixed assignment */ return a + b + c + d; /* chained assignment */ The current code generator emits the assembly below, even though the variables a, b, c, d are all constant representations. mov r0, #2 mov r1, r0 mov r0, r1 add r3, r1, r0 mov r2, #8 add r2, r3, r2 add r4, r1, r0 add r0, r4, r3 add r1, r0, r2 mov r0, r1 The new constant optimizer will evaluate the constant representations, trim the unused variables, and emit 'mov r0, #20' only.
1 parent 393b441 commit d5dcdbd

File tree

5 files changed

+117
-4
lines changed

5 files changed

+117
-4
lines changed

src/defs.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
#define MAX_PARAMS 8
1717
#define MAX_LOCALS 1450
1818
#define MAX_FIELDS 32
19-
#define MAX_FUNCS 256
20-
#define MAX_FUNC_TRIES 1950
19+
#define MAX_FUNCS 512
20+
#define MAX_FUNC_TRIES 2160
2121
#define MAX_BLOCKS 1150
2222
#define MAX_TYPES 64
2323
#define MAX_IR_INSTR 36864
@@ -175,6 +175,7 @@ struct var {
175175
ref_block_list_t ref_block_list; /* blocks which kill variable */
176176
int consumed;
177177
int is_ternary_ret;
178+
int is_const; /* whether a constant representaion or not */
178179
};
179180

180181
typedef struct var var_t;

src/parser.c

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ var_t *require_var(block_t *blk)
2828
error("Too many locals");
2929

3030
var_t *var = &blk->locals[blk->next_local++];
31+
var->consumed = -1;
3132
var->base = var;
3233
return var;
3334
}

src/reg-alloc.c

+15
Original file line numberDiff line numberDiff line change
@@ -383,10 +383,22 @@ void reg_alloc()
383383
break;
384384
case OP_load_constant:
385385
case OP_load_data_address:
386+
if (insn->rd->consumed == -1)
387+
break;
388+
386389
dest = prepare_dest(bb, insn->rd, -1, -1);
387390
ir = bb_add_ph2_ir(bb, insn->opcode);
388391
ir->src0 = insn->rd->init_val;
389392
ir->dest = dest;
393+
394+
/* store global variable immediately after assignment */
395+
if (insn->rd->is_global) {
396+
ir = bb_add_ph2_ir(bb, OP_global_store);
397+
ir->src0 = dest;
398+
ir->src1 = insn->rd->offset;
399+
REGS[dest].polluted = 0;
400+
}
401+
390402
break;
391403
case OP_address_of:
392404
/* make sure variable is on stack */
@@ -412,6 +424,9 @@ void reg_alloc()
412424
ir->dest = dest;
413425
break;
414426
case OP_assign:
427+
if (insn->rd->consumed == -1)
428+
break;
429+
415430
src0 = find_in_regs(insn->rs1);
416431

417432
/* If operand is loaded from stack, clear the original slot

src/ssa.c

+83-1
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,87 @@ int cse(insn_t *insn, basic_block_t *bb)
11111111
return 1;
11121112
}
11131113

1114+
int mark_const(insn_t *insn)
1115+
{
1116+
if (insn->opcode == OP_load_constant) {
1117+
insn->rd->is_const = 1;
1118+
return 0;
1119+
}
1120+
if (insn->opcode != OP_assign)
1121+
return 0;
1122+
/* The global variable is unique and has no subscripts in our SSA. Do NOT
1123+
* evaluate its value.
1124+
*/
1125+
if (insn->rd->is_global)
1126+
return 0;
1127+
if (!insn->rs1->is_const) {
1128+
if (!insn->prev)
1129+
return 0;
1130+
if (insn->prev->opcode != OP_load_constant)
1131+
return 0;
1132+
if (insn->rs1 != insn->prev->rd)
1133+
return 0;
1134+
}
1135+
1136+
insn->opcode = OP_load_constant;
1137+
insn->rd->is_const = 1;
1138+
insn->rd->init_val = insn->rs1->init_val;
1139+
insn->rs1 = NULL;
1140+
return 1;
1141+
}
1142+
1143+
int eval_const_arithmetic(insn_t *insn)
1144+
{
1145+
if (!insn->rs1)
1146+
return 0;
1147+
if (!insn->rs1->is_const)
1148+
return 0;
1149+
if (!insn->rs2)
1150+
return 0;
1151+
if (!insn->rs2->is_const)
1152+
return 0;
1153+
1154+
int res;
1155+
int l = insn->rs1->init_val;
1156+
int r = insn->rs2->init_val;
1157+
1158+
switch (insn->opcode) {
1159+
case OP_add:
1160+
res = l + r;
1161+
break;
1162+
case OP_sub:
1163+
res = l - r;
1164+
break;
1165+
case OP_mul:
1166+
res = l * r;
1167+
break;
1168+
case OP_div:
1169+
res = l / r;
1170+
break;
1171+
case OP_mod:
1172+
res = l % r;
1173+
break;
1174+
default:
1175+
return 0;
1176+
}
1177+
1178+
insn->rs1 = NULL;
1179+
insn->rs2 = NULL;
1180+
insn->rd->is_const = 1;
1181+
insn->rd->init_val = res;
1182+
insn->opcode = OP_load_constant;
1183+
return 1;
1184+
}
1185+
1186+
int const_folding(insn_t *insn)
1187+
{
1188+
if (mark_const(insn))
1189+
return 1;
1190+
if (eval_const_arithmetic(insn))
1191+
return 1;
1192+
return 0;
1193+
}
1194+
11141195
void optimize()
11151196
{
11161197
fn_t *fn;
@@ -1124,7 +1205,8 @@ void optimize()
11241205
for (insn = bb->insn_list.head; insn; insn = insn->next) {
11251206
if (cse(insn, bb))
11261207
continue;
1127-
1208+
if (const_folding(insn))
1209+
continue;
11281210
/* more optimizations */
11291211
}
11301212
}

tests/driver.sh

+15-1
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,9 @@ int main()
547547
}
548548
EOF
549549

550-
# optimizer
550+
# optimizers
551+
552+
# common subexpression elimination (CSE)
551553
try_ 1 << EOF
552554
int i = 0;
553555
void func()
@@ -566,4 +568,16 @@ int main()
566568
}
567569
EOF
568570

571+
# constant folding
572+
try_ 20 << EOF
573+
int main()
574+
{
575+
int a = 2; /* constant assingment */
576+
int b = a; /* assignment via constant representation */
577+
int c = a + b;
578+
int d = c + 8; /* mixed assigment */
579+
return a + b + c + d; /* chained assignment */
580+
}
581+
EOF
582+
569583
echo OK

0 commit comments

Comments
 (0)