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