2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include "jit-icalls.h"
15 #include <mono/metadata/gc-internals.h>
16 #include <mono/metadata/abi-details.h>
20 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
21 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
22 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
23 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
26 * Decompose complex long opcodes on 64 bit machines.
27 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
30 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
32 MonoInst *repl = NULL;
36 switch (ins->opcode) {
38 ins->opcode = OP_SEXT_I4;
42 if (SIZEOF_VOID_P == 4)
43 ins->opcode = OP_LMOVE;
45 ins->opcode = OP_MOVE;
48 if (SIZEOF_VOID_P == 4)
50 ins->opcode = OP_SEXT_I4;
52 ins->opcode = OP_MOVE;
55 if (SIZEOF_VOID_P == 4) {
57 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
60 ins->opcode = OP_MOVE;
64 ins->opcode = OP_SEXT_I4;
67 ins->opcode = OP_ZEXT_I4;
70 /* Clean out the upper word */
71 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
77 if (COMPILE_LLVM (cfg))
79 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
83 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
84 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
88 case OP_LADD_OVF_UN: {
91 if (COMPILE_LLVM (cfg))
93 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
97 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
98 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
102 #ifndef __mono_ppc64__
106 if (COMPILE_LLVM (cfg))
108 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
112 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
113 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
117 case OP_LSUB_OVF_UN: {
120 if (COMPILE_LLVM (cfg))
122 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
126 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
127 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
133 case OP_ICONV_TO_OVF_I8:
134 case OP_ICONV_TO_OVF_I:
135 ins->opcode = OP_SEXT_I4;
137 case OP_ICONV_TO_OVF_U8:
138 case OP_ICONV_TO_OVF_U:
139 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
140 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
141 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
144 case OP_ICONV_TO_OVF_I8_UN:
145 case OP_ICONV_TO_OVF_U8_UN:
146 case OP_ICONV_TO_OVF_I_UN:
147 case OP_ICONV_TO_OVF_U_UN:
148 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
149 /* Clean out the upper word */
150 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
153 case OP_LCONV_TO_OVF_I1:
154 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
155 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
156 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
157 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
158 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
161 case OP_LCONV_TO_OVF_I1_UN:
162 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
163 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
164 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
167 case OP_LCONV_TO_OVF_U1:
168 /* probe value to be within 0 to 255 */
169 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
170 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
171 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
174 case OP_LCONV_TO_OVF_U1_UN:
175 /* probe value to be within 0 to 255 */
176 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
177 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
178 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
181 case OP_LCONV_TO_OVF_I2:
182 /* Probe value to be within -32768 and 32767 */
183 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
184 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
185 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
186 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
187 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
190 case OP_LCONV_TO_OVF_I2_UN:
191 /* Probe value to be within 0 and 32767 */
192 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
193 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
194 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
197 case OP_LCONV_TO_OVF_U2:
198 /* Probe value to be within 0 and 65535 */
199 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
200 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
201 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
204 case OP_LCONV_TO_OVF_U2_UN:
205 /* Probe value to be within 0 and 65535 */
206 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
207 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
211 case OP_LCONV_TO_OVF_I4:
212 #if SIZEOF_VOID_P == 4
213 case OP_LCONV_TO_OVF_I:
215 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
216 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
217 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
218 #if SIZEOF_REGISTER == 8
219 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
221 g_assert (COMPILE_LLVM (cfg));
222 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
224 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
225 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
228 case OP_LCONV_TO_OVF_I4_UN:
229 #if SIZEOF_VOID_P == 4
230 case OP_LCONV_TO_OVF_I_UN:
232 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
233 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
234 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
237 case OP_LCONV_TO_OVF_U4:
238 #if SIZEOF_VOID_P == 4
239 case OP_LCONV_TO_OVF_U:
241 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
242 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
243 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
244 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
245 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
248 case OP_LCONV_TO_OVF_U4_UN:
249 #if SIZEOF_VOID_P == 4
250 case OP_LCONV_TO_OVF_U_UN:
252 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
253 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
254 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
257 #if SIZEOF_VOID_P == 8
258 case OP_LCONV_TO_OVF_I:
259 case OP_LCONV_TO_OVF_U_UN:
261 case OP_LCONV_TO_OVF_U8_UN:
262 case OP_LCONV_TO_OVF_I8:
263 ins->opcode = OP_MOVE;
265 #if SIZEOF_VOID_P == 8
266 case OP_LCONV_TO_OVF_I_UN:
268 case OP_LCONV_TO_OVF_I8_UN:
269 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
270 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
271 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
274 case OP_LCONV_TO_OVF_U8:
275 #if SIZEOF_VOID_P == 8
276 case OP_LCONV_TO_OVF_U:
278 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
279 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
280 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
292 * mono_decompose_opcode:
294 * Decompose complex opcodes into ones closer to opcodes supported by
295 * the given architecture.
296 * Returns a MonoInst which represents the result of the decomposition, and can
297 * be pushed on the IL stack. This is needed because the original instruction is
299 * Sets the cfg exception if an opcode is not supported.
302 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
304 MonoInst *repl = NULL;
305 int type = ins->type;
306 int dreg = ins->dreg;
307 gboolean emulate = FALSE;
309 /* FIXME: Instead of = NOP, don't emit the original ins at all */
310 mono_arch_decompose_opts (cfg, ins);
313 * The code below assumes that we are called immediately after emitting
314 * ins. This means we can emit code using the normal code generation
317 switch (ins->opcode) {
318 /* this doesn't make sense on ppc and other architectures */
319 #if !defined(MONO_ARCH_NO_IOV_CHECK)
321 if (COMPILE_LLVM (cfg))
323 ins->opcode = OP_IADDCC;
324 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
327 if (COMPILE_LLVM (cfg))
329 ins->opcode = OP_IADDCC;
330 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
333 if (COMPILE_LLVM (cfg))
335 ins->opcode = OP_ISUBCC;
336 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
339 if (COMPILE_LLVM (cfg))
341 ins->opcode = OP_ISUBCC;
342 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
345 case OP_ICONV_TO_OVF_I1:
346 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
347 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
348 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
349 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
350 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
353 case OP_ICONV_TO_OVF_I1_UN:
354 /* probe values between 0 to 127 */
355 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
356 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
357 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
360 case OP_ICONV_TO_OVF_U1:
361 case OP_ICONV_TO_OVF_U1_UN:
362 /* probe value to be within 0 to 255 */
363 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
364 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
365 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
368 case OP_ICONV_TO_OVF_I2:
369 /* Probe value to be within -32768 and 32767 */
370 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
371 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
372 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
373 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
374 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
377 case OP_ICONV_TO_OVF_I2_UN:
378 /* Convert uint value into short, value within 0 and 32767 */
379 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
380 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
381 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
384 case OP_ICONV_TO_OVF_U2:
385 case OP_ICONV_TO_OVF_U2_UN:
386 /* Probe value to be within 0 and 65535 */
387 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
388 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
389 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
392 case OP_ICONV_TO_OVF_U4:
393 case OP_ICONV_TO_OVF_I4_UN:
394 #if SIZEOF_VOID_P == 4
395 case OP_ICONV_TO_OVF_U:
396 case OP_ICONV_TO_OVF_I_UN:
398 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
399 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
400 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
405 case OP_ICONV_TO_OVF_I4:
406 case OP_ICONV_TO_OVF_U4_UN:
407 #if SIZEOF_VOID_P == 4
408 case OP_ICONV_TO_OVF_I:
409 case OP_ICONV_TO_OVF_U_UN:
411 ins->opcode = OP_MOVE;
414 #if SIZEOF_VOID_P == 8
415 ins->opcode = OP_SEXT_I4;
417 ins->opcode = OP_MOVE;
421 #if SIZEOF_VOID_P == 8
422 ins->opcode = OP_ZEXT_I4;
424 ins->opcode = OP_MOVE;
429 ins->opcode = OP_FMOVE;
432 case OP_FCONV_TO_OVF_I1_UN:
433 case OP_FCONV_TO_OVF_I2_UN:
434 case OP_FCONV_TO_OVF_I4_UN:
435 case OP_FCONV_TO_OVF_I8_UN:
436 case OP_FCONV_TO_OVF_U1_UN:
437 case OP_FCONV_TO_OVF_U2_UN:
438 case OP_FCONV_TO_OVF_U4_UN:
439 case OP_FCONV_TO_OVF_U8_UN:
440 case OP_FCONV_TO_OVF_I_UN:
441 case OP_FCONV_TO_OVF_U_UN:
442 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
449 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
452 if (cfg->backend->need_div_check) {
453 int reg1 = alloc_ireg (cfg);
454 int reg2 = alloc_ireg (cfg);
456 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
457 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
458 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
459 /* b == -1 && a == 0x80000000 */
460 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
461 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
463 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
464 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
465 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
466 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
469 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
478 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
481 if (cfg->backend->need_div_check) {
482 int reg1 = alloc_ireg (cfg);
483 int reg2 = alloc_ireg (cfg);
484 int reg3 = alloc_ireg (cfg);
486 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
487 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
488 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
489 /* b == -1 && a == 0x80000000 */
490 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
491 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
492 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
493 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
494 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
495 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
496 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
497 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
498 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
501 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
512 if (cfg->backend->need_div_check) {
513 int reg1 = alloc_ireg (cfg);
515 if (ins->inst_imm == 0) {
516 // FIXME: Optimize this
517 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
518 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
519 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
521 if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
522 (ins->inst_imm == -1)) {
523 /* b == -1 && a == 0x80000000 */
524 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
525 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
527 MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
540 #if SIZEOF_REGISTER == 8
541 if (decompose_long_opcode (cfg, ins, &repl))
544 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
548 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
549 cfg->has_emulated_ops = TRUE;
552 if (ins->opcode == OP_NOP) {
557 /* Use the last emitted instruction */
558 ins = cfg->cbb->last_ins;
561 g_assert (ins->dreg == dreg);
569 #if SIZEOF_REGISTER == 4
570 static int lbr_decomp [][2] = {
572 {OP_IBGT, OP_IBGE_UN}, /* BGE */
573 {OP_IBGT, OP_IBGT_UN}, /* BGT */
574 {OP_IBLT, OP_IBLE_UN}, /* BLE */
575 {OP_IBLT, OP_IBLT_UN}, /* BLT */
577 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
578 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
579 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
580 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
583 static int lcset_decomp [][2] = {
585 {OP_IBLT, OP_IBLE_UN}, /* CGT */
586 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
587 {OP_IBGT, OP_IBGE_UN}, /* CLT */
588 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
593 * mono_decompose_long_opts:
595 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
598 mono_decompose_long_opts (MonoCompile *cfg)
600 #if SIZEOF_REGISTER == 4
601 MonoBasicBlock *bb, *first_bb;
604 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
605 * needs to be able to handle long vregs.
609 * Create a dummy bblock and emit code into it so we can use the normal
610 * code generation macros.
612 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
615 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
616 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
617 MonoInst *prev = NULL;
620 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
623 cfg->cbb->code = cfg->cbb->last_ins = NULL;
626 mono_arch_decompose_long_opts (cfg, tree);
628 switch (tree->opcode) {
630 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
631 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
633 case OP_DUMMY_I8CONST:
634 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
635 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
640 case OP_LCONV_TO_OVF_U8_UN:
641 case OP_LCONV_TO_OVF_I8:
642 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
643 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
645 case OP_STOREI8_MEMBASE_REG:
646 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (tree->sreg1));
647 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (tree->sreg1));
649 case OP_LOADI8_MEMBASE:
650 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_MS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
651 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_LS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
654 case OP_ICONV_TO_I8: {
655 guint32 tmpreg = alloc_ireg (cfg);
659 * tmp = low > -1 ? 1: 0;
660 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
662 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
663 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
664 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
665 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
669 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
670 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
672 case OP_ICONV_TO_OVF_I8:
673 /* a signed 32 bit num always fits in a signed 64 bit one */
674 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
675 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
677 case OP_ICONV_TO_OVF_U8:
678 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
679 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
680 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
681 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
683 case OP_ICONV_TO_OVF_I8_UN:
684 case OP_ICONV_TO_OVF_U8_UN:
685 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
686 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
687 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
690 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
693 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
696 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
699 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
705 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
707 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
709 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
712 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
714 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
717 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
718 case OP_LCONV_TO_R_UN:
719 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
722 case OP_LCONV_TO_OVF_I1: {
723 MonoBasicBlock *is_negative, *end_label;
725 NEW_BBLOCK (cfg, is_negative);
726 NEW_BBLOCK (cfg, end_label);
728 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
729 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
730 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
731 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
733 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
734 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
737 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
738 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
739 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
742 MONO_START_BB (cfg, is_negative);
743 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
744 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
746 MONO_START_BB (cfg, end_label);
748 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
751 case OP_LCONV_TO_OVF_I1_UN:
752 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
753 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
755 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
756 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
757 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
758 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
759 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
761 case OP_LCONV_TO_OVF_U1:
762 case OP_LCONV_TO_OVF_U1_UN:
763 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
764 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
766 /* probe value to be within 0 to 255 */
767 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
768 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
769 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
771 case OP_LCONV_TO_OVF_I2: {
772 MonoBasicBlock *is_negative, *end_label;
774 NEW_BBLOCK (cfg, is_negative);
775 NEW_BBLOCK (cfg, end_label);
777 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
778 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
779 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
780 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
783 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
786 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
787 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
788 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
791 MONO_START_BB (cfg, is_negative);
792 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
793 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
794 MONO_START_BB (cfg, end_label);
796 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
799 case OP_LCONV_TO_OVF_I2_UN:
800 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
801 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
803 /* Probe value to be within -32768 and 32767 */
804 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
805 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
806 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
807 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
808 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
810 case OP_LCONV_TO_OVF_U2:
811 case OP_LCONV_TO_OVF_U2_UN:
812 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
813 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
815 /* Probe value to be within 0 and 65535 */
816 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
817 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
818 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
820 case OP_LCONV_TO_OVF_I4:
821 case OP_LCONV_TO_OVF_I:
822 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
824 case OP_LCONV_TO_OVF_U4:
825 case OP_LCONV_TO_OVF_U:
826 case OP_LCONV_TO_OVF_U4_UN:
827 case OP_LCONV_TO_OVF_U_UN:
828 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
829 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
830 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
832 case OP_LCONV_TO_OVF_I_UN:
833 case OP_LCONV_TO_OVF_I4_UN:
834 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
835 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
836 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
837 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
838 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
840 case OP_LCONV_TO_OVF_U8:
841 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
842 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
844 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
845 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
847 case OP_LCONV_TO_OVF_I8_UN:
848 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
849 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
851 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
852 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
856 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
857 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
860 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
861 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
865 /* ADC sets the condition code */
866 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
867 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
868 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
871 /* ADC sets the condition code */
872 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
873 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
874 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
877 /* SBB sets the condition code */
878 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
879 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
880 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
883 /* SBB sets the condition code */
884 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
885 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
886 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
889 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
890 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
893 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
894 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
897 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
898 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
901 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
902 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
905 /* Handled in mono_arch_decompose_long_opts () */
906 g_assert_not_reached ();
910 /* FIXME: Add OP_BIGMUL optimization */
914 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
915 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
918 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
919 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
922 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
923 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
930 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
934 if (tree->inst_c1 == 32) {
936 /* The original code had this comment: */
937 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
938 * later apply the speedup to the left shift as well
941 /* FIXME: Move this to the strength reduction pass */
942 /* just move the upper half to the lower and zero the high word */
943 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
944 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
948 if (tree->inst_c1 == 32) {
949 /* just move the lower half to the upper and zero the lower word */
950 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
951 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
956 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
960 switch (next->opcode) {
965 /* Branchless version based on gcc code */
966 d1 = alloc_ireg (cfg);
967 d2 = alloc_ireg (cfg);
968 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
969 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
970 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
971 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
972 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
984 /* Convert into three comparisons + branches */
985 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
986 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
987 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
988 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
989 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
990 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
996 /* Branchless version based on gcc code */
997 d1 = alloc_ireg (cfg);
998 d2 = alloc_ireg (cfg);
999 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1000 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1001 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1003 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1004 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1012 MonoBasicBlock *set_to_0, *set_to_1;
1014 NEW_BBLOCK (cfg, set_to_0);
1015 NEW_BBLOCK (cfg, set_to_1);
1017 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1018 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1019 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1020 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1021 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1022 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1023 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1024 MONO_START_BB (cfg, set_to_1);
1025 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1026 MONO_START_BB (cfg, set_to_0);
1031 g_assert_not_reached ();
1036 /* Not yet used, since lcompare is decomposed before local cprop */
1037 case OP_LCOMPARE_IMM: {
1038 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1039 guint32 low_imm = tree->inst_ls_word;
1040 guint32 high_imm = tree->inst_ms_word;
1041 int low_reg = MONO_LVREG_LS (tree->sreg1);
1042 int high_reg = MONO_LVREG_MS (tree->sreg1);
1046 switch (next->opcode) {
1051 /* Branchless version based on gcc code */
1052 d1 = alloc_ireg (cfg);
1053 d2 = alloc_ireg (cfg);
1054 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1055 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1056 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1057 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1058 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1071 /* Convert into three comparisons + branches */
1072 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1073 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1074 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1075 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1076 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1077 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1083 /* Branchless version based on gcc code */
1084 d1 = alloc_ireg (cfg);
1085 d2 = alloc_ireg (cfg);
1086 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1087 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1088 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1090 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1091 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1099 MonoBasicBlock *set_to_0, *set_to_1;
1101 NEW_BBLOCK (cfg, set_to_0);
1102 NEW_BBLOCK (cfg, set_to_1);
1104 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1105 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1106 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1107 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1108 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1109 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1110 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1111 MONO_START_BB (cfg, set_to_1);
1112 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1113 MONO_START_BB (cfg, set_to_0);
1118 g_assert_not_reached ();
1127 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1130 /* Replace the original instruction with the new code sequence */
1132 /* Ignore the new value of prev */
1134 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1136 /* Process the newly added ops again since they can be long ops too */
1138 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1140 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1142 first_bb->code = first_bb->last_ins = NULL;
1143 first_bb->in_count = first_bb->out_count = 0;
1144 cfg->cbb = first_bb;
1148 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1155 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1156 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1161 * mono_decompose_vtype_opts:
1163 * Decompose valuetype opcodes.
1166 mono_decompose_vtype_opts (MonoCompile *cfg)
1168 MonoBasicBlock *bb, *first_bb;
1171 * Using OP_V opcodes and decomposing them later have two main benefits:
1172 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1174 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1175 * enabling optimizations to work on vtypes too.
1176 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1177 * can be executed anytime. It should be executed as late as possible so vtype
1178 * opcodes can be optimized by the other passes.
1179 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1180 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1182 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1183 * when OP_VMOVE opcodes are decomposed.
1187 * Vregs have no associated type information, so we store the type of the vregs
1192 * Create a dummy bblock and emit code into it so we can use the normal
1193 * code generation macros.
1195 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1196 first_bb = cfg->cbb;
1198 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1200 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1202 MonoInst *prev = NULL;
1203 MonoInst *src_var, *dest_var, *src, *dest;
1207 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1209 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1215 for (ins = bb->code; ins; ins = ins->next) {
1216 switch (ins->opcode) {
1218 g_assert (ins->klass);
1219 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1221 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1222 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1225 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1228 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1231 if (src_var->backend.is_pinvoke)
1232 dest_var->backend.is_pinvoke = 1;
1234 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1235 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1237 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1241 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1244 g_assert (ins->klass);
1246 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1247 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1249 if (cfg->compute_gc_maps) {
1253 * Tell the GC map code that the vtype is considered live after
1254 * the initialization.
1256 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1257 tmp->inst_c1 = ins->dreg;
1258 MONO_ADD_INS (cfg->cbb, tmp);
1261 case OP_DUMMY_VZERO:
1262 if (COMPILE_LLVM (cfg))
1267 case OP_STOREV_MEMBASE: {
1268 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1271 g_assert (ins->klass);
1272 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1275 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1277 dreg = alloc_preg (cfg);
1278 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1279 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1282 case OP_LOADV_MEMBASE: {
1283 g_assert (ins->klass);
1284 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1287 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1291 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1293 dreg = alloc_preg (cfg);
1294 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1295 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1296 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1299 case OP_OUTARG_VT: {
1300 if (COMPILE_LLVM (cfg))
1303 g_assert (ins->klass);
1305 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1307 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1308 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1310 mono_arch_emit_outarg_vt (cfg, ins, src);
1312 /* This might be decomposed into other vtype opcodes */
1316 case OP_OUTARG_VTRETADDR: {
1317 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1319 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1321 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1322 // FIXME: src_var->backend.is_pinvoke ?
1324 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1325 src->dreg = ins->dreg;
1330 case OP_VCALL_MEMBASE: {
1331 MonoCallInst *call = (MonoCallInst*)ins;
1334 if (COMPILE_LLVM (cfg))
1337 if (call->vret_in_reg) {
1338 MonoCallInst *call2;
1340 /* Replace the vcall with a scalar call */
1341 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1342 memcpy (call2, call, sizeof (MonoCallInst));
1343 switch (ins->opcode) {
1345 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1348 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1350 case OP_VCALL_MEMBASE:
1351 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1354 call2->inst.dreg = alloc_preg (cfg);
1355 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1357 /* Compute the vtype location */
1358 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1360 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1361 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1363 /* Save the result */
1364 if (dest_var->backend.is_pinvoke)
1365 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1367 size = mono_type_size (dest_var->inst_vtype, NULL);
1370 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1373 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1377 if (call->vret_in_reg_fp)
1378 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1380 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1386 if (call->vret_in_reg_fp) {
1387 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1390 #if SIZEOF_REGISTER == 4
1392 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1393 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1395 switch (call2->inst.opcode) {
1397 call2->inst.opcode = OP_LCALL;
1400 call2->inst.opcode = OP_LCALL_REG;
1402 case OP_CALL_MEMBASE:
1403 call2->inst.opcode = OP_LCALL_MEMBASE;
1406 call2->inst.dreg = alloc_lreg (cfg);
1407 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1408 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1410 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1414 /* This assumes the vtype is sizeof (gpointer) long */
1415 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1419 switch (ins->opcode) {
1421 ins->opcode = OP_VCALL2;
1424 ins->opcode = OP_VCALL2_REG;
1426 case OP_VCALL_MEMBASE:
1427 ins->opcode = OP_VCALL2_MEMBASE;
1438 g_assert (cfg->cbb == first_bb);
1440 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1441 /* Replace the original instruction with the new code sequence */
1443 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1444 first_bb->code = first_bb->last_ins = NULL;
1445 first_bb->in_count = first_bb->out_count = 0;
1446 cfg->cbb = first_bb;
1453 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1457 inline static MonoInst *
1458 mono_get_domainvar (MonoCompile *cfg)
1460 if (!cfg->domainvar)
1461 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1462 return cfg->domainvar;
1466 * mono_decompose_array_access_opts:
1468 * Decompose array access opcodes.
1471 mono_decompose_array_access_opts (MonoCompile *cfg)
1473 MonoBasicBlock *bb, *first_bb;
1476 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1477 * can be executed anytime. It should be run before decompose_long
1481 * Create a dummy bblock and emit code into it so we can use the normal
1482 * code generation macros.
1484 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1485 first_bb = cfg->cbb;
1487 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1489 MonoInst *prev = NULL;
1491 MonoInst *iargs [3];
1494 if (!bb->has_array_access)
1497 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1499 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1505 for (ins = bb->code; ins; ins = ins->next) {
1506 switch (ins->opcode) {
1508 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1509 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1510 MONO_ADD_INS (cfg->cbb, dest);
1512 case OP_BOUNDS_CHECK:
1513 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1514 if (COMPILE_LLVM (cfg))
1515 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1517 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1520 if (cfg->opt & MONO_OPT_SHARED) {
1521 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1522 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1523 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1524 iargs [2]->dreg = ins->sreg1;
1526 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1527 dest->dreg = ins->dreg;
1529 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1530 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1531 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1533 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1534 NEW_VTABLECONST (cfg, iargs [0], vtable);
1535 MONO_ADD_INS (cfg->cbb, iargs [0]);
1536 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1537 iargs [1]->dreg = ins->sreg1;
1540 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1542 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1543 dest->dreg = ins->dreg;
1547 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1548 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1554 g_assert (cfg->cbb == first_bb);
1556 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1557 /* Replace the original instruction with the new code sequence */
1559 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1560 first_bb->code = first_bb->last_ins = NULL;
1561 first_bb->in_count = first_bb->out_count = 0;
1562 cfg->cbb = first_bb;
1569 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1579 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1582 * mono_decompose_soft_float:
1584 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1585 * similar to long support on 32 bit platforms. 32 bit float values require special
1586 * handling when used as locals, arguments, and in calls.
1587 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1590 mono_decompose_soft_float (MonoCompile *cfg)
1592 MonoBasicBlock *bb, *first_bb;
1595 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1599 * Create a dummy bblock and emit code into it so we can use the normal
1600 * code generation macros.
1602 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1603 first_bb = cfg->cbb;
1605 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1607 MonoInst *prev = NULL;
1610 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1612 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1618 for (ins = bb->code; ins; ins = ins->next) {
1619 const char *spec = INS_INFO (ins->opcode);
1621 /* Most fp operations are handled automatically by opcode emulation */
1623 switch (ins->opcode) {
1626 d.vald = *(double*)ins->inst_p0;
1627 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1632 /* We load the r8 value */
1633 d.vald = *(float*)ins->inst_p0;
1634 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1638 ins->opcode = OP_LMOVE;
1641 ins->opcode = OP_MOVE;
1642 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1645 ins->opcode = OP_MOVE;
1646 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1649 int reg = ins->sreg1;
1651 ins->opcode = OP_SETLRET;
1653 ins->sreg1 = MONO_LVREG_LS (reg);
1654 ins->sreg2 = MONO_LVREG_MS (reg);
1657 case OP_LOADR8_MEMBASE:
1658 ins->opcode = OP_LOADI8_MEMBASE;
1660 case OP_STORER8_MEMBASE_REG:
1661 ins->opcode = OP_STOREI8_MEMBASE_REG;
1663 case OP_STORER4_MEMBASE_REG: {
1664 MonoInst *iargs [2];
1667 /* Arg 1 is the double value */
1668 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1669 iargs [0]->dreg = ins->sreg1;
1671 /* Arg 2 is the address to store to */
1672 addr_reg = mono_alloc_preg (cfg);
1673 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1674 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1678 case OP_LOADR4_MEMBASE: {
1679 MonoInst *iargs [1];
1683 addr_reg = mono_alloc_preg (cfg);
1684 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1685 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1686 conv->dreg = ins->dreg;
1691 case OP_FCALL_MEMBASE: {
1692 MonoCallInst *call = (MonoCallInst*)ins;
1693 if (call->signature->ret->type == MONO_TYPE_R4) {
1694 MonoCallInst *call2;
1695 MonoInst *iargs [1];
1699 /* Convert the call into a call returning an int */
1700 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1701 memcpy (call2, call, sizeof (MonoCallInst));
1702 switch (ins->opcode) {
1704 call2->inst.opcode = OP_CALL;
1707 call2->inst.opcode = OP_CALL_REG;
1709 case OP_FCALL_MEMBASE:
1710 call2->inst.opcode = OP_CALL_MEMBASE;
1713 g_assert_not_reached ();
1715 call2->inst.dreg = mono_alloc_ireg (cfg);
1716 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1718 /* Remap OUTARG_VT instructions referencing this call */
1719 for (l = call->outarg_vts; l; l = l->next)
1720 ((MonoInst*)(l->data))->inst_p0 = call2;
1722 /* FIXME: Optimize this */
1724 /* Emit an r4->r8 conversion */
1725 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1726 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1727 conv->dreg = ins->dreg;
1729 /* The call sequence might include fp ins */
1732 switch (ins->opcode) {
1734 ins->opcode = OP_LCALL;
1737 ins->opcode = OP_LCALL_REG;
1739 case OP_FCALL_MEMBASE:
1740 ins->opcode = OP_LCALL_MEMBASE;
1743 g_assert_not_reached ();
1749 MonoJitICallInfo *info;
1750 MonoInst *iargs [2];
1751 MonoInst *call, *cmp, *br;
1753 /* Convert fcompare+fbcc to icall+icompare+beq */
1756 /* The branch might be optimized away */
1761 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1763 /* The branch might be optimized away */
1768 /* Create dummy MonoInst's for the arguments */
1769 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1770 iargs [0]->dreg = ins->sreg1;
1771 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1772 iargs [1]->dreg = ins->sreg2;
1774 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1776 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1777 cmp->sreg1 = call->dreg;
1779 MONO_ADD_INS (cfg->cbb, cmp);
1781 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1782 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1783 br->inst_true_bb = ins->next->inst_true_bb;
1784 br->inst_false_bb = ins->next->inst_false_bb;
1785 MONO_ADD_INS (cfg->cbb, br);
1787 /* The call sequence might include fp ins */
1790 /* Skip fbcc or fccc */
1791 NULLIFY_INS (ins->next);
1799 MonoJitICallInfo *info;
1800 MonoInst *iargs [2];
1803 /* Convert fccc to icall+icompare+iceq */
1805 info = mono_find_jit_opcode_emulation (ins->opcode);
1808 /* Create dummy MonoInst's for the arguments */
1809 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1810 iargs [0]->dreg = ins->sreg1;
1811 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1812 iargs [1]->dreg = ins->sreg2;
1814 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1816 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1817 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1819 /* The call sequence might include fp ins */
1824 MonoInst *iargs [2];
1825 MonoInst *call, *cmp;
1827 /* Convert to icall+icompare+cond_exc+move */
1829 /* Create dummy MonoInst's for the arguments */
1830 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1831 iargs [0]->dreg = ins->sreg1;
1833 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1835 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1836 cmp->sreg1 = call->dreg;
1838 MONO_ADD_INS (cfg->cbb, cmp);
1840 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1842 /* Do the assignment if the value is finite */
1843 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1849 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1850 mono_print_ins (ins);
1851 g_assert_not_reached ();
1856 g_assert (cfg->cbb == first_bb);
1858 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1859 /* Replace the original instruction with the new code sequence */
1861 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1862 first_bb->code = first_bb->last_ins = NULL;
1863 first_bb->in_count = first_bb->out_count = 0;
1864 cfg->cbb = first_bb;
1871 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1874 mono_decompose_long_opts (cfg);
1880 mono_local_emulate_ops (MonoCompile *cfg)
1883 gboolean inlined_wrapper = FALSE;
1885 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1888 MONO_BB_FOR_EACH_INS (bb, ins) {
1889 int op_noimm = mono_op_imm_to_op (ins->opcode);
1890 MonoJitICallInfo *info;
1893 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1894 * to check whether its non-imm counterpart is emulated and, if so,
1895 * decompose it back to its non-imm counterpart.
1898 info = mono_find_jit_opcode_emulation (op_noimm);
1900 info = mono_find_jit_opcode_emulation (ins->opcode);
1905 MonoBasicBlock *first_bb;
1907 /* Create dummy MonoInst's for the arguments */
1908 g_assert (!info->sig->hasthis);
1909 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1912 mono_decompose_op_imm (cfg, bb, ins);
1914 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1915 if (info->sig->param_count > 0) {
1916 int sregs [MONO_MAX_SRC_REGS];
1918 num_sregs = mono_inst_get_src_registers (ins, sregs);
1919 g_assert (num_sregs == info->sig->param_count);
1920 for (i = 0; i < num_sregs; ++i) {
1921 MONO_INST_NEW (cfg, args [i], OP_ARG);
1922 args [i]->dreg = sregs [i];
1926 /* We emit the call on a separate dummy basic block */
1927 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1928 first_bb = cfg->cbb;
1930 call = mono_emit_jit_icall_by_info (cfg, info, args);
1931 call->dreg = ins->dreg;
1933 /* Replace ins with the emitted code and do the necessary bb linking */
1934 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1935 MonoInst *saved_prev = ins->prev;
1937 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1938 first_bb->code = first_bb->last_ins = NULL;
1939 first_bb->in_count = first_bb->out_count = 0;
1940 cfg->cbb = first_bb;
1942 /* ins is hanging, continue scanning the emitted code */
1945 g_error ("Failed to emit emulation code");
1947 inlined_wrapper = TRUE;
1953 * Avoid rerunning these passes by emitting directly the exception checkpoint
1954 * at IR level, instead of inlining the icall wrapper. FIXME
1956 if (inlined_wrapper) {
1957 if (!COMPILE_LLVM (cfg))
1958 mono_decompose_long_opts (cfg);
1959 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1960 mono_local_cprop (cfg);
1964 #endif /* DISABLE_JIT */