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