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+ * The implementation is designed to work within shecc's constraints,
17+ * avoiding dynamic memory allocation and complex data structures.
18+ */
19+
20+ /* Simple constant propagation within basic blocks */
21+ bool simple_sccp (func_t * func )
22+ {
23+ if (!func || !func -> bbs )
24+ return false;
25+
26+ bool changed = false;
27+
28+ /* Iterate through basic blocks */
29+ for (basic_block_t * bb = func -> bbs ; bb ; bb = bb -> rpo_next ) {
30+ /* Process instructions in the block */
31+ for (insn_t * insn = bb -> insn_list .head ; insn ; insn = insn -> next ) {
32+ /* Skip if no destination */
33+ if (!insn -> rd )
34+ continue ;
35+
36+ /* Handle simple constant propagation */
37+ switch (insn -> opcode ) {
38+ case OP_assign :
39+ /* Propagate constants through assignments */
40+ if (insn -> rs1 && insn -> rs1 -> is_const && !insn -> rd -> is_const ) {
41+ insn -> rd -> is_const = true;
42+ insn -> rd -> init_val = insn -> rs1 -> init_val ;
43+ insn -> opcode = OP_load_constant ;
44+ insn -> rs1 = NULL ;
45+ changed = true;
46+ }
47+ break ;
48+
49+ case OP_add :
50+ case OP_sub :
51+ case OP_mul :
52+ /* Fold binary operations with constants */
53+ if (insn -> rs1 && insn -> rs1 -> is_const && insn -> rs2 &&
54+ insn -> rs2 -> is_const &&
55+ !insn -> rd -> is_global ) { /* Don't modify globals */
56+ int result = 0 ;
57+ int l = insn -> rs1 -> init_val ;
58+ int r = insn -> rs2 -> init_val ;
59+
60+ switch (insn -> opcode ) {
61+ case OP_add :
62+ result = l + r ;
63+ break ;
64+ case OP_sub :
65+ result = l - r ;
66+ break ;
67+ case OP_mul :
68+ result = l * r ;
69+ break ;
70+ default :
71+ continue ;
72+ }
73+
74+ /* Convert to constant load */
75+ insn -> opcode = OP_load_constant ;
76+ insn -> rd -> is_const = true;
77+ insn -> rd -> init_val = result ;
78+ insn -> rs1 = NULL ;
79+ insn -> rs2 = NULL ;
80+ changed = true;
81+ }
82+ break ;
83+
84+ case OP_eq :
85+ case OP_neq :
86+ case OP_lt :
87+ case OP_leq :
88+ case OP_gt :
89+ case OP_geq :
90+ /* Fold comparison operations */
91+ if (insn -> rs1 && insn -> rs1 -> is_const && insn -> rs2 &&
92+ insn -> rs2 -> is_const &&
93+ !insn -> rd -> is_global ) { /* Don't modify globals */
94+ int result = 0 ;
95+ int l = insn -> rs1 -> init_val ;
96+ int r = insn -> rs2 -> init_val ;
97+
98+ switch (insn -> opcode ) {
99+ case OP_eq :
100+ result = (l == r );
101+ break ;
102+ case OP_neq :
103+ result = (l != r );
104+ break ;
105+ case OP_lt :
106+ result = (l < r );
107+ break ;
108+ case OP_leq :
109+ result = (l <= r );
110+ break ;
111+ case OP_gt :
112+ result = (l > r );
113+ break ;
114+ case OP_geq :
115+ result = (l >= r );
116+ break ;
117+ default :
118+ continue ;
119+ }
120+
121+ /* Convert to constant load */
122+ insn -> opcode = OP_load_constant ;
123+ insn -> rd -> is_const = true;
124+ insn -> rd -> init_val = result ;
125+ insn -> rs1 = NULL ;
126+ insn -> rs2 = NULL ;
127+ changed = true;
128+ }
129+ break ;
130+
131+ default :
132+ /* Other opcodes - no optimization */
133+ break ;
134+ }
135+ }
136+
137+ /* Simple constant branch folding */
138+ insn_t * last = bb -> insn_list .tail ;
139+ if (last && last -> opcode == OP_branch ) {
140+ if (last -> rs1 && last -> rs1 -> is_const ) {
141+ /* Convert to unconditional jump */
142+ last -> opcode = OP_jump ;
143+
144+ if (last -> rs1 -> init_val != 0 ) {
145+ /* Take then branch */
146+ bb -> else_ = NULL ;
147+ } else {
148+ /* Take else branch */
149+ bb -> then_ = bb -> else_ ;
150+ bb -> else_ = NULL ;
151+ }
152+
153+ last -> rs1 = NULL ;
154+ changed = true;
155+ }
156+ }
157+ }
158+
159+ return changed ;
160+ }
0 commit comments