2 * cfold.c: Constant folding support
5 * Paolo Molaro (lupus@ximian.com)
6 * Dietmar Maurer (dietmar@ximian.com)
8 * (C) 2003 Ximian, Inc. http://www.ximian.com
13 is_power_of_two (guint32 val)
17 for (i = 0, j = 1, k = 0xfffffffe; i < 32; ++i, j = j << 1, k = k << 1) {
21 if (i == 32 || val & k)
26 #define FOLD_BINOP(name,op) \
28 if (inst->inst_i0->opcode != OP_ICONST) \
30 if (inst->inst_i1->opcode == OP_ICONST) { \
31 inst->opcode = OP_ICONST; \
32 inst->inst_c0 = inst->inst_i0->inst_c0 op inst->inst_i1->inst_c0; \
37 * We try to put constants on the left side of a commutative operation
38 * because it reduces register pressure and it matches the usual cpu
39 * instructions with immediates.
41 #define FOLD_BINOPCOMM(name,op) \
43 if (inst->inst_i0->opcode == OP_ICONST) {\
44 if (inst->inst_i1->opcode == OP_ICONST) { \
45 inst->opcode = OP_ICONST; \
46 inst->inst_c0 = inst->inst_i0->inst_c0 op inst->inst_i1->inst_c0; \
49 MonoInst *tmp = inst->inst_i0; \
50 inst->inst_i0 = inst->inst_i1; \
51 inst->inst_i1 = tmp; \
54 if (inst->inst_i1->opcode == OP_ICONST && inst->opcode == CEE_MUL) { \
56 if (inst->inst_i1->inst_c0 == 1) { \
57 *inst = *(inst->inst_i0); \
59 } else if (inst->inst_i1->inst_c0 == -1) { \
60 inst->opcode = CEE_NEG; \
63 power2 = is_power_of_two (inst->inst_i1->inst_c0); \
64 if (power2 < 0) return; \
65 inst->opcode = CEE_SHL; \
66 inst->inst_i1->inst_c0 = power2; \
70 #define FOLD_BINOPZ(name,op,cast) \
72 if (inst->inst_i1->opcode == OP_ICONST && inst->opcode == CEE_REM_UN && inst->inst_i1->inst_c0 == 2) { \
73 inst->opcode = CEE_AND; \
74 inst->inst_i1->inst_c0 = 1; \
77 if (inst->inst_i1->opcode == OP_ICONST) { \
78 /* let the runtime throw the exception. */ \
79 if (!inst->inst_i1->inst_c0) return; \
80 if (inst->inst_i0->opcode == OP_ICONST) { \
81 inst->inst_c0 = (cast)inst->inst_i0->inst_c0 op (cast)inst->inst_i1->inst_c0; \
82 inst->opcode = OP_ICONST; \
84 int power2 = is_power_of_two (inst->inst_i1->inst_c0); \
85 if (power2 < 0) return; \
86 if (inst->opcode == CEE_REM_UN) { \
87 inst->opcode = CEE_AND; \
88 inst->inst_i1->inst_c0 = (1 << power2) - 1; \
89 } else if (inst->opcode == CEE_DIV_UN) { \
90 inst->opcode = CEE_SHR_UN; \
91 inst->inst_i1->inst_c0 = power2; \
97 #define FOLD_BINOPA(name,op,cast) \
99 if (inst->inst_i0->opcode != OP_ICONST) \
101 if (inst->inst_i1->opcode == OP_ICONST) { \
102 inst->opcode = OP_ICONST; \
103 inst->inst_c0 = (cast)inst->inst_i0->inst_c0 op (cast)inst->inst_i1->inst_c0; \
107 #define FOLD_CXX(name,op,cast) \
109 if (inst->inst_i0->opcode != OP_COMPARE) \
111 if (inst->inst_i0->inst_i0->opcode != OP_ICONST) \
113 if (inst->inst_i0->inst_i1->opcode == OP_ICONST) { \
114 inst->opcode = OP_ICONST; \
115 inst->inst_c0 = (cast)inst->inst_i0->inst_i0->inst_c0 op (cast)inst->inst_i0->inst_i1->inst_c0; \
119 #define FOLD_UNOP(name,op) \
121 if (inst->inst_i0->opcode == OP_ICONST) { \
122 inst->opcode = OP_ICONST; \
123 inst->inst_c0 = op inst->inst_i0->inst_c0; \
124 } else if (inst->inst_i0->opcode == OP_I8CONST) { \
125 inst->opcode = OP_I8CONST; \
126 inst->inst_l = op inst->inst_i0->inst_l; \
129 #define FOLD_BRBINOP(name,op,cast) \
131 if (inst->inst_i0->opcode != OP_COMPARE) \
133 if (inst->inst_i0->inst_i0->opcode != OP_ICONST) \
135 if (inst->inst_i0->inst_i1->opcode == OP_ICONST) { \
136 if ((cast)inst->inst_i0->inst_i0->inst_c0 op (cast)inst->inst_i0->inst_i1->inst_c0) \
137 inst->opcode = CEE_BR; \
139 inst->opcode = CEE_NOP; \
144 * Helper function to do constant expression evaluation.
145 * We do constant folding of integers only, FP stuff is much more tricky,
146 * int64 probably not worth it.
149 mono_constant_fold_inst (MonoInst *inst, gpointer data)
151 switch (inst->opcode) {
153 /* FIXME: the CEE_B* don't contain operands, need to use the OP_COMPARE instruction */
154 /*FOLD_BRBINOP (CEE_BEQ,==,gint32)
155 FOLD_BRBINOP (CEE_BGE,>=,gint32)
156 FOLD_BRBINOP (CEE_BGT,>,gint32)
157 FOLD_BRBINOP (CEE_BLE,<=,gint32)
158 FOLD_BRBINOP (CEE_BLT,<,gint32)
159 FOLD_BRBINOP (CEE_BNE_UN,!=,guint32)
160 FOLD_BRBINOP (CEE_BGE_UN,>=,guint32)
161 FOLD_BRBINOP (CEE_BGT_UN,>,guint32)
162 FOLD_BRBINOP (CEE_BLE_UN,<=,guint32)
163 FOLD_BRBINOP (CEE_BLT_UN,<,guint32)*/
165 FOLD_BINOPCOMM (CEE_MUL,*)
167 FOLD_BINOPCOMM (CEE_ADD,+)
168 FOLD_BINOP (CEE_SUB,-)
169 FOLD_BINOPZ (CEE_DIV,/,gint32)
170 FOLD_BINOPZ (CEE_DIV_UN,/,guint32)
171 FOLD_BINOPZ (CEE_REM,%,gint32)
172 FOLD_BINOPZ (CEE_REM_UN,%,guint32)
173 FOLD_BINOPCOMM (CEE_AND,&)
174 FOLD_BINOPCOMM (CEE_OR,|)
175 FOLD_BINOPCOMM (CEE_XOR,^)
176 FOLD_BINOP (CEE_SHL,<<)
177 FOLD_BINOP (CEE_SHR,>>)
179 if (inst->inst_i0->opcode != OP_ICONST)
181 if (inst->inst_i1->opcode == OP_ICONST) {
182 inst->opcode = OP_ICONST;
183 inst->inst_c0 = (guint32)inst->inst_i0->inst_c0 >> (guint32)inst->inst_i1->inst_c0;
186 FOLD_UNOP (CEE_NEG,-)
187 FOLD_UNOP (CEE_NOT,~)
188 FOLD_CXX (OP_CEQ,==,gint32)
189 FOLD_CXX (OP_CGT,>,gint32)
190 FOLD_CXX (OP_CGT_UN,>,guint32)
191 FOLD_CXX (OP_CLT,<,gint32)
192 FOLD_CXX (OP_CLT_UN,<,guint32)
194 if (inst->inst_i0->opcode == OP_ICONST) {
195 inst->opcode = OP_I8CONST;
196 inst->inst_l = inst->inst_i0->inst_c0;
199 /* we should be able to handle isinst and castclass as well */
205 * *ovf* opcodes? I'ts slow and hard to do in C.
206 * switch can be replaced by a simple jump
214 mono_constant_fold (MonoCompile *cfg)
218 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
220 for (ins = bb->code; ins; ins = ins->next)
221 mono_inst_foreach (ins, mono_constant_fold_inst, NULL);