Make sure x86 ATOMIC_CAS doesn't overwrite its own operands.
[mono-debugger.git] / mono / mini / decompose.c
blob2d2ae39c28973363c8a857da8039bb7d0d7e3f0d
1 /*
2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
4 * Author:
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
8 */
10 #include "mini.h"
11 #include "ir-emit.h"
13 #ifndef DISABLE_JIT
15 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
16 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
17 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
18 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
21 * mono_decompose_opcode:
23 * Decompose complex opcodes into ones closer to opcodes supported by
24 * the given architecture.
26 void
27 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
29 /* FIXME: Instead of = NOP, don't emit the original ins at all */
31 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
32 mono_arch_decompose_opts (cfg, ins);
33 #endif
36 * The code below assumes that we are called immediately after emitting
37 * ins. This means we can emit code using the normal code generation
38 * macros.
40 switch (ins->opcode) {
41 /* this doesn't make sense on ppc and other architectures */
42 #if !defined(MONO_ARCH_NO_IOV_CHECK)
43 case OP_IADD_OVF:
44 ins->opcode = OP_IADDCC;
45 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
46 break;
47 case OP_IADD_OVF_UN:
48 ins->opcode = OP_IADDCC;
49 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
50 break;
51 case OP_ISUB_OVF:
52 ins->opcode = OP_ISUBCC;
53 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
54 break;
55 case OP_ISUB_OVF_UN:
56 ins->opcode = OP_ISUBCC;
57 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
58 break;
59 #endif
60 case OP_ICONV_TO_OVF_I1:
61 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
62 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
63 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
64 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
65 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
66 ins->opcode = OP_NOP;
67 break;
68 case OP_ICONV_TO_OVF_I1_UN:
69 /* probe values between 0 to 127 */
70 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
71 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
72 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
73 ins->opcode = OP_NOP;
74 break;
75 case OP_ICONV_TO_OVF_U1:
76 case OP_ICONV_TO_OVF_U1_UN:
77 /* probe value to be within 0 to 255 */
78 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
79 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
80 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
81 ins->opcode = OP_NOP;
82 break;
83 case OP_ICONV_TO_OVF_I2:
84 /* Probe value to be within -32768 and 32767 */
85 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
86 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
87 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
88 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
89 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
90 ins->opcode = OP_NOP;
91 break;
92 case OP_ICONV_TO_OVF_I2_UN:
93 /* Convert uint value into short, value within 0 and 32767 */
94 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
95 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
96 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
97 ins->opcode = OP_NOP;
98 break;
99 case OP_ICONV_TO_OVF_U2:
100 case OP_ICONV_TO_OVF_U2_UN:
101 /* Probe value to be within 0 and 65535 */
102 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
103 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
104 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
105 ins->opcode = OP_NOP;
106 break;
107 case OP_ICONV_TO_OVF_U4:
108 case OP_ICONV_TO_OVF_I4_UN:
109 #if SIZEOF_REGISTER == 4
110 case OP_ICONV_TO_OVF_U:
111 case OP_ICONV_TO_OVF_I_UN:
112 #endif
113 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
114 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
115 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
116 ins->opcode = OP_NOP;
117 break;
118 case OP_ICONV_TO_I4:
119 case OP_ICONV_TO_U4:
120 case OP_ICONV_TO_OVF_I4:
121 #if SIZEOF_REGISTER == 4
122 case OP_ICONV_TO_OVF_I:
123 case OP_ICONV_TO_OVF_U_UN:
124 #endif
125 ins->opcode = OP_MOVE;
126 break;
127 case OP_ICONV_TO_I:
128 #if SIZEOF_REGISTER == 8
129 ins->opcode = OP_SEXT_I4;
130 #else
131 ins->opcode = OP_MOVE;
132 #endif
133 break;
134 case OP_ICONV_TO_U:
135 #if SIZEOF_REGISTER == 8
136 ins->opcode = OP_ZEXT_I4;
137 #else
138 ins->opcode = OP_MOVE;
139 #endif
140 break;
142 case OP_FCONV_TO_R8:
143 ins->opcode = OP_FMOVE;
144 break;
146 /* Long opcodes on 64 bit machines */
147 #if SIZEOF_REGISTER == 8
148 case OP_LCONV_TO_I4:
149 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
150 ins->opcode = OP_NOP;
151 break;
152 case OP_LCONV_TO_I8:
153 case OP_LCONV_TO_I:
154 case OP_LCONV_TO_U8:
155 case OP_LCONV_TO_U:
156 ins->opcode = OP_MOVE;
157 break;
158 case OP_ICONV_TO_I8:
159 ins->opcode = OP_SEXT_I4;
160 break;
161 case OP_ICONV_TO_U8:
162 ins->opcode = OP_ZEXT_I4;
163 break;
164 case OP_LCONV_TO_U4:
165 /* Clean out the upper word */
166 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
167 ins->opcode = OP_NOP;
168 break;
169 #if defined(__mono_ppc__) && !defined(__mono_ppc64__)
170 case OP_LADD_OVF:
171 /* ADC sets the condition code */
172 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
173 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
174 ins->opcode = OP_NOP;
175 g_assert_not_reached ();
176 break;
177 case OP_LADD_OVF_UN:
178 /* ADC sets the condition code */
179 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
180 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
181 ins->opcode = OP_NOP;
182 g_assert_not_reached ();
183 break;
184 case OP_LSUB_OVF:
185 /* SBB sets the condition code */
186 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
187 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
188 ins->opcode = OP_NOP;
189 g_assert_not_reached ();
190 break;
191 case OP_LSUB_OVF_UN:
192 /* SBB sets the condition code */
193 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
194 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
195 ins->opcode = OP_NOP;
196 g_assert_not_reached ();
197 break;
198 #else
199 case OP_LADD_OVF:
200 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
201 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
202 ins->opcode = OP_NOP;
203 break;
204 case OP_LADD_OVF_UN:
205 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
206 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
207 ins->opcode = OP_NOP;
208 break;
209 #ifndef __mono_ppc64__
210 case OP_LSUB_OVF:
211 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
212 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
213 ins->opcode = OP_NOP;
214 break;
215 case OP_LSUB_OVF_UN:
216 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
217 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
218 ins->opcode = OP_NOP;
219 break;
220 #endif
221 #endif
223 case OP_ICONV_TO_OVF_I8:
224 case OP_ICONV_TO_OVF_I:
225 ins->opcode = OP_SEXT_I4;
226 break;
227 case OP_ICONV_TO_OVF_U8:
228 case OP_ICONV_TO_OVF_U:
229 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
230 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
231 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
232 ins->opcode = OP_NOP;
233 break;
234 case OP_ICONV_TO_OVF_I8_UN:
235 case OP_ICONV_TO_OVF_U8_UN:
236 case OP_ICONV_TO_OVF_I_UN:
237 case OP_ICONV_TO_OVF_U_UN:
238 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
239 /* Clean out the upper word */
240 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
241 ins->opcode = OP_NOP;
242 break;
243 case OP_LCONV_TO_OVF_I1:
244 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
245 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
246 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
247 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
248 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
249 ins->opcode = OP_NOP;
250 break;
251 case OP_LCONV_TO_OVF_I1_UN:
252 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
253 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
254 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
255 ins->opcode = OP_NOP;
256 break;
257 case OP_LCONV_TO_OVF_U1:
258 /* probe value to be within 0 to 255 */
259 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
260 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
261 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
262 ins->opcode = OP_NOP;
263 break;
264 case OP_LCONV_TO_OVF_U1_UN:
265 /* probe value to be within 0 to 255 */
266 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
267 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
268 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
269 ins->opcode = OP_NOP;
270 break;
271 case OP_LCONV_TO_OVF_I2:
272 /* Probe value to be within -32768 and 32767 */
273 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
274 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
275 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
276 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
277 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
278 ins->opcode = OP_NOP;
279 break;
280 case OP_LCONV_TO_OVF_I2_UN:
281 /* Probe value to be within 0 and 32767 */
282 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
283 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
284 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
285 ins->opcode = OP_NOP;
286 break;
287 case OP_LCONV_TO_OVF_U2:
288 /* Probe value to be within 0 and 65535 */
289 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
290 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
291 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
292 ins->opcode = OP_NOP;
293 break;
294 case OP_LCONV_TO_OVF_U2_UN:
295 /* Probe value to be within 0 and 65535 */
296 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
297 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
298 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
299 ins->opcode = OP_NOP;
300 break;
301 case OP_LCONV_TO_OVF_I4:
302 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
303 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
304 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
305 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
306 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
307 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
308 ins->opcode = OP_NOP;
309 break;
310 case OP_LCONV_TO_OVF_I4_UN:
311 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
312 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
313 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
314 ins->opcode = OP_NOP;
315 break;
316 case OP_LCONV_TO_OVF_U4:
317 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
318 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
319 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
320 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
321 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
322 ins->opcode = OP_NOP;
323 break;
324 case OP_LCONV_TO_OVF_U4_UN:
325 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
326 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
327 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
328 ins->opcode = OP_NOP;
329 break;
330 case OP_LCONV_TO_OVF_I:
331 case OP_LCONV_TO_OVF_U_UN:
332 case OP_LCONV_TO_OVF_U8_UN:
333 ins->opcode = OP_MOVE;
334 break;
335 case OP_LCONV_TO_OVF_I_UN:
336 case OP_LCONV_TO_OVF_I8_UN:
337 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
338 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
339 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
340 ins->opcode = OP_NOP;
341 break;
342 case OP_LCONV_TO_OVF_U8:
343 case OP_LCONV_TO_OVF_U:
344 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
345 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
346 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
347 ins->opcode = OP_NOP;
348 break;
349 #endif
351 default: {
352 MonoJitICallInfo *info;
354 info = mono_find_jit_opcode_emulation (ins->opcode);
355 if (info) {
356 MonoInst **args;
357 MonoInst *call;
359 /* Create dummy MonoInst's for the arguments */
360 g_assert (!info->sig->hasthis);
361 g_assert (info->sig->param_count <= 2);
363 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
364 if (info->sig->param_count > 0) {
365 MONO_INST_NEW (cfg, args [0], OP_ARG);
366 args [0]->dreg = ins->sreg1;
368 if (info->sig->param_count > 1) {
369 MONO_INST_NEW (cfg, args [1], OP_ARG);
370 args [1]->dreg = ins->sreg2;
373 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
374 call->dreg = ins->dreg;
376 ins->opcode = OP_NOP;
378 break;
383 #if SIZEOF_REGISTER == 4
384 static int lbr_decomp [][2] = {
385 {0, 0}, /* BEQ */
386 {OP_IBGT, OP_IBGE_UN}, /* BGE */
387 {OP_IBGT, OP_IBGT_UN}, /* BGT */
388 {OP_IBLT, OP_IBLE_UN}, /* BLE */
389 {OP_IBLT, OP_IBLT_UN}, /* BLT */
390 {0, 0}, /* BNE_UN */
391 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
392 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
393 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
394 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
397 static int lcset_decomp [][2] = {
398 {0, 0}, /* CEQ */
399 {OP_IBLT, OP_IBLE_UN}, /* CGT */
400 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
401 {OP_IBGT, OP_IBGE_UN}, /* CLT */
402 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
404 #endif
407 * mono_decompose_long_opts:
409 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
411 void
412 mono_decompose_long_opts (MonoCompile *cfg)
414 #if SIZEOF_REGISTER == 4
415 MonoBasicBlock *bb, *first_bb;
418 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
419 * needs to be able to handle long vregs.
422 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
425 * Create a dummy bblock and emit code into it so we can use the normal
426 * code generation macros.
428 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
429 first_bb = cfg->cbb;
431 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
432 MonoInst *tree = bb->code;
433 MonoInst *prev = NULL;
436 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
439 tree = bb->code;
440 cfg->cbb->code = cfg->cbb->last_ins = NULL;
442 while (tree) {
444 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
445 mono_arch_decompose_long_opts (cfg, tree);
446 #endif
448 switch (tree->opcode) {
449 case OP_I8CONST:
450 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
451 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
452 break;
453 case OP_LMOVE:
454 case OP_LCONV_TO_U8:
455 case OP_LCONV_TO_I8:
456 case OP_LCONV_TO_OVF_U8_UN:
457 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
458 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
459 break;
460 case OP_STOREI8_MEMBASE_REG:
461 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
462 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
463 break;
464 case OP_LOADI8_MEMBASE:
465 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
466 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
467 break;
469 case OP_ICONV_TO_I8: {
470 guint32 tmpreg = alloc_ireg (cfg);
472 /* branchless code:
473 * low = reg;
474 * tmp = low > -1 ? 1: 0;
475 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
477 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
478 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
479 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
480 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
481 break;
483 case OP_ICONV_TO_U8:
484 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
485 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
486 break;
487 case OP_ICONV_TO_OVF_I8:
488 /* a signed 32 bit num always fits in a signed 64 bit one */
489 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
490 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
491 break;
492 case OP_ICONV_TO_OVF_U8:
493 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
494 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
495 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
496 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
497 break;
498 case OP_ICONV_TO_OVF_I8_UN:
499 case OP_ICONV_TO_OVF_U8_UN:
500 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
501 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
502 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
503 break;
504 case OP_LCONV_TO_I1:
505 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
506 break;
507 case OP_LCONV_TO_U1:
508 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
509 break;
510 case OP_LCONV_TO_I2:
511 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
512 break;
513 case OP_LCONV_TO_U2:
514 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
515 break;
516 case OP_LCONV_TO_I4:
517 case OP_LCONV_TO_U4:
518 case OP_LCONV_TO_I:
519 case OP_LCONV_TO_U:
520 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
521 break;
522 case OP_LCONV_TO_R8:
523 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
524 break;
525 case OP_LCONV_TO_R4:
526 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
527 break;
528 case OP_LCONV_TO_R_UN:
529 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
530 break;
531 case OP_LCONV_TO_OVF_I1: {
532 MonoBasicBlock *is_negative, *end_label;
534 NEW_BBLOCK (cfg, is_negative);
535 NEW_BBLOCK (cfg, end_label);
537 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
538 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
539 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
540 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
542 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
543 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
545 /* Positive */
546 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
547 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
548 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
550 /* Negative */
551 MONO_START_BB (cfg, is_negative);
552 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
553 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
555 MONO_START_BB (cfg, end_label);
557 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
558 break;
560 case OP_LCONV_TO_OVF_I1_UN:
561 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
562 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
564 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
565 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
566 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
567 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
568 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
569 break;
570 case OP_LCONV_TO_OVF_U1:
571 case OP_LCONV_TO_OVF_U1_UN:
572 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
573 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
575 /* probe value to be within 0 to 255 */
576 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
577 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
578 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
579 break;
580 case OP_LCONV_TO_OVF_I2: {
581 MonoBasicBlock *is_negative, *end_label;
583 NEW_BBLOCK (cfg, is_negative);
584 NEW_BBLOCK (cfg, end_label);
586 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
587 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
588 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
589 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
591 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
592 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
594 /* Positive */
595 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
596 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
597 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
599 /* Negative */
600 MONO_START_BB (cfg, is_negative);
601 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
602 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
603 MONO_START_BB (cfg, end_label);
605 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
606 break;
608 case OP_LCONV_TO_OVF_I2_UN:
609 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
610 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
612 /* Probe value to be within -32768 and 32767 */
613 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
614 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
615 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
616 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
617 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
618 break;
619 case OP_LCONV_TO_OVF_U2:
620 case OP_LCONV_TO_OVF_U2_UN:
621 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
622 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
624 /* Probe value to be within 0 and 65535 */
625 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
626 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
627 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
628 break;
629 case OP_LCONV_TO_OVF_I4:
630 case OP_LCONV_TO_OVF_I:
631 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
632 break;
633 case OP_LCONV_TO_OVF_U4:
634 case OP_LCONV_TO_OVF_U:
635 case OP_LCONV_TO_OVF_U4_UN:
636 case OP_LCONV_TO_OVF_U_UN:
637 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
638 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
639 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
640 break;
641 case OP_LCONV_TO_OVF_I_UN:
642 case OP_LCONV_TO_OVF_I4_UN:
643 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
644 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
645 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
646 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
647 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
648 break;
649 case OP_LCONV_TO_OVF_U8:
650 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
651 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
653 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
654 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
655 break;
656 case OP_LCONV_TO_OVF_I8_UN:
657 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
658 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
660 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
661 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
662 break;
664 case OP_LADD:
665 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
666 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
667 break;
668 case OP_LSUB:
669 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
670 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
671 break;
673 #if defined(__ppc__) || defined(__powerpc__)
674 case OP_LADD_OVF:
675 /* ADC sets the condition code */
676 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
677 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
678 break;
679 case OP_LADD_OVF_UN:
680 /* ADC sets the condition code */
681 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
682 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
683 break;
684 case OP_LSUB_OVF:
685 /* SBB sets the condition code */
686 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
687 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
688 break;
689 case OP_LSUB_OVF_UN:
690 /* SBB sets the condition code */
691 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
692 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
693 break;
694 #else
695 case OP_LADD_OVF:
696 /* ADC sets the condition code */
697 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
698 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
699 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
700 break;
701 case OP_LADD_OVF_UN:
702 /* ADC sets the condition code */
703 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
704 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
705 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
706 break;
707 case OP_LSUB_OVF:
708 /* SBB sets the condition code */
709 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
710 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
711 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
712 break;
713 case OP_LSUB_OVF_UN:
714 /* SBB sets the condition code */
715 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
716 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
717 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
718 break;
719 #endif
720 case OP_LAND:
721 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
722 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
723 break;
724 case OP_LOR:
725 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
726 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
727 break;
728 case OP_LXOR:
729 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
730 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
731 break;
732 case OP_LNOT:
733 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
734 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
735 break;
736 case OP_LNEG:
738 * FIXME: The original version in inssel-long32.brg does not work
739 * on x86, and the x86 version might not work on other archs ?
741 /* FIXME: Move these to mono_arch_decompose_long_opts () */
742 #if defined(__i386__)
743 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
744 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
745 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
746 #elif defined(__sparc__)
747 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
748 MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
749 #elif defined(__arm__)
750 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
751 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
752 #elif defined(__ppc__) || defined(__powerpc__)
753 /* This is the old version from inssel-long32.brg */
754 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
755 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
756 /* ADC sets the condition codes */
757 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 1, tree->dreg + 1, 1);
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->dreg + 2, 0);
759 #else
760 NOT_IMPLEMENTED;
761 #endif
762 break;
763 case OP_LMUL:
764 /* Emulated */
765 /* FIXME: Add OP_BIGMUL optimization */
766 break;
768 case OP_LADD_IMM:
769 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
770 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
771 break;
772 case OP_LSUB_IMM:
773 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
774 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
775 break;
776 case OP_LAND_IMM:
777 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
778 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
779 break;
780 case OP_LOR_IMM:
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
783 break;
784 case OP_LXOR_IMM:
785 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
786 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
787 break;
788 case OP_LSHR_UN_IMM:
789 if (tree->inst_c1 == 32) {
791 /* The original code had this comment: */
792 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
793 * later apply the speedup to the left shift as well
794 * See BUG# 57957.
796 /* FIXME: Move this to the strength reduction pass */
797 /* just move the upper half to the lower and zero the high word */
798 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
799 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
801 break;
802 case OP_LSHL_IMM:
803 if (tree->inst_c1 == 32) {
804 /* just move the lower half to the upper and zero the lower word */
805 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
806 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
808 break;
810 case OP_LCOMPARE: {
811 MonoInst *next = tree->next;
813 g_assert (next);
815 switch (next->opcode) {
816 case OP_LBEQ:
817 case OP_LBNE_UN: {
818 int d1, d2;
820 /* Branchless version based on gcc code */
821 d1 = alloc_ireg (cfg);
822 d2 = alloc_ireg (cfg);
823 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
824 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
825 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
826 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
827 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
828 next->opcode = OP_NOP;
829 break;
831 case OP_LBGE:
832 case OP_LBGT:
833 case OP_LBLE:
834 case OP_LBLT:
835 case OP_LBGE_UN:
836 case OP_LBGT_UN:
837 case OP_LBLE_UN:
838 case OP_LBLT_UN:
839 /* Convert into three comparisons + branches */
840 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
841 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
842 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
843 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
844 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
845 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
846 next->opcode = OP_NOP;
847 break;
848 case OP_LCEQ: {
849 int d1, d2;
851 /* Branchless version based on gcc code */
852 d1 = alloc_ireg (cfg);
853 d2 = alloc_ireg (cfg);
854 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
855 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
856 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
858 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
859 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
860 next->opcode = OP_NOP;
861 break;
863 case OP_LCLT:
864 case OP_LCLT_UN:
865 case OP_LCGT:
866 case OP_LCGT_UN: {
867 MonoBasicBlock *set_to_0, *set_to_1;
869 NEW_BBLOCK (cfg, set_to_0);
870 NEW_BBLOCK (cfg, set_to_1);
872 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
873 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
874 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
875 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
876 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
877 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
878 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
879 MONO_START_BB (cfg, set_to_1);
880 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
881 MONO_START_BB (cfg, set_to_0);
882 next->opcode = OP_NOP;
883 break;
885 default:
886 g_assert_not_reached ();
888 break;
891 /* Not yet used, since lcompare is decomposed before local cprop */
892 case OP_LCOMPARE_IMM: {
893 MonoInst *next = tree->next;
894 guint32 low_imm = tree->inst_ls_word;
895 guint32 high_imm = tree->inst_ms_word;
896 int low_reg = tree->sreg1 + 1;
897 int high_reg = tree->sreg1 + 2;
899 g_assert (next);
901 switch (next->opcode) {
902 case OP_LBEQ:
903 case OP_LBNE_UN: {
904 int d1, d2;
906 /* Branchless version based on gcc code */
907 d1 = alloc_ireg (cfg);
908 d2 = alloc_ireg (cfg);
909 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
910 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
911 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
912 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
913 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
914 next->opcode = OP_NOP;
915 break;
918 case OP_LBGE:
919 case OP_LBGT:
920 case OP_LBLE:
921 case OP_LBLT:
922 case OP_LBGE_UN:
923 case OP_LBGT_UN:
924 case OP_LBLE_UN:
925 case OP_LBLT_UN:
926 /* Convert into three comparisons + branches */
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
928 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
930 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
932 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
933 next->opcode = OP_NOP;
934 break;
935 case OP_LCEQ: {
936 int d1, d2;
938 /* Branchless version based on gcc code */
939 d1 = alloc_ireg (cfg);
940 d2 = alloc_ireg (cfg);
941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
942 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
943 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
945 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
946 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
947 next->opcode = OP_NOP;
948 break;
950 case OP_LCLT:
951 case OP_LCLT_UN:
952 case OP_LCGT:
953 case OP_LCGT_UN: {
954 MonoBasicBlock *set_to_0, *set_to_1;
956 NEW_BBLOCK (cfg, set_to_0);
957 NEW_BBLOCK (cfg, set_to_1);
959 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
960 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
961 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
962 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
963 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
964 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
965 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
966 MONO_START_BB (cfg, set_to_1);
967 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
968 MONO_START_BB (cfg, set_to_0);
969 next->opcode = OP_NOP;
970 break;
972 default:
973 g_assert_not_reached ();
975 break;
978 default:
979 break;
982 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
983 MonoInst *new_prev;
985 /* Replace the original instruction with the new code sequence */
987 /* Ignore the new value of prev */
988 new_prev = prev;
989 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
991 /* Process the newly added ops again since they can be long ops too */
992 if (prev)
993 tree = prev->next;
994 else
995 tree = bb->code;
997 first_bb->code = first_bb->last_ins = NULL;
998 first_bb->in_count = first_bb->out_count = 0;
999 cfg->cbb = first_bb;
1001 else {
1002 prev = tree;
1003 tree = tree->next;
1007 #endif
1010 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1011 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1016 * mono_decompose_vtype_opts:
1018 * Decompose valuetype opcodes.
1020 void
1021 mono_decompose_vtype_opts (MonoCompile *cfg)
1023 MonoBasicBlock *bb, *first_bb;
1026 * Using OP_V opcodes and decomposing them later have two main benefits:
1027 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1028 * everywhere.
1029 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1030 * enabling optimizations to work on vtypes too.
1031 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1032 * can be executed anytime. It should be executed as late as possible so vtype
1033 * opcodes can be optimized by the other passes.
1034 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1035 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1036 * var to 1.
1037 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1038 * when OP_VMOVE opcodes are decomposed.
1042 * Vregs have no associated type information, so we store the type of the vregs
1043 * in ins->klass.
1047 * Create a dummy bblock and emit code into it so we can use the normal
1048 * code generation macros.
1050 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1051 first_bb = cfg->cbb;
1053 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1054 MonoInst *ins;
1055 MonoInst *prev = NULL;
1056 MonoInst *src_var, *dest_var, *src, *dest;
1057 gboolean restart;
1058 int dreg;
1060 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1062 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1063 restart = TRUE;
1065 while (restart) {
1066 restart = FALSE;
1068 for (ins = bb->code; ins; ins = ins->next) {
1069 switch (ins->opcode) {
1070 case OP_VMOVE: {
1071 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1072 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1074 g_assert (ins->klass);
1076 if (!src_var)
1077 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1079 if (!dest_var)
1080 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1082 // FIXME:
1083 if (src_var->backend.is_pinvoke)
1084 dest_var->backend.is_pinvoke = 1;
1086 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1087 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1089 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1090 break;
1092 case OP_VZERO:
1093 g_assert (ins->klass);
1095 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1096 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1097 break;
1098 case OP_STOREV_MEMBASE: {
1099 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1101 if (!src_var) {
1102 g_assert (ins->klass);
1103 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1106 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1108 dreg = alloc_preg (cfg);
1109 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1110 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1111 break;
1113 case OP_LOADV_MEMBASE: {
1114 g_assert (ins->klass);
1116 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1117 // FIXME:
1118 if (!dest_var)
1119 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1121 dreg = alloc_preg (cfg);
1122 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1123 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1124 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1125 break;
1127 case OP_OUTARG_VT: {
1128 g_assert (ins->klass);
1130 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1131 if (!src_var)
1132 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1133 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1135 mono_arch_emit_outarg_vt (cfg, ins, src);
1137 /* This might be decomposed into other vtype opcodes */
1138 restart = TRUE;
1139 break;
1141 case OP_OUTARG_VTRETADDR: {
1142 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1144 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1145 if (!src_var)
1146 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1147 // FIXME: src_var->backend.is_pinvoke ?
1149 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1150 src->dreg = ins->dreg;
1151 break;
1153 case OP_VCALL:
1154 case OP_VCALL_REG:
1155 case OP_VCALL_MEMBASE: {
1156 MonoCallInst *call = (MonoCallInst*)ins;
1157 int size;
1159 if (call->vret_in_reg) {
1160 MonoCallInst *call2;
1162 /* Replace the vcall with an integer call */
1163 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1164 memcpy (call2, call, sizeof (MonoCallInst));
1165 switch (ins->opcode) {
1166 case OP_VCALL:
1167 call2->inst.opcode = OP_CALL;
1168 break;
1169 case OP_VCALL_REG:
1170 call2->inst.opcode = OP_CALL_REG;
1171 break;
1172 case OP_VCALL_MEMBASE:
1173 call2->inst.opcode = OP_CALL_MEMBASE;
1174 break;
1176 call2->inst.dreg = alloc_preg (cfg);
1177 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1179 /* Compute the vtype location */
1180 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1181 if (!dest_var)
1182 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1183 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1185 /* Save the result */
1186 if (dest_var->backend.is_pinvoke)
1187 size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
1188 else
1189 size = mono_type_size (dest_var->inst_vtype, NULL);
1190 switch (size) {
1191 case 1:
1192 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1193 break;
1194 case 2:
1195 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1196 break;
1197 case 4:
1198 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1199 break;
1200 case 8:
1201 #if SIZEOF_REGISTER == 4
1203 FIXME It would be nice to fix the operding of OP_CALL to make it possible to use numbering voodoo
1204 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1206 switch (call2->inst.opcode) {
1207 case OP_CALL:
1208 call2->inst.opcode = OP_LCALL;
1209 break;
1210 case OP_CALL_REG:
1211 call2->inst.opcode = OP_LCALL_REG;
1212 break;
1213 case OP_CALL_MEMBASE:
1214 call2->inst.opcode = OP_LCALL_MEMBASE;
1215 break;
1217 call2->inst.dreg = alloc_lreg (cfg);
1218 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1219 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1220 #else
1221 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1222 #endif
1223 break;
1224 default:
1225 /* This assumes the vtype is sizeof (gpointer) long */
1226 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1227 break;
1229 } else {
1230 switch (ins->opcode) {
1231 case OP_VCALL:
1232 ins->opcode = OP_VCALL2;
1233 break;
1234 case OP_VCALL_REG:
1235 ins->opcode = OP_VCALL2_REG;
1236 break;
1237 case OP_VCALL_MEMBASE:
1238 ins->opcode = OP_VCALL2_MEMBASE;
1239 break;
1241 ins->dreg = -1;
1243 break;
1245 default:
1246 break;
1249 g_assert (cfg->cbb == first_bb);
1251 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1252 /* Replace the original instruction with the new code sequence */
1254 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1255 first_bb->code = first_bb->last_ins = NULL;
1256 first_bb->in_count = first_bb->out_count = 0;
1257 cfg->cbb = first_bb;
1259 else
1260 prev = ins;
1264 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1268 #endif /* DISABLE_JIT */