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_add :
47+ case OP_sub :
48+ case OP_mul :
49+ /* Fold binary operations with constants */
50+ if (insn -> rs1 && insn -> rs1 -> is_const && insn -> rs2 &&
51+ insn -> rs2 -> is_const &&
52+ !insn -> rd -> is_global ) { /* Don't modify globals */
53+ int result = 0 ;
54+ int l = insn -> rs1 -> init_val , r = insn -> rs2 -> init_val ;
55+
56+ switch (insn -> opcode ) {
57+ case OP_add :
58+ result = l + r ;
59+ break ;
60+ case OP_sub :
61+ result = l - r ;
62+ break ;
63+ case OP_mul :
64+ result = l * r ;
65+ break ;
66+ default :
67+ continue ;
68+ }
69+
70+ /* Convert to constant load */
71+ insn -> opcode = OP_load_constant ;
72+ insn -> rd -> is_const = true;
73+ insn -> rd -> init_val = result ;
74+ insn -> rs1 = NULL ;
75+ insn -> rs2 = NULL ;
76+ changed = true;
77+ }
78+ break ;
79+
80+ case OP_eq :
81+ case OP_neq :
82+ case OP_lt :
83+ case OP_leq :
84+ case OP_gt :
85+ case OP_geq :
86+ /* Fold comparison operations */
87+ if (insn -> rs1 && insn -> rs1 -> is_const && insn -> rs2 &&
88+ insn -> rs2 -> is_const &&
89+ !insn -> rd -> is_global ) { /* Don't modify globals */
90+ int result = 0 ;
91+ int l = insn -> rs1 -> init_val ;
92+ int r = insn -> rs2 -> init_val ;
93+
94+ switch (insn -> opcode ) {
95+ case OP_eq :
96+ result = (l == r );
97+ break ;
98+ case OP_neq :
99+ result = (l != r );
100+ break ;
101+ case OP_lt :
102+ result = (l < r );
103+ break ;
104+ case OP_leq :
105+ result = (l <= r );
106+ break ;
107+ case OP_gt :
108+ result = (l > r );
109+ break ;
110+ case OP_geq :
111+ result = (l >= r );
112+ break ;
113+ default :
114+ continue ;
115+ }
116+
117+ /* Convert to constant load */
118+ insn -> opcode = OP_load_constant ;
119+ insn -> rd -> is_const = true;
120+ insn -> rd -> init_val = result ;
121+ insn -> rs1 = NULL ;
122+ insn -> rs2 = NULL ;
123+ changed = true;
124+ }
125+ break ;
126+
127+ default :
128+ /* Other opcodes - no optimization */
129+ break ;
130+ }
131+ }
132+
133+ /* Simple constant branch folding */
134+ insn_t * last = bb -> insn_list .tail ;
135+ if (last && last -> opcode == OP_branch ) {
136+ if (last -> rs1 && last -> rs1 -> is_const ) {
137+ /* Convert to unconditional jump */
138+ last -> opcode = OP_jump ;
139+
140+ if (last -> rs1 -> init_val != 0 ) {
141+ /* Take then branch */
142+ bb -> else_ = NULL ;
143+ } else {
144+ /* Take else branch */
145+ bb -> then_ = bb -> else_ ;
146+ bb -> else_ = NULL ;
147+ }
148+
149+ last -> rs1 = NULL ;
150+ changed = true;
151+ }
152+ }
153+ }
154+
155+ return changed ;
156+ }
0 commit comments