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);
24 /* Decompose complex long opcodes on 64 bit machines or when using LLVM */
26 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
28 MonoInst *repl = NULL;
32 switch (ins->opcode) {
34 ins->opcode = OP_SEXT_I4;
40 ins->opcode = OP_MOVE;
43 ins->opcode = OP_SEXT_I4;
46 ins->opcode = OP_ZEXT_I4;
49 /* Clean out the upper word */
50 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
54 if (COMPILE_LLVM (cfg))
58 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
63 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
65 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
69 if (COMPILE_LLVM (cfg))
73 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
78 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
80 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
83 #ifndef __mono_ppc64__
85 if (COMPILE_LLVM (cfg))
89 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
94 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
96 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
100 if (COMPILE_LLVM (cfg))
104 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
109 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
111 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
116 case OP_ICONV_TO_OVF_I8:
117 case OP_ICONV_TO_OVF_I:
118 ins->opcode = OP_SEXT_I4;
120 case OP_ICONV_TO_OVF_U8:
121 case OP_ICONV_TO_OVF_U:
122 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
123 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
124 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
127 case OP_ICONV_TO_OVF_I8_UN:
128 case OP_ICONV_TO_OVF_U8_UN:
129 case OP_ICONV_TO_OVF_I_UN:
130 case OP_ICONV_TO_OVF_U_UN:
131 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
132 /* Clean out the upper word */
133 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
136 case OP_LCONV_TO_OVF_I1:
137 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
138 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
139 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
140 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
141 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
144 case OP_LCONV_TO_OVF_I1_UN:
145 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
146 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
147 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
150 case OP_LCONV_TO_OVF_U1:
151 /* probe value to be within 0 to 255 */
152 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
153 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
154 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
157 case OP_LCONV_TO_OVF_U1_UN:
158 /* probe value to be within 0 to 255 */
159 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
160 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
161 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
164 case OP_LCONV_TO_OVF_I2:
165 /* Probe value to be within -32768 and 32767 */
166 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
167 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
168 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
169 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
170 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
173 case OP_LCONV_TO_OVF_I2_UN:
174 /* Probe value to be within 0 and 32767 */
175 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
176 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
177 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
180 case OP_LCONV_TO_OVF_U2:
181 /* Probe value to be within 0 and 65535 */
182 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
183 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
184 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
187 case OP_LCONV_TO_OVF_U2_UN:
188 /* Probe value to be within 0 and 65535 */
189 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
190 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
191 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
194 case OP_LCONV_TO_OVF_I4:
195 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
196 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
197 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
198 #if SIZEOF_REGISTER == 8
199 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
201 g_assert (COMPILE_LLVM (cfg));
202 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
204 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
205 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
208 case OP_LCONV_TO_OVF_I4_UN:
209 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
210 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
211 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
214 case OP_LCONV_TO_OVF_U4:
215 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
216 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
217 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
218 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
219 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
222 case OP_LCONV_TO_OVF_U4_UN:
223 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
224 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
225 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
228 case OP_LCONV_TO_OVF_I:
229 case OP_LCONV_TO_OVF_U_UN:
230 case OP_LCONV_TO_OVF_U8_UN:
231 case OP_LCONV_TO_OVF_I8:
232 ins->opcode = OP_MOVE;
234 case OP_LCONV_TO_OVF_I_UN:
235 case OP_LCONV_TO_OVF_I8_UN:
236 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
237 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
238 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
241 case OP_LCONV_TO_OVF_U8:
242 case OP_LCONV_TO_OVF_U:
243 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
244 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
245 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
257 * mono_decompose_opcode:
259 * Decompose complex opcodes into ones closer to opcodes supported by
260 * the given architecture.
261 * Returns a MonoInst which represents the result of the decomposition, and can
262 * be pushed on the IL stack. This is needed because the original instruction is
264 * Sets the cfg exception if an opcode is not supported.
267 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
269 MonoInst *repl = NULL;
270 int type = ins->type;
271 int dreg = ins->dreg;
272 gboolean emulate = FALSE;
274 /* FIXME: Instead of = NOP, don't emit the original ins at all */
276 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
277 mono_arch_decompose_opts (cfg, ins);
281 * The code below assumes that we are called immediately after emitting
282 * ins. This means we can emit code using the normal code generation
285 switch (ins->opcode) {
286 /* this doesn't make sense on ppc and other architectures */
287 #if !defined(MONO_ARCH_NO_IOV_CHECK)
289 if (COMPILE_LLVM (cfg))
291 ins->opcode = OP_IADDCC;
292 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
295 if (COMPILE_LLVM (cfg))
297 ins->opcode = OP_IADDCC;
298 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
301 if (COMPILE_LLVM (cfg))
303 ins->opcode = OP_ISUBCC;
304 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
307 if (COMPILE_LLVM (cfg))
309 ins->opcode = OP_ISUBCC;
310 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
313 case OP_ICONV_TO_OVF_I1:
314 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
315 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
316 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
317 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
318 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
321 case OP_ICONV_TO_OVF_I1_UN:
322 /* probe values between 0 to 127 */
323 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
324 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
325 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
328 case OP_ICONV_TO_OVF_U1:
329 case OP_ICONV_TO_OVF_U1_UN:
330 /* probe value to be within 0 to 255 */
331 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
332 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
333 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
336 case OP_ICONV_TO_OVF_I2:
337 /* Probe value to be within -32768 and 32767 */
338 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
339 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
340 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
341 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
342 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
345 case OP_ICONV_TO_OVF_I2_UN:
346 /* Convert uint value into short, value within 0 and 32767 */
347 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
348 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
349 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
352 case OP_ICONV_TO_OVF_U2:
353 case OP_ICONV_TO_OVF_U2_UN:
354 /* Probe value to be within 0 and 65535 */
355 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
356 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
357 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
360 case OP_ICONV_TO_OVF_U4:
361 case OP_ICONV_TO_OVF_I4_UN:
362 #if SIZEOF_VOID_P == 4
363 case OP_ICONV_TO_OVF_U:
364 case OP_ICONV_TO_OVF_I_UN:
366 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
367 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
368 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
373 case OP_ICONV_TO_OVF_I4:
374 case OP_ICONV_TO_OVF_U4_UN:
375 #if SIZEOF_VOID_P == 4
376 case OP_ICONV_TO_OVF_I:
377 case OP_ICONV_TO_OVF_U_UN:
379 ins->opcode = OP_MOVE;
382 #if SIZEOF_VOID_P == 8
383 ins->opcode = OP_SEXT_I4;
385 ins->opcode = OP_MOVE;
389 #if SIZEOF_VOID_P == 8
390 ins->opcode = OP_ZEXT_I4;
392 ins->opcode = OP_MOVE;
397 ins->opcode = OP_FMOVE;
400 case OP_FCONV_TO_OVF_I1_UN:
401 case OP_FCONV_TO_OVF_I2_UN:
402 case OP_FCONV_TO_OVF_I4_UN:
403 case OP_FCONV_TO_OVF_I8_UN:
404 case OP_FCONV_TO_OVF_U1_UN:
405 case OP_FCONV_TO_OVF_U2_UN:
406 case OP_FCONV_TO_OVF_U4_UN:
407 case OP_FCONV_TO_OVF_U8_UN:
408 case OP_FCONV_TO_OVF_I_UN:
409 case OP_FCONV_TO_OVF_U_UN:
410 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
411 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
414 #if defined(MONO_ARCH_EMULATE_DIV) && defined(MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION)
419 if (!mono_arch_opcode_needs_emulation (cfg, ins->opcode)) {
420 #ifdef MONO_ARCH_NEED_DIV_CHECK
421 int reg1 = alloc_ireg (cfg);
422 int reg2 = alloc_ireg (cfg);
424 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
425 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
426 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
427 /* b == -1 && a == 0x80000000 */
428 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
429 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
430 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
431 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
432 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
433 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
434 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
437 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
438 ins->opcode = OP_NOP;
451 MonoJitICallInfo *info = NULL;
453 #if SIZEOF_REGISTER == 8
454 if (decompose_long_opcode (cfg, ins, &repl))
457 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
462 info = mono_find_jit_opcode_emulation (ins->opcode);
467 /* Create dummy MonoInst's for the arguments */
468 g_assert (!info->sig->hasthis);
469 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
471 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
472 if (info->sig->param_count > 0) {
473 int sregs [MONO_MAX_SRC_REGS];
475 num_sregs = mono_inst_get_src_registers (ins, sregs);
476 g_assert (num_sregs == info->sig->param_count);
477 for (i = 0; i < num_sregs; ++i) {
478 MONO_INST_NEW (cfg, args [i], OP_ARG);
479 args [i]->dreg = sregs [i];
483 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
484 call->dreg = ins->dreg;
490 if (ins->opcode == OP_NOP) {
495 /* Use the last emitted instruction */
496 ins = cfg->cbb->last_ins;
499 g_assert (ins->dreg == dreg);
507 #if SIZEOF_REGISTER == 4
508 static int lbr_decomp [][2] = {
510 {OP_IBGT, OP_IBGE_UN}, /* BGE */
511 {OP_IBGT, OP_IBGT_UN}, /* BGT */
512 {OP_IBLT, OP_IBLE_UN}, /* BLE */
513 {OP_IBLT, OP_IBLT_UN}, /* BLT */
515 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
516 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
517 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
518 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
521 static int lcset_decomp [][2] = {
523 {OP_IBLT, OP_IBLE_UN}, /* CGT */
524 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
525 {OP_IBGT, OP_IBGE_UN}, /* CLT */
526 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
531 * mono_decompose_long_opts:
533 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
536 mono_decompose_long_opts (MonoCompile *cfg)
538 #if SIZEOF_REGISTER == 4
539 MonoBasicBlock *bb, *first_bb;
542 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
543 * needs to be able to handle long vregs.
546 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
549 * Create a dummy bblock and emit code into it so we can use the normal
550 * code generation macros.
552 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
555 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
556 MonoInst *tree = bb->code;
557 MonoInst *prev = NULL;
560 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
564 cfg->cbb->code = cfg->cbb->last_ins = NULL;
568 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
569 mono_arch_decompose_long_opts (cfg, tree);
572 switch (tree->opcode) {
574 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
575 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
577 case OP_DUMMY_I8CONST:
578 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 1, OP_DUMMY_ICONST);
579 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 2, OP_DUMMY_ICONST);
584 case OP_LCONV_TO_OVF_U8_UN:
585 case OP_LCONV_TO_OVF_I8:
586 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
587 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
589 case OP_STOREI8_MEMBASE_REG:
590 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
591 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
593 case OP_LOADI8_MEMBASE:
594 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
595 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
598 case OP_ICONV_TO_I8: {
599 guint32 tmpreg = alloc_ireg (cfg);
603 * tmp = low > -1 ? 1: 0;
604 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
606 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
607 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
608 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
609 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
613 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
614 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
616 case OP_ICONV_TO_OVF_I8:
617 /* a signed 32 bit num always fits in a signed 64 bit one */
618 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
619 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
621 case OP_ICONV_TO_OVF_U8:
622 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
623 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
624 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
625 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
627 case OP_ICONV_TO_OVF_I8_UN:
628 case OP_ICONV_TO_OVF_U8_UN:
629 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
630 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
631 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
634 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
637 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
640 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
643 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
649 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
652 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
655 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
657 case OP_LCONV_TO_R_UN:
658 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
660 case OP_LCONV_TO_OVF_I1: {
661 MonoBasicBlock *is_negative, *end_label;
663 NEW_BBLOCK (cfg, is_negative);
664 NEW_BBLOCK (cfg, end_label);
666 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
667 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
668 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
669 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
671 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
672 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
675 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
676 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
677 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
680 MONO_START_BB (cfg, is_negative);
681 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
682 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
684 MONO_START_BB (cfg, end_label);
686 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
689 case OP_LCONV_TO_OVF_I1_UN:
690 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
691 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
693 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
694 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
695 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
696 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
697 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
699 case OP_LCONV_TO_OVF_U1:
700 case OP_LCONV_TO_OVF_U1_UN:
701 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
702 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
704 /* probe value to be within 0 to 255 */
705 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
706 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
707 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
709 case OP_LCONV_TO_OVF_I2: {
710 MonoBasicBlock *is_negative, *end_label;
712 NEW_BBLOCK (cfg, is_negative);
713 NEW_BBLOCK (cfg, end_label);
715 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
716 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
717 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
718 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
720 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
721 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
724 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
725 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
726 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
729 MONO_START_BB (cfg, is_negative);
730 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
731 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
732 MONO_START_BB (cfg, end_label);
734 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
737 case OP_LCONV_TO_OVF_I2_UN:
738 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
739 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
741 /* Probe value to be within -32768 and 32767 */
742 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
743 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
744 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
745 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
746 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
748 case OP_LCONV_TO_OVF_U2:
749 case OP_LCONV_TO_OVF_U2_UN:
750 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
751 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
753 /* Probe value to be within 0 and 65535 */
754 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
755 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
756 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
758 case OP_LCONV_TO_OVF_I4:
759 case OP_LCONV_TO_OVF_I:
760 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
762 case OP_LCONV_TO_OVF_U4:
763 case OP_LCONV_TO_OVF_U:
764 case OP_LCONV_TO_OVF_U4_UN:
765 case OP_LCONV_TO_OVF_U_UN:
766 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
767 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
768 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
770 case OP_LCONV_TO_OVF_I_UN:
771 case OP_LCONV_TO_OVF_I4_UN:
772 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
773 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
774 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
775 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
776 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
778 case OP_LCONV_TO_OVF_U8:
779 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
780 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
782 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
783 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
785 case OP_LCONV_TO_OVF_I8_UN:
786 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
787 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
789 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
790 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
794 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
795 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
798 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
799 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
803 /* ADC sets the condition code */
804 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
805 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
806 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
809 /* ADC sets the condition code */
810 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
811 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
812 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
815 /* SBB sets the condition code */
816 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
817 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
818 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
821 /* SBB sets the condition code */
822 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
823 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
824 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
827 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
828 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
831 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
832 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
835 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
836 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
839 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
840 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
843 /* Handled in mono_arch_decompose_long_opts () */
844 g_assert_not_reached ();
848 /* FIXME: Add OP_BIGMUL optimization */
852 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
853 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
856 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
857 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
860 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
861 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
864 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
865 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
868 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
869 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
872 if (tree->inst_c1 == 32) {
874 /* The original code had this comment: */
875 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
876 * later apply the speedup to the left shift as well
879 /* FIXME: Move this to the strength reduction pass */
880 /* just move the upper half to the lower and zero the high word */
881 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
882 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
886 if (tree->inst_c1 == 32) {
887 /* just move the lower half to the upper and zero the lower word */
888 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
889 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
894 MonoInst *next = tree->next;
898 switch (next->opcode) {
903 /* Branchless version based on gcc code */
904 d1 = alloc_ireg (cfg);
905 d2 = alloc_ireg (cfg);
906 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
907 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
908 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
909 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
910 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
911 next->opcode = OP_NOP;
922 /* Convert into three comparisons + branches */
923 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
924 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
925 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
926 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
927 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
928 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
929 next->opcode = OP_NOP;
934 /* Branchless version based on gcc code */
935 d1 = alloc_ireg (cfg);
936 d2 = alloc_ireg (cfg);
937 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
938 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
939 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
942 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
943 next->opcode = OP_NOP;
950 MonoBasicBlock *set_to_0, *set_to_1;
952 NEW_BBLOCK (cfg, set_to_0);
953 NEW_BBLOCK (cfg, set_to_1);
955 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
956 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
957 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
958 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
959 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
960 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
961 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
962 MONO_START_BB (cfg, set_to_1);
963 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
964 MONO_START_BB (cfg, set_to_0);
965 next->opcode = OP_NOP;
969 g_assert_not_reached ();
974 /* Not yet used, since lcompare is decomposed before local cprop */
975 case OP_LCOMPARE_IMM: {
976 MonoInst *next = tree->next;
977 guint32 low_imm = tree->inst_ls_word;
978 guint32 high_imm = tree->inst_ms_word;
979 int low_reg = tree->sreg1 + 1;
980 int high_reg = tree->sreg1 + 2;
984 switch (next->opcode) {
989 /* Branchless version based on gcc code */
990 d1 = alloc_ireg (cfg);
991 d2 = alloc_ireg (cfg);
992 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
993 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
994 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
995 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
996 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
997 next->opcode = OP_NOP;
1009 /* Convert into three comparisons + branches */
1010 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1011 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1012 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1013 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1014 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1015 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1016 next->opcode = OP_NOP;
1021 /* Branchless version based on gcc code */
1022 d1 = alloc_ireg (cfg);
1023 d2 = alloc_ireg (cfg);
1024 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1025 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1026 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1028 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1029 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1030 next->opcode = OP_NOP;
1037 MonoBasicBlock *set_to_0, *set_to_1;
1039 NEW_BBLOCK (cfg, set_to_0);
1040 NEW_BBLOCK (cfg, set_to_1);
1042 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1043 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1044 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1045 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1046 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1047 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1048 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1049 MONO_START_BB (cfg, set_to_1);
1050 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1051 MONO_START_BB (cfg, set_to_0);
1052 next->opcode = OP_NOP;
1056 g_assert_not_reached ();
1065 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1068 /* Replace the original instruction with the new code sequence */
1070 /* Ignore the new value of prev */
1072 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1074 /* Process the newly added ops again since they can be long ops too */
1080 first_bb->code = first_bb->last_ins = NULL;
1081 first_bb->in_count = first_bb->out_count = 0;
1082 cfg->cbb = first_bb;
1093 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1094 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1099 * mono_decompose_vtype_opts:
1101 * Decompose valuetype opcodes.
1104 mono_decompose_vtype_opts (MonoCompile *cfg)
1106 MonoBasicBlock *bb, *first_bb;
1109 * Using OP_V opcodes and decomposing them later have two main benefits:
1110 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1112 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1113 * enabling optimizations to work on vtypes too.
1114 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1115 * can be executed anytime. It should be executed as late as possible so vtype
1116 * opcodes can be optimized by the other passes.
1117 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1118 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1120 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1121 * when OP_VMOVE opcodes are decomposed.
1125 * Vregs have no associated type information, so we store the type of the vregs
1130 * Create a dummy bblock and emit code into it so we can use the normal
1131 * code generation macros.
1133 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1134 first_bb = cfg->cbb;
1136 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1138 MonoInst *prev = NULL;
1139 MonoInst *src_var, *dest_var, *src, *dest;
1143 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1145 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1151 for (ins = bb->code; ins; ins = ins->next) {
1152 switch (ins->opcode) {
1154 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1155 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1157 g_assert (ins->klass);
1160 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1163 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1166 if (src_var->backend.is_pinvoke)
1167 dest_var->backend.is_pinvoke = 1;
1169 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1170 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1172 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1176 g_assert (ins->klass);
1178 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1179 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1181 if (cfg->compute_gc_maps) {
1185 * Tell the GC map code that the vtype is considered live after
1186 * the initialization.
1188 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1189 tmp->inst_c1 = ins->dreg;
1190 MONO_ADD_INS (cfg->cbb, tmp);
1193 case OP_DUMMY_VZERO:
1196 case OP_STOREV_MEMBASE: {
1197 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1200 g_assert (ins->klass);
1201 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1204 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1206 dreg = alloc_preg (cfg);
1207 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1208 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1211 case OP_LOADV_MEMBASE: {
1212 g_assert (ins->klass);
1214 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1218 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1220 dreg = alloc_preg (cfg);
1221 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1222 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1223 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1226 case OP_OUTARG_VT: {
1227 g_assert (ins->klass);
1229 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1231 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1232 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1234 mono_arch_emit_outarg_vt (cfg, ins, src);
1236 /* This might be decomposed into other vtype opcodes */
1240 case OP_OUTARG_VTRETADDR: {
1241 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1243 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1245 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1246 // FIXME: src_var->backend.is_pinvoke ?
1248 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1249 src->dreg = ins->dreg;
1254 case OP_VCALL_MEMBASE: {
1255 MonoCallInst *call = (MonoCallInst*)ins;
1258 if (call->vret_in_reg) {
1259 MonoCallInst *call2;
1261 /* Replace the vcall with an integer call */
1262 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1263 memcpy (call2, call, sizeof (MonoCallInst));
1264 switch (ins->opcode) {
1266 call2->inst.opcode = OP_CALL;
1269 call2->inst.opcode = OP_CALL_REG;
1271 case OP_VCALL_MEMBASE:
1272 call2->inst.opcode = OP_CALL_MEMBASE;
1275 call2->inst.dreg = alloc_preg (cfg);
1276 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1278 /* Compute the vtype location */
1279 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1281 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1282 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1284 /* Save the result */
1285 if (dest_var->backend.is_pinvoke)
1286 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1288 size = mono_type_size (dest_var->inst_vtype, NULL);
1291 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1294 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1298 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1304 #if SIZEOF_REGISTER == 4
1306 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1307 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1309 switch (call2->inst.opcode) {
1311 call2->inst.opcode = OP_LCALL;
1314 call2->inst.opcode = OP_LCALL_REG;
1316 case OP_CALL_MEMBASE:
1317 call2->inst.opcode = OP_LCALL_MEMBASE;
1320 call2->inst.dreg = alloc_lreg (cfg);
1321 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1322 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1324 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1328 /* This assumes the vtype is sizeof (gpointer) long */
1329 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1333 switch (ins->opcode) {
1335 ins->opcode = OP_VCALL2;
1338 ins->opcode = OP_VCALL2_REG;
1340 case OP_VCALL_MEMBASE:
1341 ins->opcode = OP_VCALL2_MEMBASE;
1352 g_assert (cfg->cbb == first_bb);
1354 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1355 /* Replace the original instruction with the new code sequence */
1357 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1358 first_bb->code = first_bb->last_ins = NULL;
1359 first_bb->in_count = first_bb->out_count = 0;
1360 cfg->cbb = first_bb;
1367 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1372 mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
1374 MonoBasicBlock *bb, *first_bb;
1376 /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
1378 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1379 first_bb = cfg->cbb;
1381 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1383 MonoInst *prev = NULL;
1384 MonoInst *src_var, *src, *dest;
1388 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
1390 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1396 for (ins = bb->code; ins; ins = ins->next) {
1397 switch (ins->opcode) {
1398 case OP_STOREV_MEMBASE: {
1399 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1402 g_assert (ins->klass);
1403 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1406 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1408 dreg = alloc_preg (cfg);
1409 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1410 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1417 g_assert (cfg->cbb == first_bb);
1419 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1420 /* Replace the original instruction with the new code sequence */
1422 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1423 first_bb->code = first_bb->last_ins = NULL;
1424 first_bb->in_count = first_bb->out_count = 0;
1425 cfg->cbb = first_bb;
1432 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
1436 inline static MonoInst *
1437 mono_get_domainvar (MonoCompile *cfg)
1439 if (!cfg->domainvar)
1440 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1441 return cfg->domainvar;
1445 * mono_decompose_array_access_opts:
1447 * Decompose array access opcodes.
1450 mono_decompose_array_access_opts (MonoCompile *cfg)
1452 MonoBasicBlock *bb, *first_bb;
1455 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1456 * can be executed anytime. It should be run before decompose_long
1460 * Create a dummy bblock and emit code into it so we can use the normal
1461 * code generation macros.
1463 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1464 first_bb = cfg->cbb;
1466 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1468 MonoInst *prev = NULL;
1470 MonoInst *iargs [3];
1473 if (!bb->has_array_access)
1476 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1478 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1484 for (ins = bb->code; ins; ins = ins->next) {
1485 switch (ins->opcode) {
1487 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1488 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1489 MONO_ADD_INS (cfg->cbb, dest);
1491 case OP_BOUNDS_CHECK:
1492 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1493 if (COMPILE_LLVM (cfg))
1494 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1496 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1499 if (cfg->opt & MONO_OPT_SHARED) {
1500 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1501 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1502 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1503 iargs [2]->dreg = ins->sreg1;
1505 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1506 dest->dreg = ins->dreg;
1508 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1509 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1510 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1512 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1513 NEW_VTABLECONST (cfg, iargs [0], vtable);
1514 MONO_ADD_INS (cfg->cbb, iargs [0]);
1515 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1516 iargs [1]->dreg = ins->sreg1;
1519 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1521 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1522 dest->dreg = ins->dreg;
1526 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1527 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1533 g_assert (cfg->cbb == first_bb);
1535 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1536 /* Replace the original instruction with the new code sequence */
1538 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1539 first_bb->code = first_bb->last_ins = NULL;
1540 first_bb->in_count = first_bb->out_count = 0;
1541 cfg->cbb = first_bb;
1548 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1558 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1561 * mono_decompose_soft_float:
1563 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1564 * similar to long support on 32 bit platforms. 32 bit float values require special
1565 * handling when used as locals, arguments, and in calls.
1566 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1569 mono_decompose_soft_float (MonoCompile *cfg)
1571 MonoBasicBlock *bb, *first_bb;
1574 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1578 * Create a dummy bblock and emit code into it so we can use the normal
1579 * code generation macros.
1581 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1582 first_bb = cfg->cbb;
1584 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1586 MonoInst *prev = NULL;
1589 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1591 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1597 for (ins = bb->code; ins; ins = ins->next) {
1598 const char *spec = INS_INFO (ins->opcode);
1600 /* Most fp operations are handled automatically by opcode emulation */
1602 switch (ins->opcode) {
1605 d.vald = *(double*)ins->inst_p0;
1606 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1611 /* We load the r8 value */
1612 d.vald = *(float*)ins->inst_p0;
1613 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1617 ins->opcode = OP_LMOVE;
1620 ins->opcode = OP_MOVE;
1621 ins->sreg1 = ins->sreg1 + 1;
1624 ins->opcode = OP_MOVE;
1625 ins->sreg1 = ins->sreg1 + 2;
1628 int reg = ins->sreg1;
1630 ins->opcode = OP_SETLRET;
1632 ins->sreg1 = reg + 1;
1633 ins->sreg2 = reg + 2;
1636 case OP_LOADR8_MEMBASE:
1637 ins->opcode = OP_LOADI8_MEMBASE;
1639 case OP_STORER8_MEMBASE_REG:
1640 ins->opcode = OP_STOREI8_MEMBASE_REG;
1642 case OP_STORER4_MEMBASE_REG: {
1643 MonoInst *iargs [2];
1646 /* Arg 1 is the double value */
1647 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1648 iargs [0]->dreg = ins->sreg1;
1650 /* Arg 2 is the address to store to */
1651 addr_reg = mono_alloc_preg (cfg);
1652 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1653 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1657 case OP_LOADR4_MEMBASE: {
1658 MonoInst *iargs [1];
1662 addr_reg = mono_alloc_preg (cfg);
1663 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1664 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1665 conv->dreg = ins->dreg;
1670 case OP_FCALL_MEMBASE: {
1671 MonoCallInst *call = (MonoCallInst*)ins;
1672 if (call->signature->ret->type == MONO_TYPE_R4) {
1673 MonoCallInst *call2;
1674 MonoInst *iargs [1];
1678 /* Convert the call into a call returning an int */
1679 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1680 memcpy (call2, call, sizeof (MonoCallInst));
1681 switch (ins->opcode) {
1683 call2->inst.opcode = OP_CALL;
1686 call2->inst.opcode = OP_CALL_REG;
1688 case OP_FCALL_MEMBASE:
1689 call2->inst.opcode = OP_CALL_MEMBASE;
1692 g_assert_not_reached ();
1694 call2->inst.dreg = mono_alloc_ireg (cfg);
1695 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1697 /* Remap OUTARG_VT instructions referencing this call */
1698 for (l = call->outarg_vts; l; l = l->next)
1699 ((MonoInst*)(l->data))->inst_p0 = call2;
1701 /* FIXME: Optimize this */
1703 /* Emit an r4->r8 conversion */
1704 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1705 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1706 conv->dreg = ins->dreg;
1708 /* The call sequence might include fp ins */
1711 switch (ins->opcode) {
1713 ins->opcode = OP_LCALL;
1716 ins->opcode = OP_LCALL_REG;
1718 case OP_FCALL_MEMBASE:
1719 ins->opcode = OP_LCALL_MEMBASE;
1722 g_assert_not_reached ();
1728 MonoJitICallInfo *info;
1729 MonoInst *iargs [2];
1730 MonoInst *call, *cmp, *br;
1732 /* Convert fcompare+fbcc to icall+icompare+beq */
1735 /* The branch might be optimized away */
1740 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1742 /* The branch might be optimized away */
1747 /* Create dummy MonoInst's for the arguments */
1748 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1749 iargs [0]->dreg = ins->sreg1;
1750 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1751 iargs [1]->dreg = ins->sreg2;
1753 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1755 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1756 cmp->sreg1 = call->dreg;
1758 MONO_ADD_INS (cfg->cbb, cmp);
1760 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1761 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1762 br->inst_true_bb = ins->next->inst_true_bb;
1763 br->inst_false_bb = ins->next->inst_false_bb;
1764 MONO_ADD_INS (cfg->cbb, br);
1766 /* The call sequence might include fp ins */
1769 /* Skip fbcc or fccc */
1770 NULLIFY_INS (ins->next);
1778 MonoJitICallInfo *info;
1779 MonoInst *iargs [2];
1782 /* Convert fccc to icall+icompare+iceq */
1784 info = mono_find_jit_opcode_emulation (ins->opcode);
1787 /* Create dummy MonoInst's for the arguments */
1788 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1789 iargs [0]->dreg = ins->sreg1;
1790 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1791 iargs [1]->dreg = ins->sreg2;
1793 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1795 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1796 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1798 /* The call sequence might include fp ins */
1803 MonoInst *iargs [2];
1804 MonoInst *call, *cmp;
1806 /* Convert to icall+icompare+cond_exc+move */
1808 /* Create dummy MonoInst's for the arguments */
1809 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1810 iargs [0]->dreg = ins->sreg1;
1812 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1814 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1815 cmp->sreg1 = call->dreg;
1817 MONO_ADD_INS (cfg->cbb, cmp);
1819 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1821 /* Do the assignment if the value is finite */
1822 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1828 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1829 mono_print_ins (ins);
1830 g_assert_not_reached ();
1835 g_assert (cfg->cbb == first_bb);
1837 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1838 /* Replace the original instruction with the new code sequence */
1840 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1841 first_bb->code = first_bb->last_ins = NULL;
1842 first_bb->in_count = first_bb->out_count = 0;
1843 cfg->cbb = first_bb;
1850 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1853 mono_decompose_long_opts (cfg);
1858 #endif /* DISABLE_JIT */