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);
474 #if SIZEOF_VOID_P == 8
479 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
482 if (cfg->backend->need_div_check) {
483 int reg1 = alloc_ireg (cfg);
484 int reg2 = alloc_ireg (cfg);
485 int reg3 = alloc_ireg (cfg);
487 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
488 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
489 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
490 /* b == -1 && a == 0x80000000 */
491 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
492 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
493 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
494 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
495 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
496 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
497 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
498 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
499 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
502 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
514 if (cfg->backend->need_div_check) {
515 int reg1 = alloc_ireg (cfg);
517 if (ins->inst_imm == 0) {
518 // FIXME: Optimize this
519 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
520 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
521 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
523 if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
524 (ins->inst_imm == -1)) {
525 /* b == -1 && a == 0x80000000 */
526 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
527 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
529 MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
542 #if SIZEOF_REGISTER == 8
543 if (decompose_long_opcode (cfg, ins, &repl))
546 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
550 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
551 cfg->has_emulated_ops = TRUE;
554 if (ins->opcode == OP_NOP) {
559 /* Use the last emitted instruction */
560 ins = cfg->cbb->last_ins;
563 g_assert (ins->dreg == dreg);
571 #if SIZEOF_REGISTER == 4
572 static int lbr_decomp [][2] = {
574 {OP_IBGT, OP_IBGE_UN}, /* BGE */
575 {OP_IBGT, OP_IBGT_UN}, /* BGT */
576 {OP_IBLT, OP_IBLE_UN}, /* BLE */
577 {OP_IBLT, OP_IBLT_UN}, /* BLT */
579 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
580 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
581 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
582 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
585 static int lcset_decomp [][2] = {
587 {OP_IBLT, OP_IBLE_UN}, /* CGT */
588 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
589 {OP_IBGT, OP_IBGE_UN}, /* CLT */
590 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
595 * mono_decompose_long_opts:
597 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
600 mono_decompose_long_opts (MonoCompile *cfg)
602 #if SIZEOF_REGISTER == 4
603 MonoBasicBlock *bb, *first_bb;
606 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
607 * needs to be able to handle long vregs.
611 * Create a dummy bblock and emit code into it so we can use the normal
612 * code generation macros.
614 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
617 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
618 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
619 MonoInst *prev = NULL;
622 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
625 cfg->cbb->code = cfg->cbb->last_ins = NULL;
628 mono_arch_decompose_long_opts (cfg, tree);
630 switch (tree->opcode) {
632 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
633 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
635 case OP_DUMMY_I8CONST:
636 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
637 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
642 case OP_LCONV_TO_OVF_U8_UN:
643 case OP_LCONV_TO_OVF_I8:
644 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
645 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
647 case OP_STOREI8_MEMBASE_REG:
648 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));
649 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));
651 case OP_LOADI8_MEMBASE:
652 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);
653 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);
656 case OP_ICONV_TO_I8: {
657 guint32 tmpreg = alloc_ireg (cfg);
661 * tmp = low > -1 ? 1: 0;
662 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
664 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
665 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
666 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
667 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
671 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
672 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
674 case OP_ICONV_TO_OVF_I8:
675 /* a signed 32 bit num always fits in a signed 64 bit one */
676 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
677 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
679 case OP_ICONV_TO_OVF_U8:
680 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
681 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
682 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
683 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
685 case OP_ICONV_TO_OVF_I8_UN:
686 case OP_ICONV_TO_OVF_U8_UN:
687 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
688 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
689 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
692 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
695 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
698 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
701 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
707 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
709 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
711 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
714 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
716 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
719 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
720 case OP_LCONV_TO_R_UN:
721 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
724 case OP_LCONV_TO_OVF_I1: {
725 MonoBasicBlock *is_negative, *end_label;
727 NEW_BBLOCK (cfg, is_negative);
728 NEW_BBLOCK (cfg, end_label);
730 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
731 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
732 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
733 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
735 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
736 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
739 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
740 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
741 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
744 MONO_START_BB (cfg, is_negative);
745 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
746 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
748 MONO_START_BB (cfg, end_label);
750 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
753 case OP_LCONV_TO_OVF_I1_UN:
754 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
755 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
757 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
758 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
759 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
760 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
761 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
763 case OP_LCONV_TO_OVF_U1:
764 case OP_LCONV_TO_OVF_U1_UN:
765 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
766 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
768 /* probe value to be within 0 to 255 */
769 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
770 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
771 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
773 case OP_LCONV_TO_OVF_I2: {
774 MonoBasicBlock *is_negative, *end_label;
776 NEW_BBLOCK (cfg, is_negative);
777 NEW_BBLOCK (cfg, end_label);
779 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
780 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
782 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
784 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
785 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
788 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
789 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
790 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
793 MONO_START_BB (cfg, is_negative);
794 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
795 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
796 MONO_START_BB (cfg, end_label);
798 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
801 case OP_LCONV_TO_OVF_I2_UN:
802 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
803 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
805 /* Probe value to be within -32768 and 32767 */
806 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
807 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
808 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
809 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
810 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
812 case OP_LCONV_TO_OVF_U2:
813 case OP_LCONV_TO_OVF_U2_UN:
814 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
815 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
817 /* Probe value to be within 0 and 65535 */
818 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
819 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
820 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
822 case OP_LCONV_TO_OVF_I4:
823 case OP_LCONV_TO_OVF_I:
824 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
826 case OP_LCONV_TO_OVF_U4:
827 case OP_LCONV_TO_OVF_U:
828 case OP_LCONV_TO_OVF_U4_UN:
829 case OP_LCONV_TO_OVF_U_UN:
830 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
831 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
832 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
834 case OP_LCONV_TO_OVF_I_UN:
835 case OP_LCONV_TO_OVF_I4_UN:
836 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
837 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
838 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
839 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
840 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
842 case OP_LCONV_TO_OVF_U8:
843 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
844 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
846 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
847 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
849 case OP_LCONV_TO_OVF_I8_UN:
850 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
851 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
853 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
854 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
858 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
859 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
862 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
863 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
867 /* ADC sets the condition code */
868 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
869 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
870 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
873 /* ADC sets the condition code */
874 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
875 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
876 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
879 /* SBB sets the condition code */
880 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
881 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
882 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
885 /* SBB sets the condition code */
886 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
887 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
888 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
891 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
892 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
895 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
896 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
899 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
900 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
903 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
904 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
907 /* Handled in mono_arch_decompose_long_opts () */
908 g_assert_not_reached ();
912 /* FIXME: Add OP_BIGMUL optimization */
916 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
917 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
920 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
932 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
936 if (tree->inst_c1 == 32) {
938 /* The original code had this comment: */
939 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
940 * later apply the speedup to the left shift as well
943 /* FIXME: Move this to the strength reduction pass */
944 /* just move the upper half to the lower and zero the high word */
945 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
946 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
950 if (tree->inst_c1 == 32) {
951 /* just move the lower half to the upper and zero the lower word */
952 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
953 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
958 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
962 switch (next->opcode) {
967 /* Branchless version based on gcc code */
968 d1 = alloc_ireg (cfg);
969 d2 = alloc_ireg (cfg);
970 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
971 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
972 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
973 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
974 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
986 /* Convert into three comparisons + branches */
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, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
989 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
990 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
991 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
992 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
998 /* Branchless version based on gcc code */
999 d1 = alloc_ireg (cfg);
1000 d2 = alloc_ireg (cfg);
1001 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1002 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1003 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1005 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1006 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1014 MonoBasicBlock *set_to_0, *set_to_1;
1016 NEW_BBLOCK (cfg, set_to_0);
1017 NEW_BBLOCK (cfg, set_to_1);
1019 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 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, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1022 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1023 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1024 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1025 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1026 MONO_START_BB (cfg, set_to_1);
1027 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1028 MONO_START_BB (cfg, set_to_0);
1033 g_assert_not_reached ();
1038 /* Not yet used, since lcompare is decomposed before local cprop */
1039 case OP_LCOMPARE_IMM: {
1040 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1041 guint32 low_imm = tree->inst_ls_word;
1042 guint32 high_imm = tree->inst_ms_word;
1043 int low_reg = MONO_LVREG_LS (tree->sreg1);
1044 int high_reg = MONO_LVREG_MS (tree->sreg1);
1048 switch (next->opcode) {
1053 /* Branchless version based on gcc code */
1054 d1 = alloc_ireg (cfg);
1055 d2 = alloc_ireg (cfg);
1056 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1057 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1058 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1059 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1060 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1073 /* Convert into three comparisons + branches */
1074 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1075 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1076 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1077 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1078 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1079 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1085 /* Branchless version based on gcc code */
1086 d1 = alloc_ireg (cfg);
1087 d2 = alloc_ireg (cfg);
1088 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1089 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1090 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1092 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1093 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1101 MonoBasicBlock *set_to_0, *set_to_1;
1103 NEW_BBLOCK (cfg, set_to_0);
1104 NEW_BBLOCK (cfg, set_to_1);
1106 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1107 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1108 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1109 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1110 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1111 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1112 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1113 MONO_START_BB (cfg, set_to_1);
1114 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1115 MONO_START_BB (cfg, set_to_0);
1120 g_assert_not_reached ();
1129 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1132 /* Replace the original instruction with the new code sequence */
1134 /* Ignore the new value of prev */
1136 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1138 /* Process the newly added ops again since they can be long ops too */
1140 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1142 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1144 first_bb->code = first_bb->last_ins = NULL;
1145 first_bb->in_count = first_bb->out_count = 0;
1146 cfg->cbb = first_bb;
1150 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1157 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1158 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1163 * mono_decompose_vtype_opts:
1165 * Decompose valuetype opcodes.
1168 mono_decompose_vtype_opts (MonoCompile *cfg)
1170 MonoBasicBlock *bb, *first_bb;
1173 * Using OP_V opcodes and decomposing them later have two main benefits:
1174 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1176 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1177 * enabling optimizations to work on vtypes too.
1178 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1179 * can be executed anytime. It should be executed as late as possible so vtype
1180 * opcodes can be optimized by the other passes.
1181 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1182 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1184 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1185 * when OP_VMOVE opcodes are decomposed.
1189 * Vregs have no associated type information, so we store the type of the vregs
1194 * Create a dummy bblock and emit code into it so we can use the normal
1195 * code generation macros.
1197 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1198 first_bb = cfg->cbb;
1200 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1202 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1204 MonoInst *prev = NULL;
1205 MonoInst *src_var, *dest_var, *src, *dest;
1209 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1211 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1217 for (ins = bb->code; ins; ins = ins->next) {
1218 switch (ins->opcode) {
1220 g_assert (ins->klass);
1221 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1223 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1224 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1227 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1230 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1233 if (src_var->backend.is_pinvoke)
1234 dest_var->backend.is_pinvoke = 1;
1236 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1237 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1239 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1243 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1246 g_assert (ins->klass);
1248 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1249 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1251 if (cfg->compute_gc_maps) {
1255 * Tell the GC map code that the vtype is considered live after
1256 * the initialization.
1258 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1259 tmp->inst_c1 = ins->dreg;
1260 MONO_ADD_INS (cfg->cbb, tmp);
1263 case OP_DUMMY_VZERO:
1264 if (COMPILE_LLVM (cfg))
1269 case OP_STOREV_MEMBASE: {
1270 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1273 g_assert (ins->klass);
1274 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1277 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1279 dreg = alloc_preg (cfg);
1280 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1281 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1284 case OP_LOADV_MEMBASE: {
1285 g_assert (ins->klass);
1286 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1289 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1293 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1295 dreg = alloc_preg (cfg);
1296 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1297 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1298 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1301 case OP_OUTARG_VT: {
1302 if (COMPILE_LLVM (cfg))
1305 g_assert (ins->klass);
1307 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1309 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1310 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1312 mono_arch_emit_outarg_vt (cfg, ins, src);
1314 /* This might be decomposed into other vtype opcodes */
1318 case OP_OUTARG_VTRETADDR: {
1319 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1321 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1323 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1324 // FIXME: src_var->backend.is_pinvoke ?
1326 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1327 src->dreg = ins->dreg;
1332 case OP_VCALL_MEMBASE: {
1333 MonoCallInst *call = (MonoCallInst*)ins;
1336 if (COMPILE_LLVM (cfg))
1339 if (call->vret_in_reg) {
1340 MonoCallInst *call2;
1342 /* Replace the vcall with a scalar call */
1343 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1344 memcpy (call2, call, sizeof (MonoCallInst));
1345 switch (ins->opcode) {
1347 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1350 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1352 case OP_VCALL_MEMBASE:
1353 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1356 call2->inst.dreg = alloc_preg (cfg);
1357 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1359 /* Compute the vtype location */
1360 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1362 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1363 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1365 /* Save the result */
1366 if (dest_var->backend.is_pinvoke)
1367 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1369 size = mono_type_size (dest_var->inst_vtype, NULL);
1372 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1375 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1379 if (call->vret_in_reg_fp)
1380 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1382 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1388 if (call->vret_in_reg_fp) {
1389 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1392 #if SIZEOF_REGISTER == 4
1394 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1395 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1397 switch (call2->inst.opcode) {
1399 call2->inst.opcode = OP_LCALL;
1402 call2->inst.opcode = OP_LCALL_REG;
1404 case OP_CALL_MEMBASE:
1405 call2->inst.opcode = OP_LCALL_MEMBASE;
1408 call2->inst.dreg = alloc_lreg (cfg);
1409 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1410 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1412 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1416 /* This assumes the vtype is sizeof (gpointer) long */
1417 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1421 switch (ins->opcode) {
1423 ins->opcode = OP_VCALL2;
1426 ins->opcode = OP_VCALL2_REG;
1428 case OP_VCALL_MEMBASE:
1429 ins->opcode = OP_VCALL2_MEMBASE;
1440 g_assert (cfg->cbb == first_bb);
1442 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1443 /* Replace the original instruction with the new code sequence */
1445 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1446 first_bb->code = first_bb->last_ins = NULL;
1447 first_bb->in_count = first_bb->out_count = 0;
1448 cfg->cbb = first_bb;
1455 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1459 inline static MonoInst *
1460 mono_get_domainvar (MonoCompile *cfg)
1462 if (!cfg->domainvar)
1463 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1464 return cfg->domainvar;
1468 * mono_decompose_array_access_opts:
1470 * Decompose array access opcodes.
1473 mono_decompose_array_access_opts (MonoCompile *cfg)
1475 MonoBasicBlock *bb, *first_bb;
1478 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1479 * can be executed anytime. It should be run before decompose_long
1483 * Create a dummy bblock and emit code into it so we can use the normal
1484 * code generation macros.
1486 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1487 first_bb = cfg->cbb;
1489 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1491 MonoInst *prev = NULL;
1493 MonoInst *iargs [3];
1496 if (!bb->has_array_access)
1499 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1501 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1507 for (ins = bb->code; ins; ins = ins->next) {
1508 switch (ins->opcode) {
1510 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1511 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1512 MONO_ADD_INS (cfg->cbb, dest);
1514 case OP_BOUNDS_CHECK:
1515 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1516 if (COMPILE_LLVM (cfg))
1517 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1519 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1522 if (cfg->opt & MONO_OPT_SHARED) {
1523 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1524 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1525 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1526 iargs [2]->dreg = ins->sreg1;
1528 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1529 dest->dreg = ins->dreg;
1531 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1532 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1533 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1535 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1536 NEW_VTABLECONST (cfg, iargs [0], vtable);
1537 MONO_ADD_INS (cfg->cbb, iargs [0]);
1538 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1539 iargs [1]->dreg = ins->sreg1;
1542 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1544 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1545 dest->dreg = ins->dreg;
1549 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1550 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1556 g_assert (cfg->cbb == first_bb);
1558 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1559 /* Replace the original instruction with the new code sequence */
1561 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1562 first_bb->code = first_bb->last_ins = NULL;
1563 first_bb->in_count = first_bb->out_count = 0;
1564 cfg->cbb = first_bb;
1571 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1581 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1584 * mono_decompose_soft_float:
1586 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1587 * similar to long support on 32 bit platforms. 32 bit float values require special
1588 * handling when used as locals, arguments, and in calls.
1589 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1592 mono_decompose_soft_float (MonoCompile *cfg)
1594 MonoBasicBlock *bb, *first_bb;
1597 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1601 * Create a dummy bblock and emit code into it so we can use the normal
1602 * code generation macros.
1604 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1605 first_bb = cfg->cbb;
1607 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1609 MonoInst *prev = NULL;
1612 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1614 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1620 for (ins = bb->code; ins; ins = ins->next) {
1621 const char *spec = INS_INFO (ins->opcode);
1623 /* Most fp operations are handled automatically by opcode emulation */
1625 switch (ins->opcode) {
1628 d.vald = *(double*)ins->inst_p0;
1629 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1634 /* We load the r8 value */
1635 d.vald = *(float*)ins->inst_p0;
1636 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1640 ins->opcode = OP_LMOVE;
1643 ins->opcode = OP_MOVE;
1644 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1647 ins->opcode = OP_MOVE;
1648 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1651 int reg = ins->sreg1;
1653 ins->opcode = OP_SETLRET;
1655 ins->sreg1 = MONO_LVREG_LS (reg);
1656 ins->sreg2 = MONO_LVREG_MS (reg);
1659 case OP_LOADR8_MEMBASE:
1660 ins->opcode = OP_LOADI8_MEMBASE;
1662 case OP_STORER8_MEMBASE_REG:
1663 ins->opcode = OP_STOREI8_MEMBASE_REG;
1665 case OP_STORER4_MEMBASE_REG: {
1666 MonoInst *iargs [2];
1669 /* Arg 1 is the double value */
1670 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1671 iargs [0]->dreg = ins->sreg1;
1673 /* Arg 2 is the address to store to */
1674 addr_reg = mono_alloc_preg (cfg);
1675 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1676 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1680 case OP_LOADR4_MEMBASE: {
1681 MonoInst *iargs [1];
1685 addr_reg = mono_alloc_preg (cfg);
1686 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1687 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1688 conv->dreg = ins->dreg;
1693 case OP_FCALL_MEMBASE: {
1694 MonoCallInst *call = (MonoCallInst*)ins;
1695 if (call->signature->ret->type == MONO_TYPE_R4) {
1696 MonoCallInst *call2;
1697 MonoInst *iargs [1];
1701 /* Convert the call into a call returning an int */
1702 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1703 memcpy (call2, call, sizeof (MonoCallInst));
1704 switch (ins->opcode) {
1706 call2->inst.opcode = OP_CALL;
1709 call2->inst.opcode = OP_CALL_REG;
1711 case OP_FCALL_MEMBASE:
1712 call2->inst.opcode = OP_CALL_MEMBASE;
1715 g_assert_not_reached ();
1717 call2->inst.dreg = mono_alloc_ireg (cfg);
1718 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1720 /* Remap OUTARG_VT instructions referencing this call */
1721 for (l = call->outarg_vts; l; l = l->next)
1722 ((MonoInst*)(l->data))->inst_p0 = call2;
1724 /* FIXME: Optimize this */
1726 /* Emit an r4->r8 conversion */
1727 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1728 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1729 conv->dreg = ins->dreg;
1731 /* The call sequence might include fp ins */
1734 switch (ins->opcode) {
1736 ins->opcode = OP_LCALL;
1739 ins->opcode = OP_LCALL_REG;
1741 case OP_FCALL_MEMBASE:
1742 ins->opcode = OP_LCALL_MEMBASE;
1745 g_assert_not_reached ();
1751 MonoJitICallInfo *info;
1752 MonoInst *iargs [2];
1753 MonoInst *call, *cmp, *br;
1755 /* Convert fcompare+fbcc to icall+icompare+beq */
1758 /* The branch might be optimized away */
1763 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1765 /* The branch might be optimized away */
1770 /* Create dummy MonoInst's for the arguments */
1771 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1772 iargs [0]->dreg = ins->sreg1;
1773 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1774 iargs [1]->dreg = ins->sreg2;
1776 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1778 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1779 cmp->sreg1 = call->dreg;
1781 MONO_ADD_INS (cfg->cbb, cmp);
1783 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1784 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1785 br->inst_true_bb = ins->next->inst_true_bb;
1786 br->inst_false_bb = ins->next->inst_false_bb;
1787 MONO_ADD_INS (cfg->cbb, br);
1789 /* The call sequence might include fp ins */
1792 /* Skip fbcc or fccc */
1793 NULLIFY_INS (ins->next);
1801 MonoJitICallInfo *info;
1802 MonoInst *iargs [2];
1805 /* Convert fccc to icall+icompare+iceq */
1807 info = mono_find_jit_opcode_emulation (ins->opcode);
1810 /* Create dummy MonoInst's for the arguments */
1811 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1812 iargs [0]->dreg = ins->sreg1;
1813 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1814 iargs [1]->dreg = ins->sreg2;
1816 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1818 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1819 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1821 /* The call sequence might include fp ins */
1826 MonoInst *iargs [2];
1827 MonoInst *call, *cmp;
1829 /* Convert to icall+icompare+cond_exc+move */
1831 /* Create dummy MonoInst's for the arguments */
1832 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1833 iargs [0]->dreg = ins->sreg1;
1835 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1837 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1838 cmp->sreg1 = call->dreg;
1840 MONO_ADD_INS (cfg->cbb, cmp);
1842 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1844 /* Do the assignment if the value is finite */
1845 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1851 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1852 mono_print_ins (ins);
1853 g_assert_not_reached ();
1858 g_assert (cfg->cbb == first_bb);
1860 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1861 /* Replace the original instruction with the new code sequence */
1863 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1864 first_bb->code = first_bb->last_ins = NULL;
1865 first_bb->in_count = first_bb->out_count = 0;
1866 cfg->cbb = first_bb;
1873 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1876 mono_decompose_long_opts (cfg);
1882 mono_local_emulate_ops (MonoCompile *cfg)
1885 gboolean inlined_wrapper = FALSE;
1887 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1890 MONO_BB_FOR_EACH_INS (bb, ins) {
1891 int op_noimm = mono_op_imm_to_op (ins->opcode);
1892 MonoJitICallInfo *info;
1895 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1896 * to check whether its non-imm counterpart is emulated and, if so,
1897 * decompose it back to its non-imm counterpart.
1900 info = mono_find_jit_opcode_emulation (op_noimm);
1902 info = mono_find_jit_opcode_emulation (ins->opcode);
1907 MonoBasicBlock *first_bb;
1909 /* Create dummy MonoInst's for the arguments */
1910 g_assert (!info->sig->hasthis);
1911 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1914 mono_decompose_op_imm (cfg, bb, ins);
1916 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1917 if (info->sig->param_count > 0) {
1918 int sregs [MONO_MAX_SRC_REGS];
1920 num_sregs = mono_inst_get_src_registers (ins, sregs);
1921 g_assert (num_sregs == info->sig->param_count);
1922 for (i = 0; i < num_sregs; ++i) {
1923 MONO_INST_NEW (cfg, args [i], OP_ARG);
1924 args [i]->dreg = sregs [i];
1928 /* We emit the call on a separate dummy basic block */
1929 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1930 first_bb = cfg->cbb;
1932 call = mono_emit_jit_icall_by_info (cfg, info, args);
1933 call->dreg = ins->dreg;
1935 /* Replace ins with the emitted code and do the necessary bb linking */
1936 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1937 MonoInst *saved_prev = ins->prev;
1939 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1940 first_bb->code = first_bb->last_ins = NULL;
1941 first_bb->in_count = first_bb->out_count = 0;
1942 cfg->cbb = first_bb;
1944 /* ins is hanging, continue scanning the emitted code */
1947 g_error ("Failed to emit emulation code");
1949 inlined_wrapper = TRUE;
1955 * Avoid rerunning these passes by emitting directly the exception checkpoint
1956 * at IR level, instead of inlining the icall wrapper. FIXME
1958 if (inlined_wrapper) {
1959 if (!COMPILE_LLVM (cfg))
1960 mono_decompose_long_opts (cfg);
1961 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1962 mono_local_cprop (cfg);
1966 #endif /* DISABLE_JIT */