Skip to content

Commit 0bd9bd9

Browse files
authored
Merge pull request #242 from sysprog21/improve-ssa
SSA optimizer enhancements
2 parents 5b9dfe7 + f386319 commit 0bd9bd9

File tree

2 files changed

+711
-134
lines changed

2 files changed

+711
-134
lines changed

src/opt-sccp.c

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/*
2+
* shecc - Self-Hosting and Educational C Compiler.
3+
*
4+
* shecc is freely redistributable under the BSD 2 clause license. See the
5+
* file "LICENSE" for information on usage and redistribution of this file.
6+
*/
7+
8+
/* SCCP (Sparse Conditional Constant Propagation) Optimization Pass
9+
*
10+
* This optimization pass performs:
11+
* - Constant propagation through assignments
12+
* - Constant folding for arithmetic and comparison operations
13+
* - Branch folding when conditions are compile-time constants
14+
* - Dead code elimination through unreachable branch removal
15+
*/
16+
17+
/* Simple constant propagation within basic blocks */
18+
bool simple_sccp(func_t *func)
19+
{
20+
if (!func || !func->bbs)
21+
return false;
22+
23+
bool changed = false;
24+
25+
/* Iterate through basic blocks */
26+
for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) {
27+
/* Process instructions in the block */
28+
for (insn_t *insn = bb->insn_list.head; insn; insn = insn->next) {
29+
/* Skip if no destination */
30+
if (!insn->rd)
31+
continue;
32+
33+
/* Handle simple constant propagation */
34+
switch (insn->opcode) {
35+
case OP_assign:
36+
/* Propagate constants through assignments */
37+
if (insn->rs1 && insn->rs1->is_const && !insn->rd->is_const) {
38+
insn->rd->is_const = true;
39+
insn->rd->init_val = insn->rs1->init_val;
40+
insn->opcode = OP_load_constant;
41+
insn->rs1 = NULL;
42+
changed = true;
43+
}
44+
break;
45+
46+
case OP_trunc:
47+
/* Constant truncation optimization integrated into SCCP */
48+
if (insn->rs1 && insn->rs1->is_const && !insn->rd->is_global &&
49+
insn->sz > 0) {
50+
int value = insn->rs1->init_val;
51+
int result = value;
52+
53+
/* Perform truncation based on size */
54+
if (insn->sz == 1) {
55+
/* Truncate to 8 bits */
56+
result = value & 0xFF;
57+
} else if (insn->sz == 2) {
58+
/* Truncate to 16 bits */
59+
result = value & 0xFFFF;
60+
} else if (insn->sz == 4) {
61+
/* No truncation needed for 32-bit */
62+
result = value;
63+
} else {
64+
/* Invalid size, skip */
65+
break;
66+
}
67+
68+
/* Convert to constant load */
69+
insn->opcode = OP_load_constant;
70+
insn->rd->is_const = true;
71+
insn->rd->init_val = result;
72+
insn->rs1 = NULL;
73+
insn->sz = 0;
74+
changed = true;
75+
}
76+
break;
77+
78+
case OP_sign_ext:
79+
/* Constant sign extension optimization integrated into SCCP */
80+
if (insn->rs1 && insn->rs1->is_const && !insn->rd->is_global &&
81+
insn->sz > 0) {
82+
int value = insn->rs1->init_val;
83+
int result = value;
84+
85+
/* Perform sign extension based on source size */
86+
if (insn->sz == 1) {
87+
/* Sign extend from 8 bits */
88+
result = (value & 0x80) ? (value | 0xFFFFFF00)
89+
: (value & 0xFF);
90+
} else if (insn->sz == 2) {
91+
/* Sign extend from 16 bits */
92+
result = (value & 0x8000) ? (value | 0xFFFF0000)
93+
: (value & 0xFFFF);
94+
} else if (insn->sz == 4) {
95+
/* No sign extension needed for 32-bit */
96+
result = value;
97+
} else {
98+
/* Invalid size, skip */
99+
break;
100+
}
101+
102+
/* Convert to constant load */
103+
insn->opcode = OP_load_constant;
104+
insn->rd->is_const = true;
105+
insn->rd->init_val = result;
106+
insn->rs1 = NULL;
107+
insn->sz = 0;
108+
changed = true;
109+
}
110+
break;
111+
112+
case OP_add:
113+
case OP_sub:
114+
case OP_mul:
115+
case OP_eq:
116+
case OP_neq:
117+
case OP_lt:
118+
case OP_leq:
119+
case OP_gt:
120+
case OP_geq:
121+
/* Unified constant folding for binary and comparison ops */
122+
if (insn->rs1 && insn->rs1->is_const && insn->rs2 &&
123+
insn->rs2->is_const && !insn->rd->is_global) {
124+
int result = 0;
125+
int l = insn->rs1->init_val, r = insn->rs2->init_val;
126+
127+
/* Compute result based on operation type */
128+
switch (insn->opcode) {
129+
case OP_add:
130+
result = l + r;
131+
break;
132+
case OP_sub:
133+
result = l - r;
134+
break;
135+
case OP_mul:
136+
result = l * r;
137+
break;
138+
case OP_eq:
139+
result = (l == r);
140+
break;
141+
case OP_neq:
142+
result = (l != r);
143+
break;
144+
case OP_lt:
145+
result = (l < r);
146+
break;
147+
case OP_leq:
148+
result = (l <= r);
149+
break;
150+
case OP_gt:
151+
result = (l > r);
152+
break;
153+
case OP_geq:
154+
result = (l >= r);
155+
break;
156+
default:
157+
continue;
158+
}
159+
160+
/* Convert to constant load */
161+
insn->opcode = OP_load_constant;
162+
insn->rd->is_const = true;
163+
insn->rd->init_val = result;
164+
insn->rs1 = NULL;
165+
insn->rs2 = NULL;
166+
changed = true;
167+
}
168+
break;
169+
170+
default:
171+
/* Other opcodes - no optimization */
172+
break;
173+
}
174+
}
175+
176+
/* Simple constant branch folding */
177+
insn_t *last = bb->insn_list.tail;
178+
if (last && last->opcode == OP_branch) {
179+
if (last->rs1 && last->rs1->is_const) {
180+
/* Convert to unconditional jump */
181+
last->opcode = OP_jump;
182+
183+
if (last->rs1->init_val != 0) {
184+
/* Take then branch */
185+
bb->else_ = NULL;
186+
} else {
187+
/* Take else branch */
188+
bb->then_ = bb->else_;
189+
bb->else_ = NULL;
190+
}
191+
192+
last->rs1 = NULL;
193+
changed = true;
194+
}
195+
}
196+
}
197+
198+
return changed;
199+
}
200+
201+
/* Targeted constant truncation peephole optimization */
202+
bool optimize_constant_casts(func_t *func)
203+
{
204+
if (!func || !func->bbs)
205+
return false;
206+
207+
bool changed = false;
208+
209+
/* Simple peephole optimization: const + trunc pattern */
210+
for (basic_block_t *bb = func->bbs; bb; bb = bb->rpo_next) {
211+
if (!bb)
212+
continue;
213+
214+
for (insn_t *insn = bb->insn_list.head; insn && insn->next;
215+
insn = insn->next) {
216+
insn_t *next_insn = insn->next;
217+
218+
/* Look for pattern: const %.tX, VALUE followed by
219+
* %.tY = trunc %.tX, SIZE
220+
*/
221+
if (insn->opcode == OP_load_constant &&
222+
next_insn->opcode == OP_trunc && insn->rd && next_insn->rs1 &&
223+
insn->rd == next_insn->rs1 && next_insn->sz > 0 &&
224+
!next_insn->rd->is_global) {
225+
int value = insn->rd->init_val;
226+
int result = value;
227+
228+
/* Perform truncation based on size */
229+
if (next_insn->sz == 1) {
230+
/* Truncate to 8 bits */
231+
result = value & 0xFF;
232+
} else if (next_insn->sz == 2) {
233+
/* Truncate to 16 bits */
234+
result = value & 0xFFFF;
235+
} else if (next_insn->sz == 4) {
236+
/* No truncation needed for 32-bit */
237+
result = value;
238+
} else {
239+
/* Invalid size, skip */
240+
continue;
241+
}
242+
243+
/* Optimize: Replace both instructions with single const */
244+
insn->rd = next_insn->rd; /* Update dest to final target */
245+
insn->rd->is_const = true;
246+
insn->rd->init_val = result;
247+
248+
/* Remove the truncation instruction by converting it to
249+
* NOP-like
250+
*/
251+
next_insn->opcode = OP_load_constant;
252+
next_insn->rd->is_const = true;
253+
next_insn->rd->init_val = result;
254+
next_insn->rs1 = NULL;
255+
next_insn->sz = 0;
256+
257+
changed = true;
258+
}
259+
}
260+
}
261+
262+
return changed;
263+
}

0 commit comments

Comments
 (0)