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-internal.h>
19 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
20 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
21 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
22 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
25 * Decompose complex long opcodes on 64 bit machines.
26 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
29 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
31 MonoInst *repl = NULL;
35 switch (ins->opcode) {
37 ins->opcode = OP_SEXT_I4;
41 if (SIZEOF_VOID_P == 4)
42 ins->opcode = OP_LMOVE;
44 ins->opcode = OP_MOVE;
47 if (SIZEOF_VOID_P == 4)
49 ins->opcode = OP_SEXT_I4;
51 ins->opcode = OP_MOVE;
54 if (SIZEOF_VOID_P == 4) {
56 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
59 ins->opcode = OP_MOVE;
63 ins->opcode = OP_SEXT_I4;
66 ins->opcode = OP_ZEXT_I4;
69 /* Clean out the upper word */
70 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
74 if (COMPILE_LLVM (cfg))
78 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
83 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
85 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
89 if (COMPILE_LLVM (cfg))
93 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
98 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
100 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
103 #ifndef __mono_ppc64__
105 if (COMPILE_LLVM (cfg))
109 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
114 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
116 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
120 if (COMPILE_LLVM (cfg))
124 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
129 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
131 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
136 case OP_ICONV_TO_OVF_I8:
137 case OP_ICONV_TO_OVF_I:
138 ins->opcode = OP_SEXT_I4;
140 case OP_ICONV_TO_OVF_U8:
141 case OP_ICONV_TO_OVF_U:
142 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
143 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
144 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
147 case OP_ICONV_TO_OVF_I8_UN:
148 case OP_ICONV_TO_OVF_U8_UN:
149 case OP_ICONV_TO_OVF_I_UN:
150 case OP_ICONV_TO_OVF_U_UN:
151 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
152 /* Clean out the upper word */
153 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
156 case OP_LCONV_TO_OVF_I1:
157 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
158 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
159 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
160 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
161 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
164 case OP_LCONV_TO_OVF_I1_UN:
165 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
166 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
167 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
170 case OP_LCONV_TO_OVF_U1:
171 /* probe value to be within 0 to 255 */
172 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
173 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
174 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
177 case OP_LCONV_TO_OVF_U1_UN:
178 /* probe value to be within 0 to 255 */
179 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
180 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
181 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
184 case OP_LCONV_TO_OVF_I2:
185 /* Probe value to be within -32768 and 32767 */
186 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
187 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
188 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
189 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
190 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
193 case OP_LCONV_TO_OVF_I2_UN:
194 /* Probe value to be within 0 and 32767 */
195 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
196 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
197 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
200 case OP_LCONV_TO_OVF_U2:
201 /* Probe value to be within 0 and 65535 */
202 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
203 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
204 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
207 case OP_LCONV_TO_OVF_U2_UN:
208 /* Probe value to be within 0 and 65535 */
209 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
210 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
211 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
214 case OP_LCONV_TO_OVF_I4:
215 #if SIZEOF_VOID_P == 4
216 case OP_LCONV_TO_OVF_I:
218 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
219 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
220 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
221 #if SIZEOF_REGISTER == 8
222 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
224 g_assert (COMPILE_LLVM (cfg));
225 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
227 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
228 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
231 case OP_LCONV_TO_OVF_I4_UN:
232 #if SIZEOF_VOID_P == 4
233 case OP_LCONV_TO_OVF_I_UN:
235 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
236 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
237 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
240 case OP_LCONV_TO_OVF_U4:
241 #if SIZEOF_VOID_P == 4
242 case OP_LCONV_TO_OVF_U:
244 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
245 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
246 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
247 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
248 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
251 case OP_LCONV_TO_OVF_U4_UN:
252 #if SIZEOF_VOID_P == 4
253 case OP_LCONV_TO_OVF_U_UN:
255 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
256 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
257 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
260 #if SIZEOF_VOID_P == 8
261 case OP_LCONV_TO_OVF_I:
262 case OP_LCONV_TO_OVF_U_UN:
264 case OP_LCONV_TO_OVF_U8_UN:
265 case OP_LCONV_TO_OVF_I8:
266 ins->opcode = OP_MOVE;
268 #if SIZEOF_VOID_P == 8
269 case OP_LCONV_TO_OVF_I_UN:
271 case OP_LCONV_TO_OVF_I8_UN:
272 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
273 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
274 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
277 case OP_LCONV_TO_OVF_U8:
278 #if SIZEOF_VOID_P == 8
279 case OP_LCONV_TO_OVF_U:
281 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
282 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
283 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
295 * mono_decompose_opcode:
297 * Decompose complex opcodes into ones closer to opcodes supported by
298 * the given architecture.
299 * Returns a MonoInst which represents the result of the decomposition, and can
300 * be pushed on the IL stack. This is needed because the original instruction is
302 * Sets the cfg exception if an opcode is not supported.
305 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
307 MonoInst *repl = NULL;
308 int type = ins->type;
309 int dreg = ins->dreg;
310 gboolean emulate = FALSE;
312 /* FIXME: Instead of = NOP, don't emit the original ins at all */
314 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
315 mono_arch_decompose_opts (cfg, ins);
319 * The code below assumes that we are called immediately after emitting
320 * ins. This means we can emit code using the normal code generation
323 switch (ins->opcode) {
324 /* this doesn't make sense on ppc and other architectures */
325 #if !defined(MONO_ARCH_NO_IOV_CHECK)
327 if (COMPILE_LLVM (cfg))
329 ins->opcode = OP_IADDCC;
330 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
333 if (COMPILE_LLVM (cfg))
335 ins->opcode = OP_IADDCC;
336 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
339 if (COMPILE_LLVM (cfg))
341 ins->opcode = OP_ISUBCC;
342 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
345 if (COMPILE_LLVM (cfg))
347 ins->opcode = OP_ISUBCC;
348 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
351 case OP_ICONV_TO_OVF_I1:
352 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
353 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
354 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
355 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
356 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
359 case OP_ICONV_TO_OVF_I1_UN:
360 /* probe values between 0 to 127 */
361 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
362 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
363 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
366 case OP_ICONV_TO_OVF_U1:
367 case OP_ICONV_TO_OVF_U1_UN:
368 /* probe value to be within 0 to 255 */
369 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
370 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
371 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
374 case OP_ICONV_TO_OVF_I2:
375 /* Probe value to be within -32768 and 32767 */
376 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
377 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
378 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
379 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
380 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
383 case OP_ICONV_TO_OVF_I2_UN:
384 /* Convert uint value into short, value within 0 and 32767 */
385 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
386 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
387 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
390 case OP_ICONV_TO_OVF_U2:
391 case OP_ICONV_TO_OVF_U2_UN:
392 /* Probe value to be within 0 and 65535 */
393 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
394 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
395 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
398 case OP_ICONV_TO_OVF_U4:
399 case OP_ICONV_TO_OVF_I4_UN:
400 #if SIZEOF_VOID_P == 4
401 case OP_ICONV_TO_OVF_U:
402 case OP_ICONV_TO_OVF_I_UN:
404 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
405 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
406 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
411 case OP_ICONV_TO_OVF_I4:
412 case OP_ICONV_TO_OVF_U4_UN:
413 #if SIZEOF_VOID_P == 4
414 case OP_ICONV_TO_OVF_I:
415 case OP_ICONV_TO_OVF_U_UN:
417 ins->opcode = OP_MOVE;
420 #if SIZEOF_VOID_P == 8
421 ins->opcode = OP_SEXT_I4;
423 ins->opcode = OP_MOVE;
427 #if SIZEOF_VOID_P == 8
428 ins->opcode = OP_ZEXT_I4;
430 ins->opcode = OP_MOVE;
435 ins->opcode = OP_FMOVE;
438 case OP_FCONV_TO_OVF_I1_UN:
439 case OP_FCONV_TO_OVF_I2_UN:
440 case OP_FCONV_TO_OVF_I4_UN:
441 case OP_FCONV_TO_OVF_I8_UN:
442 case OP_FCONV_TO_OVF_U1_UN:
443 case OP_FCONV_TO_OVF_U2_UN:
444 case OP_FCONV_TO_OVF_U4_UN:
445 case OP_FCONV_TO_OVF_U8_UN:
446 case OP_FCONV_TO_OVF_I_UN:
447 case OP_FCONV_TO_OVF_U_UN:
448 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
449 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
452 #if defined(MONO_ARCH_EMULATE_DIV) && defined(MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION)
457 if (!mono_arch_opcode_needs_emulation (cfg, ins->opcode)) {
458 #ifdef MONO_ARCH_NEED_DIV_CHECK
459 int reg1 = alloc_ireg (cfg);
460 int reg2 = alloc_ireg (cfg);
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
463 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
464 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
465 /* b == -1 && a == 0x80000000 */
466 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
467 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
468 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
469 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
470 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
471 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
472 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
475 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
476 ins->opcode = OP_NOP;
489 MonoJitICallInfo *info = NULL;
491 #if SIZEOF_REGISTER == 8
492 if (decompose_long_opcode (cfg, ins, &repl))
495 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
500 info = mono_find_jit_opcode_emulation (ins->opcode);
505 /* Create dummy MonoInst's for the arguments */
506 g_assert (!info->sig->hasthis);
507 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
509 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
510 if (info->sig->param_count > 0) {
511 int sregs [MONO_MAX_SRC_REGS];
513 num_sregs = mono_inst_get_src_registers (ins, sregs);
514 g_assert (num_sregs == info->sig->param_count);
515 for (i = 0; i < num_sregs; ++i) {
516 MONO_INST_NEW (cfg, args [i], OP_ARG);
517 args [i]->dreg = sregs [i];
521 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
522 call->dreg = ins->dreg;
528 if (ins->opcode == OP_NOP) {
533 /* Use the last emitted instruction */
534 ins = cfg->cbb->last_ins;
537 g_assert (ins->dreg == dreg);
545 #if SIZEOF_REGISTER == 4
546 static int lbr_decomp [][2] = {
548 {OP_IBGT, OP_IBGE_UN}, /* BGE */
549 {OP_IBGT, OP_IBGT_UN}, /* BGT */
550 {OP_IBLT, OP_IBLE_UN}, /* BLE */
551 {OP_IBLT, OP_IBLT_UN}, /* BLT */
553 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
554 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
555 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
556 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
559 static int lcset_decomp [][2] = {
561 {OP_IBLT, OP_IBLE_UN}, /* CGT */
562 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
563 {OP_IBGT, OP_IBGE_UN}, /* CLT */
564 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
569 * mono_decompose_long_opts:
571 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
574 mono_decompose_long_opts (MonoCompile *cfg)
576 #if SIZEOF_REGISTER == 4
577 MonoBasicBlock *bb, *first_bb;
580 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
581 * needs to be able to handle long vregs.
584 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
587 * Create a dummy bblock and emit code into it so we can use the normal
588 * code generation macros.
590 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
593 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
594 MonoInst *tree = bb->code;
595 MonoInst *prev = NULL;
598 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
602 cfg->cbb->code = cfg->cbb->last_ins = NULL;
606 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
607 mono_arch_decompose_long_opts (cfg, tree);
610 switch (tree->opcode) {
612 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
613 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
615 case OP_DUMMY_I8CONST:
616 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 1, OP_DUMMY_ICONST);
617 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 2, OP_DUMMY_ICONST);
622 case OP_LCONV_TO_OVF_U8_UN:
623 case OP_LCONV_TO_OVF_I8:
624 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
625 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
627 case OP_STOREI8_MEMBASE_REG:
628 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
629 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
631 case OP_LOADI8_MEMBASE:
632 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
633 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
636 case OP_ICONV_TO_I8: {
637 guint32 tmpreg = alloc_ireg (cfg);
641 * tmp = low > -1 ? 1: 0;
642 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
644 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
645 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
646 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
647 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
651 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
652 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
654 case OP_ICONV_TO_OVF_I8:
655 /* a signed 32 bit num always fits in a signed 64 bit one */
656 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
657 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
659 case OP_ICONV_TO_OVF_U8:
660 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
661 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
662 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
663 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
665 case OP_ICONV_TO_OVF_I8_UN:
666 case OP_ICONV_TO_OVF_U8_UN:
667 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
668 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
669 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
672 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
675 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
678 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
681 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
687 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
690 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
693 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
695 case OP_LCONV_TO_R_UN:
696 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
698 case OP_LCONV_TO_OVF_I1: {
699 MonoBasicBlock *is_negative, *end_label;
701 NEW_BBLOCK (cfg, is_negative);
702 NEW_BBLOCK (cfg, end_label);
704 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
705 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
706 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
707 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
709 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
710 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
713 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
714 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
715 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
718 MONO_START_BB (cfg, is_negative);
719 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
720 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
722 MONO_START_BB (cfg, end_label);
724 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
727 case OP_LCONV_TO_OVF_I1_UN:
728 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
729 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
731 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
732 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
733 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
734 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
735 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
737 case OP_LCONV_TO_OVF_U1:
738 case OP_LCONV_TO_OVF_U1_UN:
739 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
740 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
742 /* probe value to be within 0 to 255 */
743 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
744 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
745 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
747 case OP_LCONV_TO_OVF_I2: {
748 MonoBasicBlock *is_negative, *end_label;
750 NEW_BBLOCK (cfg, is_negative);
751 NEW_BBLOCK (cfg, end_label);
753 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
754 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
755 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
756 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
759 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
762 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
763 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
764 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
767 MONO_START_BB (cfg, is_negative);
768 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
769 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
770 MONO_START_BB (cfg, end_label);
772 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
775 case OP_LCONV_TO_OVF_I2_UN:
776 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
777 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
779 /* Probe value to be within -32768 and 32767 */
780 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
781 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
782 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
783 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
784 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
786 case OP_LCONV_TO_OVF_U2:
787 case OP_LCONV_TO_OVF_U2_UN:
788 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
789 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
791 /* Probe value to be within 0 and 65535 */
792 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
793 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
794 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
796 case OP_LCONV_TO_OVF_I4:
797 case OP_LCONV_TO_OVF_I:
798 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
800 case OP_LCONV_TO_OVF_U4:
801 case OP_LCONV_TO_OVF_U:
802 case OP_LCONV_TO_OVF_U4_UN:
803 case OP_LCONV_TO_OVF_U_UN:
804 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
805 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
806 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
808 case OP_LCONV_TO_OVF_I_UN:
809 case OP_LCONV_TO_OVF_I4_UN:
810 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
811 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
812 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
813 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
814 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
816 case OP_LCONV_TO_OVF_U8:
817 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
818 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
820 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
821 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
823 case OP_LCONV_TO_OVF_I8_UN:
824 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
825 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
827 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
828 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
832 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
833 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
836 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
837 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
841 /* ADC sets the condition code */
842 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
843 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
844 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
847 /* ADC sets the condition code */
848 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
849 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
850 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
853 /* SBB sets the condition code */
854 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
855 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
856 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
859 /* SBB sets the condition code */
860 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
861 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
862 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
865 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
866 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
869 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
870 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
873 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
874 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
877 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
878 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
881 /* Handled in mono_arch_decompose_long_opts () */
882 g_assert_not_reached ();
886 /* FIXME: Add OP_BIGMUL optimization */
890 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
891 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
894 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
895 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
898 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
899 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
902 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
903 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
906 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
907 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
910 if (tree->inst_c1 == 32) {
912 /* The original code had this comment: */
913 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
914 * later apply the speedup to the left shift as well
917 /* FIXME: Move this to the strength reduction pass */
918 /* just move the upper half to the lower and zero the high word */
919 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
920 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
924 if (tree->inst_c1 == 32) {
925 /* just move the lower half to the upper and zero the lower word */
926 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
927 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
932 MonoInst *next = tree->next;
936 switch (next->opcode) {
941 /* Branchless version based on gcc code */
942 d1 = alloc_ireg (cfg);
943 d2 = alloc_ireg (cfg);
944 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
945 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
946 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
947 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
948 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
949 next->opcode = OP_NOP;
960 /* Convert into three comparisons + branches */
961 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
962 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
963 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
964 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
965 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
966 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
967 next->opcode = OP_NOP;
972 /* Branchless version based on gcc code */
973 d1 = alloc_ireg (cfg);
974 d2 = alloc_ireg (cfg);
975 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
976 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
977 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
979 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
980 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
981 next->opcode = OP_NOP;
988 MonoBasicBlock *set_to_0, *set_to_1;
990 NEW_BBLOCK (cfg, set_to_0);
991 NEW_BBLOCK (cfg, set_to_1);
993 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
994 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
995 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
996 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
997 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
998 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
999 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1000 MONO_START_BB (cfg, set_to_1);
1001 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1002 MONO_START_BB (cfg, set_to_0);
1003 next->opcode = OP_NOP;
1007 g_assert_not_reached ();
1012 /* Not yet used, since lcompare is decomposed before local cprop */
1013 case OP_LCOMPARE_IMM: {
1014 MonoInst *next = tree->next;
1015 guint32 low_imm = tree->inst_ls_word;
1016 guint32 high_imm = tree->inst_ms_word;
1017 int low_reg = tree->sreg1 + 1;
1018 int high_reg = tree->sreg1 + 2;
1022 switch (next->opcode) {
1027 /* Branchless version based on gcc code */
1028 d1 = alloc_ireg (cfg);
1029 d2 = alloc_ireg (cfg);
1030 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1031 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1032 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1033 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1034 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1035 next->opcode = OP_NOP;
1047 /* Convert into three comparisons + branches */
1048 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1049 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1050 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1051 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1052 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1053 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1054 next->opcode = OP_NOP;
1059 /* Branchless version based on gcc code */
1060 d1 = alloc_ireg (cfg);
1061 d2 = alloc_ireg (cfg);
1062 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1063 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1064 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1066 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1067 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1068 next->opcode = OP_NOP;
1075 MonoBasicBlock *set_to_0, *set_to_1;
1077 NEW_BBLOCK (cfg, set_to_0);
1078 NEW_BBLOCK (cfg, set_to_1);
1080 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1081 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1082 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1083 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1084 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1085 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1086 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1087 MONO_START_BB (cfg, set_to_1);
1088 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1089 MONO_START_BB (cfg, set_to_0);
1090 next->opcode = OP_NOP;
1094 g_assert_not_reached ();
1103 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1106 /* Replace the original instruction with the new code sequence */
1108 /* Ignore the new value of prev */
1110 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1112 /* Process the newly added ops again since they can be long ops too */
1118 first_bb->code = first_bb->last_ins = NULL;
1119 first_bb->in_count = first_bb->out_count = 0;
1120 cfg->cbb = first_bb;
1131 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1132 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1137 * mono_decompose_vtype_opts:
1139 * Decompose valuetype opcodes.
1142 mono_decompose_vtype_opts (MonoCompile *cfg)
1144 MonoBasicBlock *bb, *first_bb;
1147 * Using OP_V opcodes and decomposing them later have two main benefits:
1148 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1150 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1151 * enabling optimizations to work on vtypes too.
1152 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1153 * can be executed anytime. It should be executed as late as possible so vtype
1154 * opcodes can be optimized by the other passes.
1155 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1156 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1158 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1159 * when OP_VMOVE opcodes are decomposed.
1163 * Vregs have no associated type information, so we store the type of the vregs
1168 * Create a dummy bblock and emit code into it so we can use the normal
1169 * code generation macros.
1171 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1172 first_bb = cfg->cbb;
1174 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1176 MonoInst *prev = NULL;
1177 MonoInst *src_var, *dest_var, *src, *dest;
1181 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1183 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1189 for (ins = bb->code; ins; ins = ins->next) {
1190 switch (ins->opcode) {
1192 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1193 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1195 g_assert (ins->klass);
1198 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1201 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1204 if (src_var->backend.is_pinvoke)
1205 dest_var->backend.is_pinvoke = 1;
1207 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1208 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1210 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1214 g_assert (ins->klass);
1216 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1217 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1219 if (cfg->compute_gc_maps) {
1223 * Tell the GC map code that the vtype is considered live after
1224 * the initialization.
1226 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1227 tmp->inst_c1 = ins->dreg;
1228 MONO_ADD_INS (cfg->cbb, tmp);
1231 case OP_DUMMY_VZERO:
1234 case OP_STOREV_MEMBASE: {
1235 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1238 g_assert (ins->klass);
1239 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1242 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1244 dreg = alloc_preg (cfg);
1245 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1246 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1249 case OP_LOADV_MEMBASE: {
1250 g_assert (ins->klass);
1252 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1256 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1258 dreg = alloc_preg (cfg);
1259 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1260 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1261 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1264 case OP_OUTARG_VT: {
1265 g_assert (ins->klass);
1267 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1269 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1270 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1272 mono_arch_emit_outarg_vt (cfg, ins, src);
1274 /* This might be decomposed into other vtype opcodes */
1278 case OP_OUTARG_VTRETADDR: {
1279 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1281 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1283 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1284 // FIXME: src_var->backend.is_pinvoke ?
1286 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1287 src->dreg = ins->dreg;
1292 case OP_VCALL_MEMBASE: {
1293 MonoCallInst *call = (MonoCallInst*)ins;
1296 if (call->vret_in_reg) {
1297 MonoCallInst *call2;
1299 /* Replace the vcall with an integer call */
1300 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1301 memcpy (call2, call, sizeof (MonoCallInst));
1302 switch (ins->opcode) {
1304 call2->inst.opcode = OP_CALL;
1307 call2->inst.opcode = OP_CALL_REG;
1309 case OP_VCALL_MEMBASE:
1310 call2->inst.opcode = OP_CALL_MEMBASE;
1313 call2->inst.dreg = alloc_preg (cfg);
1314 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1316 /* Compute the vtype location */
1317 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1319 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1320 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1322 /* Save the result */
1323 if (dest_var->backend.is_pinvoke)
1324 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1326 size = mono_type_size (dest_var->inst_vtype, NULL);
1329 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1332 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1336 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1342 #if SIZEOF_REGISTER == 4
1344 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1345 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1347 switch (call2->inst.opcode) {
1349 call2->inst.opcode = OP_LCALL;
1352 call2->inst.opcode = OP_LCALL_REG;
1354 case OP_CALL_MEMBASE:
1355 call2->inst.opcode = OP_LCALL_MEMBASE;
1358 call2->inst.dreg = alloc_lreg (cfg);
1359 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1360 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1362 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1366 /* This assumes the vtype is sizeof (gpointer) long */
1367 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1371 switch (ins->opcode) {
1373 ins->opcode = OP_VCALL2;
1376 ins->opcode = OP_VCALL2_REG;
1378 case OP_VCALL_MEMBASE:
1379 ins->opcode = OP_VCALL2_MEMBASE;
1390 g_assert (cfg->cbb == first_bb);
1392 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1393 /* Replace the original instruction with the new code sequence */
1395 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1396 first_bb->code = first_bb->last_ins = NULL;
1397 first_bb->in_count = first_bb->out_count = 0;
1398 cfg->cbb = first_bb;
1405 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1410 mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
1412 MonoBasicBlock *bb, *first_bb;
1414 /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
1416 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1417 first_bb = cfg->cbb;
1419 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1421 MonoInst *prev = NULL;
1422 MonoInst *src_var, *src, *dest;
1426 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
1428 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1434 for (ins = bb->code; ins; ins = ins->next) {
1435 switch (ins->opcode) {
1436 case OP_STOREV_MEMBASE: {
1437 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1440 g_assert (ins->klass);
1441 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1444 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1446 dreg = alloc_preg (cfg);
1447 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1448 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1455 g_assert (cfg->cbb == first_bb);
1457 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1458 /* Replace the original instruction with the new code sequence */
1460 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1461 first_bb->code = first_bb->last_ins = NULL;
1462 first_bb->in_count = first_bb->out_count = 0;
1463 cfg->cbb = first_bb;
1470 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
1474 inline static MonoInst *
1475 mono_get_domainvar (MonoCompile *cfg)
1477 if (!cfg->domainvar)
1478 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1479 return cfg->domainvar;
1483 * mono_decompose_array_access_opts:
1485 * Decompose array access opcodes.
1488 mono_decompose_array_access_opts (MonoCompile *cfg)
1490 MonoBasicBlock *bb, *first_bb;
1493 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1494 * can be executed anytime. It should be run before decompose_long
1498 * Create a dummy bblock and emit code into it so we can use the normal
1499 * code generation macros.
1501 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1502 first_bb = cfg->cbb;
1504 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1506 MonoInst *prev = NULL;
1508 MonoInst *iargs [3];
1511 if (!bb->has_array_access)
1514 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1516 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1522 for (ins = bb->code; ins; ins = ins->next) {
1523 switch (ins->opcode) {
1525 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1526 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1527 MONO_ADD_INS (cfg->cbb, dest);
1529 case OP_BOUNDS_CHECK:
1530 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1531 if (COMPILE_LLVM (cfg))
1532 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1534 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1537 if (cfg->opt & MONO_OPT_SHARED) {
1538 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1539 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1540 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1541 iargs [2]->dreg = ins->sreg1;
1543 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1544 dest->dreg = ins->dreg;
1546 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1547 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1548 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1550 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1551 NEW_VTABLECONST (cfg, iargs [0], vtable);
1552 MONO_ADD_INS (cfg->cbb, iargs [0]);
1553 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1554 iargs [1]->dreg = ins->sreg1;
1557 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1559 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1560 dest->dreg = ins->dreg;
1564 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1565 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1571 g_assert (cfg->cbb == first_bb);
1573 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1574 /* Replace the original instruction with the new code sequence */
1576 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1577 first_bb->code = first_bb->last_ins = NULL;
1578 first_bb->in_count = first_bb->out_count = 0;
1579 cfg->cbb = first_bb;
1586 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1596 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1599 * mono_decompose_soft_float:
1601 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1602 * similar to long support on 32 bit platforms. 32 bit float values require special
1603 * handling when used as locals, arguments, and in calls.
1604 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1607 mono_decompose_soft_float (MonoCompile *cfg)
1609 MonoBasicBlock *bb, *first_bb;
1612 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1616 * Create a dummy bblock and emit code into it so we can use the normal
1617 * code generation macros.
1619 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1620 first_bb = cfg->cbb;
1622 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1624 MonoInst *prev = NULL;
1627 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1629 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1635 for (ins = bb->code; ins; ins = ins->next) {
1636 const char *spec = INS_INFO (ins->opcode);
1638 /* Most fp operations are handled automatically by opcode emulation */
1640 switch (ins->opcode) {
1643 d.vald = *(double*)ins->inst_p0;
1644 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1649 /* We load the r8 value */
1650 d.vald = *(float*)ins->inst_p0;
1651 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1655 ins->opcode = OP_LMOVE;
1658 ins->opcode = OP_MOVE;
1659 ins->sreg1 = ins->sreg1 + 1;
1662 ins->opcode = OP_MOVE;
1663 ins->sreg1 = ins->sreg1 + 2;
1666 int reg = ins->sreg1;
1668 ins->opcode = OP_SETLRET;
1670 ins->sreg1 = reg + 1;
1671 ins->sreg2 = reg + 2;
1674 case OP_LOADR8_MEMBASE:
1675 ins->opcode = OP_LOADI8_MEMBASE;
1677 case OP_STORER8_MEMBASE_REG:
1678 ins->opcode = OP_STOREI8_MEMBASE_REG;
1680 case OP_STORER4_MEMBASE_REG: {
1681 MonoInst *iargs [2];
1684 /* Arg 1 is the double value */
1685 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1686 iargs [0]->dreg = ins->sreg1;
1688 /* Arg 2 is the address to store to */
1689 addr_reg = mono_alloc_preg (cfg);
1690 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1691 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1695 case OP_LOADR4_MEMBASE: {
1696 MonoInst *iargs [1];
1700 addr_reg = mono_alloc_preg (cfg);
1701 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1702 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1703 conv->dreg = ins->dreg;
1708 case OP_FCALL_MEMBASE: {
1709 MonoCallInst *call = (MonoCallInst*)ins;
1710 if (call->signature->ret->type == MONO_TYPE_R4) {
1711 MonoCallInst *call2;
1712 MonoInst *iargs [1];
1716 /* Convert the call into a call returning an int */
1717 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1718 memcpy (call2, call, sizeof (MonoCallInst));
1719 switch (ins->opcode) {
1721 call2->inst.opcode = OP_CALL;
1724 call2->inst.opcode = OP_CALL_REG;
1726 case OP_FCALL_MEMBASE:
1727 call2->inst.opcode = OP_CALL_MEMBASE;
1730 g_assert_not_reached ();
1732 call2->inst.dreg = mono_alloc_ireg (cfg);
1733 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1735 /* Remap OUTARG_VT instructions referencing this call */
1736 for (l = call->outarg_vts; l; l = l->next)
1737 ((MonoInst*)(l->data))->inst_p0 = call2;
1739 /* FIXME: Optimize this */
1741 /* Emit an r4->r8 conversion */
1742 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1743 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1744 conv->dreg = ins->dreg;
1746 /* The call sequence might include fp ins */
1749 switch (ins->opcode) {
1751 ins->opcode = OP_LCALL;
1754 ins->opcode = OP_LCALL_REG;
1756 case OP_FCALL_MEMBASE:
1757 ins->opcode = OP_LCALL_MEMBASE;
1760 g_assert_not_reached ();
1766 MonoJitICallInfo *info;
1767 MonoInst *iargs [2];
1768 MonoInst *call, *cmp, *br;
1770 /* Convert fcompare+fbcc to icall+icompare+beq */
1773 /* The branch might be optimized away */
1778 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1780 /* The branch might be optimized away */
1785 /* Create dummy MonoInst's for the arguments */
1786 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1787 iargs [0]->dreg = ins->sreg1;
1788 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1789 iargs [1]->dreg = ins->sreg2;
1791 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1793 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1794 cmp->sreg1 = call->dreg;
1796 MONO_ADD_INS (cfg->cbb, cmp);
1798 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1799 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1800 br->inst_true_bb = ins->next->inst_true_bb;
1801 br->inst_false_bb = ins->next->inst_false_bb;
1802 MONO_ADD_INS (cfg->cbb, br);
1804 /* The call sequence might include fp ins */
1807 /* Skip fbcc or fccc */
1808 NULLIFY_INS (ins->next);
1816 MonoJitICallInfo *info;
1817 MonoInst *iargs [2];
1820 /* Convert fccc to icall+icompare+iceq */
1822 info = mono_find_jit_opcode_emulation (ins->opcode);
1825 /* Create dummy MonoInst's for the arguments */
1826 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1827 iargs [0]->dreg = ins->sreg1;
1828 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1829 iargs [1]->dreg = ins->sreg2;
1831 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1833 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1834 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1836 /* The call sequence might include fp ins */
1841 MonoInst *iargs [2];
1842 MonoInst *call, *cmp;
1844 /* Convert to icall+icompare+cond_exc+move */
1846 /* Create dummy MonoInst's for the arguments */
1847 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1848 iargs [0]->dreg = ins->sreg1;
1850 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1852 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1853 cmp->sreg1 = call->dreg;
1855 MONO_ADD_INS (cfg->cbb, cmp);
1857 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1859 /* Do the assignment if the value is finite */
1860 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1866 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1867 mono_print_ins (ins);
1868 g_assert_not_reached ();
1873 g_assert (cfg->cbb == first_bb);
1875 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1876 /* Replace the original instruction with the new code sequence */
1878 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1879 first_bb->code = first_bb->last_ins = NULL;
1880 first_bb->in_count = first_bb->out_count = 0;
1881 cfg->cbb = first_bb;
1888 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1891 mono_decompose_long_opts (cfg);
1896 #endif /* DISABLE_JIT */