3 * Functions to decompose complex IR instructions into simpler ones.
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2002 Ximian, Inc.
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include "jit-icalls.h"
17 #include <mono/metadata/gc-internals.h>
18 #include <mono/metadata/abi-details.h>
19 #include <mono/utils/mono-compiler.h>
24 * Decompose complex long opcodes on 64 bit machines.
25 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
28 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
30 MonoInst *repl = NULL;
34 switch (ins->opcode) {
36 ins->opcode = OP_SEXT_I4;
40 if (SIZEOF_VOID_P == 4)
41 ins->opcode = OP_LMOVE;
43 ins->opcode = OP_MOVE;
46 if (SIZEOF_VOID_P == 4)
48 ins->opcode = OP_SEXT_I4;
50 ins->opcode = OP_MOVE;
53 if (SIZEOF_VOID_P == 4) {
55 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
58 ins->opcode = OP_MOVE;
62 ins->opcode = OP_SEXT_I4;
65 ins->opcode = OP_ZEXT_I4;
68 /* Clean out the upper word */
69 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
75 if (COMPILE_LLVM (cfg))
77 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
81 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
82 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
86 case OP_LADD_OVF_UN: {
89 if (COMPILE_LLVM (cfg))
91 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
95 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
96 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
100 #ifndef __mono_ppc64__
104 if (COMPILE_LLVM (cfg))
106 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
110 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
111 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
115 case OP_LSUB_OVF_UN: {
118 if (COMPILE_LLVM (cfg))
120 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
124 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
125 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
131 case OP_ICONV_TO_OVF_I8:
132 case OP_ICONV_TO_OVF_I:
133 ins->opcode = OP_SEXT_I4;
135 case OP_ICONV_TO_OVF_U8:
136 case OP_ICONV_TO_OVF_U:
137 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
138 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
139 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
142 case OP_ICONV_TO_OVF_I8_UN:
143 case OP_ICONV_TO_OVF_U8_UN:
144 case OP_ICONV_TO_OVF_I_UN:
145 case OP_ICONV_TO_OVF_U_UN:
146 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
147 /* Clean out the upper word */
148 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
151 case OP_LCONV_TO_OVF_I1:
152 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
153 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
154 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
155 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
156 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
159 case OP_LCONV_TO_OVF_I1_UN:
160 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
161 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
162 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
165 case OP_LCONV_TO_OVF_U1:
166 /* probe value to be within 0 to 255 */
167 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
168 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
169 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
172 case OP_LCONV_TO_OVF_U1_UN:
173 /* probe value to be within 0 to 255 */
174 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
175 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
176 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
179 case OP_LCONV_TO_OVF_I2:
180 /* Probe value to be within -32768 and 32767 */
181 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
182 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
183 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
184 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
185 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
188 case OP_LCONV_TO_OVF_I2_UN:
189 /* Probe value to be within 0 and 32767 */
190 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
191 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
192 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
195 case OP_LCONV_TO_OVF_U2:
196 /* Probe value to be within 0 and 65535 */
197 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
198 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
199 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
202 case OP_LCONV_TO_OVF_U2_UN:
203 /* Probe value to be within 0 and 65535 */
204 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
205 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
206 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
209 case OP_LCONV_TO_OVF_I4:
210 #if SIZEOF_VOID_P == 4
211 case OP_LCONV_TO_OVF_I:
213 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
214 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
215 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
216 #if SIZEOF_REGISTER == 8
217 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
219 g_assert (COMPILE_LLVM (cfg));
220 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
222 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
223 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
226 case OP_LCONV_TO_OVF_I4_UN:
227 #if SIZEOF_VOID_P == 4
228 case OP_LCONV_TO_OVF_I_UN:
230 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
231 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
232 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
235 case OP_LCONV_TO_OVF_U4:
236 #if SIZEOF_VOID_P == 4
237 case OP_LCONV_TO_OVF_U:
239 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
240 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
241 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
242 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
243 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
246 case OP_LCONV_TO_OVF_U4_UN:
247 #if SIZEOF_VOID_P == 4
248 case OP_LCONV_TO_OVF_U_UN:
250 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
251 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
252 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
255 #if SIZEOF_VOID_P == 8
256 case OP_LCONV_TO_OVF_I:
257 case OP_LCONV_TO_OVF_U_UN:
259 case OP_LCONV_TO_OVF_U8_UN:
260 case OP_LCONV_TO_OVF_I8:
261 ins->opcode = OP_MOVE;
263 #if SIZEOF_VOID_P == 8
264 case OP_LCONV_TO_OVF_I_UN:
266 case OP_LCONV_TO_OVF_I8_UN:
267 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
268 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
269 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
272 case OP_LCONV_TO_OVF_U8:
273 #if SIZEOF_VOID_P == 8
274 case OP_LCONV_TO_OVF_U:
276 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
277 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
278 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
290 * mono_decompose_opcode:
292 * Decompose complex opcodes into ones closer to opcodes supported by
293 * the given architecture.
294 * Returns a MonoInst which represents the result of the decomposition, and can
295 * be pushed on the IL stack. This is needed because the original instruction is
297 * Sets the cfg exception if an opcode is not supported.
300 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
302 MonoInst *repl = NULL;
303 int type = ins->type;
304 int dreg = ins->dreg;
305 gboolean emulate = FALSE;
307 /* FIXME: Instead of = NOP, don't emit the original ins at all */
308 mono_arch_decompose_opts (cfg, ins);
311 * The code below assumes that we are called immediately after emitting
312 * ins. This means we can emit code using the normal code generation
315 switch (ins->opcode) {
316 /* this doesn't make sense on ppc and other architectures */
317 #if !defined(MONO_ARCH_NO_IOV_CHECK)
319 if (COMPILE_LLVM (cfg))
321 ins->opcode = OP_IADDCC;
322 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
325 if (COMPILE_LLVM (cfg))
327 ins->opcode = OP_IADDCC;
328 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
331 if (COMPILE_LLVM (cfg))
333 ins->opcode = OP_ISUBCC;
334 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
337 if (COMPILE_LLVM (cfg))
339 ins->opcode = OP_ISUBCC;
340 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
343 case OP_ICONV_TO_OVF_I1:
344 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
345 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
346 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
347 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
348 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
351 case OP_ICONV_TO_OVF_I1_UN:
352 /* probe values between 0 to 127 */
353 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
354 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
355 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
358 case OP_ICONV_TO_OVF_U1:
359 case OP_ICONV_TO_OVF_U1_UN:
360 /* probe value to be within 0 to 255 */
361 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
362 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
363 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
366 case OP_ICONV_TO_OVF_I2:
367 /* Probe value to be within -32768 and 32767 */
368 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
369 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
370 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
371 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
372 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
375 case OP_ICONV_TO_OVF_I2_UN:
376 /* Convert uint value into short, value within 0 and 32767 */
377 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
378 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
379 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
382 case OP_ICONV_TO_OVF_U2:
383 case OP_ICONV_TO_OVF_U2_UN:
384 /* Probe value to be within 0 and 65535 */
385 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
386 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
387 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
390 case OP_ICONV_TO_OVF_U4:
391 case OP_ICONV_TO_OVF_I4_UN:
392 #if SIZEOF_VOID_P == 4
393 case OP_ICONV_TO_OVF_U:
394 case OP_ICONV_TO_OVF_I_UN:
396 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
397 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
398 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
403 case OP_ICONV_TO_OVF_I4:
404 case OP_ICONV_TO_OVF_U4_UN:
405 #if SIZEOF_VOID_P == 4
406 case OP_ICONV_TO_OVF_I:
407 case OP_ICONV_TO_OVF_U_UN:
409 ins->opcode = OP_MOVE;
412 #if SIZEOF_VOID_P == 8
413 ins->opcode = OP_SEXT_I4;
415 ins->opcode = OP_MOVE;
419 #if SIZEOF_VOID_P == 8
420 ins->opcode = OP_ZEXT_I4;
422 ins->opcode = OP_MOVE;
427 ins->opcode = OP_FMOVE;
430 case OP_FCONV_TO_OVF_I1_UN:
431 case OP_FCONV_TO_OVF_I2_UN:
432 case OP_FCONV_TO_OVF_I4_UN:
433 case OP_FCONV_TO_OVF_I8_UN:
434 case OP_FCONV_TO_OVF_U1_UN:
435 case OP_FCONV_TO_OVF_U2_UN:
436 case OP_FCONV_TO_OVF_U4_UN:
437 case OP_FCONV_TO_OVF_U8_UN:
438 case OP_FCONV_TO_OVF_I_UN:
439 case OP_FCONV_TO_OVF_U_UN:
440 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
447 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
450 if (cfg->backend->need_div_check) {
451 int reg1 = alloc_ireg (cfg);
452 int reg2 = alloc_ireg (cfg);
454 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
455 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
456 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
457 /* b == -1 && a == 0x80000000 */
458 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
459 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
460 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
461 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
462 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
463 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
464 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
467 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
472 #if SIZEOF_VOID_P == 8
477 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
480 if (cfg->backend->need_div_check) {
481 int reg1 = alloc_ireg (cfg);
482 int reg2 = alloc_ireg (cfg);
483 int reg3 = alloc_ireg (cfg);
485 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
486 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
487 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
488 /* b == -1 && a == 0x80000000 */
489 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
490 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
491 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
492 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
493 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
494 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
495 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
496 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
497 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
500 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);
933 #ifdef TARGET_POWERPC
934 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
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 /* just move the upper half to the lower and zero the high word */
944 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
945 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
950 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
954 switch (next->opcode) {
959 /* Branchless version based on gcc code */
960 d1 = alloc_ireg (cfg);
961 d2 = alloc_ireg (cfg);
962 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
963 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
964 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
965 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
966 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
978 /* Convert into three comparisons + branches */
979 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
980 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
981 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
982 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
983 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
984 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
990 /* Branchless version based on gcc code */
991 d1 = alloc_ireg (cfg);
992 d2 = alloc_ireg (cfg);
993 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
994 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
995 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
997 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
998 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1006 MonoBasicBlock *set_to_0, *set_to_1;
1008 NEW_BBLOCK (cfg, set_to_0);
1009 NEW_BBLOCK (cfg, set_to_1);
1011 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1012 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1013 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1014 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1015 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1016 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1017 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1018 MONO_START_BB (cfg, set_to_1);
1019 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1020 MONO_START_BB (cfg, set_to_0);
1025 g_assert_not_reached ();
1030 /* Not yet used, since lcompare is decomposed before local cprop */
1031 case OP_LCOMPARE_IMM: {
1032 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1033 guint32 low_imm = tree->inst_ls_word;
1034 guint32 high_imm = tree->inst_ms_word;
1035 int low_reg = MONO_LVREG_LS (tree->sreg1);
1036 int high_reg = MONO_LVREG_MS (tree->sreg1);
1040 switch (next->opcode) {
1045 /* Branchless version based on gcc code */
1046 d1 = alloc_ireg (cfg);
1047 d2 = alloc_ireg (cfg);
1048 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1049 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1050 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1051 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1052 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1065 /* Convert into three comparisons + branches */
1066 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1067 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1068 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1069 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1070 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1071 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1077 /* Branchless version based on gcc code */
1078 d1 = alloc_ireg (cfg);
1079 d2 = alloc_ireg (cfg);
1080 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1081 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1082 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1084 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1085 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1093 MonoBasicBlock *set_to_0, *set_to_1;
1095 NEW_BBLOCK (cfg, set_to_0);
1096 NEW_BBLOCK (cfg, set_to_1);
1098 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1099 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1100 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1101 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1102 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1103 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1104 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1105 MONO_START_BB (cfg, set_to_1);
1106 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1107 MONO_START_BB (cfg, set_to_0);
1112 g_assert_not_reached ();
1121 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1124 /* Replace the original instruction with the new code sequence */
1126 /* Ignore the new value of prev */
1128 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1130 /* Process the newly added ops again since they can be long ops too */
1132 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1134 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1136 first_bb->code = first_bb->last_ins = NULL;
1137 first_bb->in_count = first_bb->out_count = 0;
1138 cfg->cbb = first_bb;
1142 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1149 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1150 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1155 * mono_decompose_vtype_opts:
1157 * Decompose valuetype opcodes.
1160 mono_decompose_vtype_opts (MonoCompile *cfg)
1162 MonoBasicBlock *bb, *first_bb;
1165 * Using OP_V opcodes and decomposing them later have two main benefits:
1166 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1168 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1169 * enabling optimizations to work on vtypes too.
1170 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1171 * can be executed anytime. It should be executed as late as possible so vtype
1172 * opcodes can be optimized by the other passes.
1173 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1174 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1176 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1177 * when OP_VMOVE opcodes are decomposed.
1181 * Vregs have no associated type information, so we store the type of the vregs
1186 * Create a dummy bblock and emit code into it so we can use the normal
1187 * code generation macros.
1189 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1190 first_bb = cfg->cbb;
1192 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1194 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1196 MonoInst *prev = NULL;
1197 MonoInst *src_var, *dest_var, *src, *dest;
1201 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1203 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1209 for (ins = bb->code; ins; ins = ins->next) {
1210 switch (ins->opcode) {
1212 g_assert (ins->klass);
1213 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1215 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1216 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1219 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1222 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1225 if (src_var->backend.is_pinvoke)
1226 dest_var->backend.is_pinvoke = 1;
1228 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1229 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1230 mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0);
1235 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1238 g_assert (ins->klass);
1240 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1241 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1243 if (cfg->compute_gc_maps) {
1247 * Tell the GC map code that the vtype is considered live after
1248 * the initialization.
1250 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1251 tmp->inst_c1 = ins->dreg;
1252 MONO_ADD_INS (cfg->cbb, tmp);
1255 case OP_DUMMY_VZERO:
1256 if (COMPILE_LLVM (cfg))
1261 case OP_STOREV_MEMBASE: {
1262 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1264 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !cfg->gen_write_barriers)
1268 g_assert (ins->klass);
1269 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1272 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1274 dreg = alloc_preg (cfg);
1275 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1276 mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0);
1279 case OP_LOADV_MEMBASE: {
1280 g_assert (ins->klass);
1281 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1284 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1288 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1290 dreg = alloc_preg (cfg);
1291 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1292 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1293 mini_emit_memory_copy (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke, 0);
1296 case OP_OUTARG_VT: {
1297 if (COMPILE_LLVM (cfg))
1300 g_assert (ins->klass);
1302 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1304 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1305 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1307 mono_arch_emit_outarg_vt (cfg, ins, src);
1309 /* This might be decomposed into other vtype opcodes */
1313 case OP_OUTARG_VTRETADDR: {
1314 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1316 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1318 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1319 // FIXME: src_var->backend.is_pinvoke ?
1321 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1322 src->dreg = ins->dreg;
1327 case OP_VCALL_MEMBASE: {
1328 MonoCallInst *call = (MonoCallInst*)ins;
1331 if (COMPILE_LLVM (cfg))
1334 if (call->vret_in_reg) {
1335 MonoCallInst *call2;
1337 /* Replace the vcall with a scalar call */
1338 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1339 memcpy (call2, call, sizeof (MonoCallInst));
1340 switch (ins->opcode) {
1342 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1345 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1347 case OP_VCALL_MEMBASE:
1348 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1351 call2->inst.dreg = alloc_preg (cfg);
1352 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1354 /* Compute the vtype location */
1355 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1357 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1358 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1360 /* Save the result */
1361 if (dest_var->backend.is_pinvoke)
1362 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1364 size = mono_type_size (dest_var->inst_vtype, NULL);
1367 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1370 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1374 if (call->vret_in_reg_fp)
1375 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1377 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1383 if (call->vret_in_reg_fp) {
1384 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1387 #if SIZEOF_REGISTER == 4
1389 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1390 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1392 switch (call2->inst.opcode) {
1394 call2->inst.opcode = OP_LCALL;
1397 call2->inst.opcode = OP_LCALL_REG;
1399 case OP_CALL_MEMBASE:
1400 call2->inst.opcode = OP_LCALL_MEMBASE;
1403 call2->inst.dreg = alloc_lreg (cfg);
1404 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1405 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1407 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1411 /* This assumes the vtype is sizeof (gpointer) long */
1412 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1416 switch (ins->opcode) {
1418 ins->opcode = OP_VCALL2;
1421 ins->opcode = OP_VCALL2_REG;
1423 case OP_VCALL_MEMBASE:
1424 ins->opcode = OP_VCALL2_MEMBASE;
1435 g_assert (cfg->cbb == first_bb);
1437 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1438 /* Replace the original instruction with the new code sequence */
1440 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1441 first_bb->code = first_bb->last_ins = NULL;
1442 first_bb->in_count = first_bb->out_count = 0;
1443 cfg->cbb = first_bb;
1450 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1454 inline static MonoInst *
1455 mono_get_domainvar (MonoCompile *cfg)
1457 if (!cfg->domainvar)
1458 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1459 return cfg->domainvar;
1463 * mono_decompose_array_access_opts:
1465 * Decompose array access opcodes.
1468 mono_decompose_array_access_opts (MonoCompile *cfg)
1470 MonoBasicBlock *bb, *first_bb;
1473 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1474 * can be executed anytime. It should be run before decompose_long
1478 * Create a dummy bblock and emit code into it so we can use the normal
1479 * code generation macros.
1481 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1482 first_bb = cfg->cbb;
1484 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1486 MonoInst *prev = NULL;
1488 MonoInst *iargs [3];
1491 if (!bb->has_array_access)
1494 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1496 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1502 for (ins = bb->code; ins; ins = ins->next) {
1503 switch (ins->opcode) {
1505 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1506 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1507 MONO_ADD_INS (cfg->cbb, dest);
1509 case OP_BOUNDS_CHECK:
1510 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1511 if (COMPILE_LLVM (cfg)) {
1512 int index2_reg = alloc_preg (cfg);
1513 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, ins->sreg2);
1514 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, index2_reg, ins->flags & MONO_INST_FAULT);
1516 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, ves_icall_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 * These opcodes don't have logical equivalence to the emulating native
1894 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1896 if (MONO_HAS_CUSTOM_EMULATION (ins))
1900 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1901 * to check whether its non-imm counterpart is emulated and, if so,
1902 * decompose it back to its non-imm counterpart.
1905 info = mono_find_jit_opcode_emulation (op_noimm);
1907 info = mono_find_jit_opcode_emulation (ins->opcode);
1912 MonoBasicBlock *first_bb;
1914 /* Create dummy MonoInst's for the arguments */
1915 g_assert (!info->sig->hasthis);
1916 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1919 mono_decompose_op_imm (cfg, bb, ins);
1921 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1922 if (info->sig->param_count > 0) {
1923 int sregs [MONO_MAX_SRC_REGS];
1925 num_sregs = mono_inst_get_src_registers (ins, sregs);
1926 g_assert (num_sregs == info->sig->param_count);
1927 for (i = 0; i < num_sregs; ++i) {
1928 MONO_INST_NEW (cfg, args [i], OP_ARG);
1929 args [i]->dreg = sregs [i];
1933 /* We emit the call on a separate dummy basic block */
1934 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1935 first_bb = cfg->cbb;
1937 call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
1938 call->dreg = ins->dreg;
1940 /* Replace ins with the emitted code and do the necessary bb linking */
1941 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1942 MonoInst *saved_prev = ins->prev;
1944 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1945 first_bb->code = first_bb->last_ins = NULL;
1946 first_bb->in_count = first_bb->out_count = 0;
1947 cfg->cbb = first_bb;
1949 /* ins is hanging, continue scanning the emitted code */
1952 g_error ("Failed to emit emulation code");
1954 inlined_wrapper = TRUE;
1960 * Avoid rerunning these passes by emitting directly the exception checkpoint
1961 * at IR level, instead of inlining the icall wrapper. FIXME
1963 if (inlined_wrapper) {
1964 if (!COMPILE_LLVM (cfg))
1965 mono_decompose_long_opts (cfg);
1966 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1967 mono_local_cprop (cfg);
1971 #else /* !DISABLE_JIT */
1973 MONO_EMPTY_SOURCE_FILE (decompose);
1975 #endif /* !DISABLE_JIT */