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 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;
273 /* FIXME: Instead of = NOP, don't emit the original ins at all */
275 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
276 mono_arch_decompose_opts (cfg, ins);
280 * The code below assumes that we are called immediately after emitting
281 * ins. This means we can emit code using the normal code generation
284 switch (ins->opcode) {
285 /* this doesn't make sense on ppc and other architectures */
286 #if !defined(MONO_ARCH_NO_IOV_CHECK)
288 if (COMPILE_LLVM (cfg))
290 ins->opcode = OP_IADDCC;
291 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
294 if (COMPILE_LLVM (cfg))
296 ins->opcode = OP_IADDCC;
297 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
300 if (COMPILE_LLVM (cfg))
302 ins->opcode = OP_ISUBCC;
303 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
306 if (COMPILE_LLVM (cfg))
308 ins->opcode = OP_ISUBCC;
309 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
312 case OP_ICONV_TO_OVF_I1:
313 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
314 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
315 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
316 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
317 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
320 case OP_ICONV_TO_OVF_I1_UN:
321 /* probe values between 0 to 127 */
322 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
323 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
324 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
327 case OP_ICONV_TO_OVF_U1:
328 case OP_ICONV_TO_OVF_U1_UN:
329 /* probe value to be within 0 to 255 */
330 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
331 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
332 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
335 case OP_ICONV_TO_OVF_I2:
336 /* Probe value to be within -32768 and 32767 */
337 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
338 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
339 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
340 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
341 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
344 case OP_ICONV_TO_OVF_I2_UN:
345 /* Convert uint value into short, value within 0 and 32767 */
346 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
347 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
348 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
351 case OP_ICONV_TO_OVF_U2:
352 case OP_ICONV_TO_OVF_U2_UN:
353 /* Probe value to be within 0 and 65535 */
354 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
355 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
356 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
359 case OP_ICONV_TO_OVF_U4:
360 case OP_ICONV_TO_OVF_I4_UN:
361 #if SIZEOF_VOID_P == 4
362 case OP_ICONV_TO_OVF_U:
363 case OP_ICONV_TO_OVF_I_UN:
365 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
366 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
367 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
372 case OP_ICONV_TO_OVF_I4:
373 case OP_ICONV_TO_OVF_U4_UN:
374 #if SIZEOF_VOID_P == 4
375 case OP_ICONV_TO_OVF_I:
376 case OP_ICONV_TO_OVF_U_UN:
378 ins->opcode = OP_MOVE;
381 #if SIZEOF_VOID_P == 8
382 ins->opcode = OP_SEXT_I4;
384 ins->opcode = OP_MOVE;
388 #if SIZEOF_VOID_P == 8
389 ins->opcode = OP_ZEXT_I4;
391 ins->opcode = OP_MOVE;
396 ins->opcode = OP_FMOVE;
399 case OP_FCONV_TO_OVF_I1_UN:
400 case OP_FCONV_TO_OVF_I2_UN:
401 case OP_FCONV_TO_OVF_I4_UN:
402 case OP_FCONV_TO_OVF_I8_UN:
403 case OP_FCONV_TO_OVF_U1_UN:
404 case OP_FCONV_TO_OVF_U2_UN:
405 case OP_FCONV_TO_OVF_U4_UN:
406 case OP_FCONV_TO_OVF_U8_UN:
407 case OP_FCONV_TO_OVF_I_UN:
408 case OP_FCONV_TO_OVF_U_UN:
409 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
410 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
414 MonoJitICallInfo *info;
416 #if SIZEOF_REGISTER == 8
417 if (decompose_long_opcode (cfg, ins, &repl))
420 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
424 info = mono_find_jit_opcode_emulation (ins->opcode);
429 /* Create dummy MonoInst's for the arguments */
430 g_assert (!info->sig->hasthis);
431 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
433 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
434 if (info->sig->param_count > 0) {
435 int sregs [MONO_MAX_SRC_REGS];
437 num_sregs = mono_inst_get_src_registers (ins, sregs);
438 g_assert (num_sregs == info->sig->param_count);
439 for (i = 0; i < num_sregs; ++i) {
440 MONO_INST_NEW (cfg, args [i], OP_ARG);
441 args [i]->dreg = sregs [i];
445 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
446 call->dreg = ins->dreg;
454 if (ins->opcode == OP_NOP) {
459 /* Use the last emitted instruction */
460 ins = cfg->cbb->last_ins;
463 g_assert (ins->dreg == dreg);
471 #if SIZEOF_REGISTER == 4
472 static int lbr_decomp [][2] = {
474 {OP_IBGT, OP_IBGE_UN}, /* BGE */
475 {OP_IBGT, OP_IBGT_UN}, /* BGT */
476 {OP_IBLT, OP_IBLE_UN}, /* BLE */
477 {OP_IBLT, OP_IBLT_UN}, /* BLT */
479 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
480 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
481 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
482 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
485 static int lcset_decomp [][2] = {
487 {OP_IBLT, OP_IBLE_UN}, /* CGT */
488 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
489 {OP_IBGT, OP_IBGE_UN}, /* CLT */
490 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
495 * mono_decompose_long_opts:
497 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
500 mono_decompose_long_opts (MonoCompile *cfg)
502 #if SIZEOF_REGISTER == 4
503 MonoBasicBlock *bb, *first_bb;
506 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
507 * needs to be able to handle long vregs.
510 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
513 * Create a dummy bblock and emit code into it so we can use the normal
514 * code generation macros.
516 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
519 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
520 MonoInst *tree = bb->code;
521 MonoInst *prev = NULL;
524 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
528 cfg->cbb->code = cfg->cbb->last_ins = NULL;
532 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
533 mono_arch_decompose_long_opts (cfg, tree);
536 switch (tree->opcode) {
538 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
539 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
544 case OP_LCONV_TO_OVF_U8_UN:
545 case OP_LCONV_TO_OVF_I8:
546 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
547 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
549 case OP_STOREI8_MEMBASE_REG:
550 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
551 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
553 case OP_LOADI8_MEMBASE:
554 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
555 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
558 case OP_ICONV_TO_I8: {
559 guint32 tmpreg = alloc_ireg (cfg);
563 * tmp = low > -1 ? 1: 0;
564 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
566 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
567 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
568 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
569 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
573 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
574 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
576 case OP_ICONV_TO_OVF_I8:
577 /* a signed 32 bit num always fits in a signed 64 bit one */
578 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
579 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
581 case OP_ICONV_TO_OVF_U8:
582 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
583 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
584 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
585 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
587 case OP_ICONV_TO_OVF_I8_UN:
588 case OP_ICONV_TO_OVF_U8_UN:
589 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
590 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
591 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
594 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
597 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
600 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
603 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
609 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
612 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
615 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
617 case OP_LCONV_TO_R_UN:
618 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
620 case OP_LCONV_TO_OVF_I1: {
621 MonoBasicBlock *is_negative, *end_label;
623 NEW_BBLOCK (cfg, is_negative);
624 NEW_BBLOCK (cfg, end_label);
626 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
627 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
628 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
629 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
631 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
632 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
635 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
636 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
637 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
640 MONO_START_BB (cfg, is_negative);
641 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
642 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
644 MONO_START_BB (cfg, end_label);
646 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
649 case OP_LCONV_TO_OVF_I1_UN:
650 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
651 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
653 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
654 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
655 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
656 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
657 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
659 case OP_LCONV_TO_OVF_U1:
660 case OP_LCONV_TO_OVF_U1_UN:
661 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
662 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
664 /* probe value to be within 0 to 255 */
665 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
666 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
667 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
669 case OP_LCONV_TO_OVF_I2: {
670 MonoBasicBlock *is_negative, *end_label;
672 NEW_BBLOCK (cfg, is_negative);
673 NEW_BBLOCK (cfg, end_label);
675 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
676 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
677 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
678 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
680 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
681 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
684 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
685 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
686 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
689 MONO_START_BB (cfg, is_negative);
690 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
691 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
692 MONO_START_BB (cfg, end_label);
694 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
697 case OP_LCONV_TO_OVF_I2_UN:
698 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
699 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
701 /* Probe value to be within -32768 and 32767 */
702 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
703 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
704 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
705 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
706 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
708 case OP_LCONV_TO_OVF_U2:
709 case OP_LCONV_TO_OVF_U2_UN:
710 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
711 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
713 /* Probe value to be within 0 and 65535 */
714 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
715 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
716 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
718 case OP_LCONV_TO_OVF_I4:
719 case OP_LCONV_TO_OVF_I:
720 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
722 case OP_LCONV_TO_OVF_U4:
723 case OP_LCONV_TO_OVF_U:
724 case OP_LCONV_TO_OVF_U4_UN:
725 case OP_LCONV_TO_OVF_U_UN:
726 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
727 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
728 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
730 case OP_LCONV_TO_OVF_I_UN:
731 case OP_LCONV_TO_OVF_I4_UN:
732 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
733 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
734 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
735 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
736 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
738 case OP_LCONV_TO_OVF_U8:
739 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
740 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
742 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
743 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
745 case OP_LCONV_TO_OVF_I8_UN:
746 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
747 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
749 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
750 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
754 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
755 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
758 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
759 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
763 /* ADC sets the condition code */
764 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
765 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
766 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
769 /* ADC sets the condition code */
770 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
771 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
772 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
775 /* SBB sets the condition code */
776 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
777 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
778 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
781 /* SBB sets the condition code */
782 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
783 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
784 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
787 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
788 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
791 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
792 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
795 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
796 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
799 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
800 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
803 /* Handled in mono_arch_decompose_long_opts () */
804 g_assert_not_reached ();
808 /* FIXME: Add OP_BIGMUL optimization */
812 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
813 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
816 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
817 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
820 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
821 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
824 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
825 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
828 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
829 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
832 if (tree->inst_c1 == 32) {
834 /* The original code had this comment: */
835 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
836 * later apply the speedup to the left shift as well
839 /* FIXME: Move this to the strength reduction pass */
840 /* just move the upper half to the lower and zero the high word */
841 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
842 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
846 if (tree->inst_c1 == 32) {
847 /* just move the lower half to the upper and zero the lower word */
848 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
849 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
854 MonoInst *next = tree->next;
858 switch (next->opcode) {
863 /* Branchless version based on gcc code */
864 d1 = alloc_ireg (cfg);
865 d2 = alloc_ireg (cfg);
866 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
867 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
868 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
869 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
870 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
871 next->opcode = OP_NOP;
882 /* Convert into three comparisons + branches */
883 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
884 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
885 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
886 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
887 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
888 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
889 next->opcode = OP_NOP;
894 /* Branchless version based on gcc code */
895 d1 = alloc_ireg (cfg);
896 d2 = alloc_ireg (cfg);
897 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
898 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
899 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
901 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
902 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
903 next->opcode = OP_NOP;
910 MonoBasicBlock *set_to_0, *set_to_1;
912 NEW_BBLOCK (cfg, set_to_0);
913 NEW_BBLOCK (cfg, set_to_1);
915 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
916 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
917 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
918 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
919 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
920 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
921 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
922 MONO_START_BB (cfg, set_to_1);
923 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
924 MONO_START_BB (cfg, set_to_0);
925 next->opcode = OP_NOP;
929 g_assert_not_reached ();
934 /* Not yet used, since lcompare is decomposed before local cprop */
935 case OP_LCOMPARE_IMM: {
936 MonoInst *next = tree->next;
937 guint32 low_imm = tree->inst_ls_word;
938 guint32 high_imm = tree->inst_ms_word;
939 int low_reg = tree->sreg1 + 1;
940 int high_reg = tree->sreg1 + 2;
944 switch (next->opcode) {
949 /* Branchless version based on gcc code */
950 d1 = alloc_ireg (cfg);
951 d2 = alloc_ireg (cfg);
952 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
953 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
954 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
955 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
956 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
957 next->opcode = OP_NOP;
969 /* Convert into three comparisons + branches */
970 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
971 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
972 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
973 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
974 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
975 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
976 next->opcode = OP_NOP;
981 /* Branchless version based on gcc code */
982 d1 = alloc_ireg (cfg);
983 d2 = alloc_ireg (cfg);
984 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
985 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
986 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
988 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
989 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
990 next->opcode = OP_NOP;
997 MonoBasicBlock *set_to_0, *set_to_1;
999 NEW_BBLOCK (cfg, set_to_0);
1000 NEW_BBLOCK (cfg, set_to_1);
1002 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1003 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1004 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1005 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1006 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1007 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1008 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1009 MONO_START_BB (cfg, set_to_1);
1010 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1011 MONO_START_BB (cfg, set_to_0);
1012 next->opcode = OP_NOP;
1016 g_assert_not_reached ();
1025 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1028 /* Replace the original instruction with the new code sequence */
1030 /* Ignore the new value of prev */
1032 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1034 /* Process the newly added ops again since they can be long ops too */
1040 first_bb->code = first_bb->last_ins = NULL;
1041 first_bb->in_count = first_bb->out_count = 0;
1042 cfg->cbb = first_bb;
1053 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1054 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1059 * mono_decompose_vtype_opts:
1061 * Decompose valuetype opcodes.
1064 mono_decompose_vtype_opts (MonoCompile *cfg)
1066 MonoBasicBlock *bb, *first_bb;
1069 * Using OP_V opcodes and decomposing them later have two main benefits:
1070 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1072 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1073 * enabling optimizations to work on vtypes too.
1074 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1075 * can be executed anytime. It should be executed as late as possible so vtype
1076 * opcodes can be optimized by the other passes.
1077 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1078 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1080 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1081 * when OP_VMOVE opcodes are decomposed.
1085 * Vregs have no associated type information, so we store the type of the vregs
1090 * Create a dummy bblock and emit code into it so we can use the normal
1091 * code generation macros.
1093 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1094 first_bb = cfg->cbb;
1096 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1098 MonoInst *prev = NULL;
1099 MonoInst *src_var, *dest_var, *src, *dest;
1103 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1105 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1111 for (ins = bb->code; ins; ins = ins->next) {
1112 switch (ins->opcode) {
1114 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1115 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1117 g_assert (ins->klass);
1120 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1123 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1126 if (src_var->backend.is_pinvoke)
1127 dest_var->backend.is_pinvoke = 1;
1129 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1130 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1132 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1136 g_assert (ins->klass);
1138 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1139 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1141 if (cfg->compute_gc_maps) {
1145 * Tell the GC map code that the vtype is considered live after
1146 * the initialization.
1148 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1149 tmp->inst_c1 = ins->dreg;
1150 MONO_ADD_INS (cfg->cbb, tmp);
1153 case OP_STOREV_MEMBASE: {
1154 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1157 g_assert (ins->klass);
1158 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1161 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1163 dreg = alloc_preg (cfg);
1164 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1165 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1168 case OP_LOADV_MEMBASE: {
1169 g_assert (ins->klass);
1171 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1175 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1177 dreg = alloc_preg (cfg);
1178 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1179 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1180 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1183 case OP_OUTARG_VT: {
1184 g_assert (ins->klass);
1186 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1188 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1189 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1191 mono_arch_emit_outarg_vt (cfg, ins, src);
1193 /* This might be decomposed into other vtype opcodes */
1197 case OP_OUTARG_VTRETADDR: {
1198 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1200 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1202 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1203 // FIXME: src_var->backend.is_pinvoke ?
1205 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1206 src->dreg = ins->dreg;
1211 case OP_VCALL_MEMBASE: {
1212 MonoCallInst *call = (MonoCallInst*)ins;
1215 if (call->vret_in_reg) {
1216 MonoCallInst *call2;
1218 /* Replace the vcall with an integer call */
1219 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1220 memcpy (call2, call, sizeof (MonoCallInst));
1221 switch (ins->opcode) {
1223 call2->inst.opcode = OP_CALL;
1226 call2->inst.opcode = OP_CALL_REG;
1228 case OP_VCALL_MEMBASE:
1229 call2->inst.opcode = OP_CALL_MEMBASE;
1232 call2->inst.dreg = alloc_preg (cfg);
1233 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1235 /* Compute the vtype location */
1236 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1238 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1239 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1241 /* Save the result */
1242 if (dest_var->backend.is_pinvoke)
1243 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1245 size = mono_type_size (dest_var->inst_vtype, NULL);
1248 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1251 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1255 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1261 #if SIZEOF_REGISTER == 4
1263 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1264 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1266 switch (call2->inst.opcode) {
1268 call2->inst.opcode = OP_LCALL;
1271 call2->inst.opcode = OP_LCALL_REG;
1273 case OP_CALL_MEMBASE:
1274 call2->inst.opcode = OP_LCALL_MEMBASE;
1277 call2->inst.dreg = alloc_lreg (cfg);
1278 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1279 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1281 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1285 /* This assumes the vtype is sizeof (gpointer) long */
1286 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1290 switch (ins->opcode) {
1292 ins->opcode = OP_VCALL2;
1295 ins->opcode = OP_VCALL2_REG;
1297 case OP_VCALL_MEMBASE:
1298 ins->opcode = OP_VCALL2_MEMBASE;
1309 g_assert (cfg->cbb == first_bb);
1311 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1312 /* Replace the original instruction with the new code sequence */
1314 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1315 first_bb->code = first_bb->last_ins = NULL;
1316 first_bb->in_count = first_bb->out_count = 0;
1317 cfg->cbb = first_bb;
1324 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1328 inline static MonoInst *
1329 mono_get_domainvar (MonoCompile *cfg)
1331 if (!cfg->domainvar)
1332 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1333 return cfg->domainvar;
1337 * mono_decompose_array_access_opts:
1339 * Decompose array access opcodes.
1342 mono_decompose_array_access_opts (MonoCompile *cfg)
1344 MonoBasicBlock *bb, *first_bb;
1347 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1348 * can be executed anytime. It should be run before decompose_long
1352 * Create a dummy bblock and emit code into it so we can use the normal
1353 * code generation macros.
1355 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1356 first_bb = cfg->cbb;
1358 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1360 MonoInst *prev = NULL;
1362 MonoInst *iargs [3];
1365 if (!bb->has_array_access)
1368 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1370 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1376 for (ins = bb->code; ins; ins = ins->next) {
1377 switch (ins->opcode) {
1379 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1380 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_CONSTANT_LOAD);
1381 MONO_ADD_INS (cfg->cbb, dest);
1383 case OP_BOUNDS_CHECK:
1384 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1385 if (COMPILE_LLVM (cfg))
1386 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1388 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1391 if (cfg->opt & MONO_OPT_SHARED) {
1392 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1393 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1394 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1395 iargs [2]->dreg = ins->sreg1;
1397 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1398 dest->dreg = ins->dreg;
1400 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1401 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1402 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1404 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1405 NEW_VTABLECONST (cfg, iargs [0], vtable);
1406 MONO_ADD_INS (cfg->cbb, iargs [0]);
1407 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1408 iargs [1]->dreg = ins->sreg1;
1411 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1413 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1414 dest->dreg = ins->dreg;
1418 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1419 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
1425 g_assert (cfg->cbb == first_bb);
1427 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1428 /* Replace the original instruction with the new code sequence */
1430 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1431 first_bb->code = first_bb->last_ins = NULL;
1432 first_bb->in_count = first_bb->out_count = 0;
1433 cfg->cbb = first_bb;
1440 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1450 #ifdef MONO_ARCH_SOFT_FLOAT
1453 * mono_decompose_soft_float:
1455 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1456 * similar to long support on 32 bit platforms. 32 bit float values require special
1457 * handling when used as locals, arguments, and in calls.
1458 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1461 mono_decompose_soft_float (MonoCompile *cfg)
1463 MonoBasicBlock *bb, *first_bb;
1466 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1470 * Create a dummy bblock and emit code into it so we can use the normal
1471 * code generation macros.
1473 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1474 first_bb = cfg->cbb;
1476 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1478 MonoInst *prev = NULL;
1481 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1483 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1489 for (ins = bb->code; ins; ins = ins->next) {
1490 const char *spec = INS_INFO (ins->opcode);
1492 /* Most fp operations are handled automatically by opcode emulation */
1494 switch (ins->opcode) {
1497 d.vald = *(double*)ins->inst_p0;
1498 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1503 /* We load the r8 value */
1504 d.vald = *(float*)ins->inst_p0;
1505 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1509 ins->opcode = OP_LMOVE;
1512 ins->opcode = OP_MOVE;
1513 ins->sreg1 = ins->sreg1 + 1;
1516 ins->opcode = OP_MOVE;
1517 ins->sreg1 = ins->sreg1 + 2;
1520 int reg = ins->sreg1;
1522 ins->opcode = OP_SETLRET;
1524 ins->sreg1 = reg + 1;
1525 ins->sreg2 = reg + 2;
1528 case OP_LOADR8_MEMBASE:
1529 ins->opcode = OP_LOADI8_MEMBASE;
1531 case OP_STORER8_MEMBASE_REG:
1532 ins->opcode = OP_STOREI8_MEMBASE_REG;
1534 case OP_STORER4_MEMBASE_REG: {
1535 MonoInst *iargs [2];
1538 /* Arg 1 is the double value */
1539 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1540 iargs [0]->dreg = ins->sreg1;
1542 /* Arg 2 is the address to store to */
1543 addr_reg = mono_alloc_preg (cfg);
1544 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1545 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1549 case OP_LOADR4_MEMBASE: {
1550 MonoInst *iargs [1];
1554 addr_reg = mono_alloc_preg (cfg);
1555 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1556 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1557 conv->dreg = ins->dreg;
1562 case OP_FCALL_MEMBASE: {
1563 MonoCallInst *call = (MonoCallInst*)ins;
1564 if (call->signature->ret->type == MONO_TYPE_R4) {
1565 MonoCallInst *call2;
1566 MonoInst *iargs [1];
1570 /* Convert the call into a call returning an int */
1571 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1572 memcpy (call2, call, sizeof (MonoCallInst));
1573 switch (ins->opcode) {
1575 call2->inst.opcode = OP_CALL;
1578 call2->inst.opcode = OP_CALL_REG;
1580 case OP_FCALL_MEMBASE:
1581 call2->inst.opcode = OP_CALL_MEMBASE;
1584 g_assert_not_reached ();
1586 call2->inst.dreg = mono_alloc_ireg (cfg);
1587 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1589 /* Remap OUTARG_VT instructions referencing this call */
1590 for (l = call->outarg_vts; l; l = l->next)
1591 ((MonoInst*)(l->data))->inst_p0 = call2;
1593 /* FIXME: Optimize this */
1595 /* Emit an r4->r8 conversion */
1596 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1597 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1598 conv->dreg = ins->dreg;
1600 /* The call sequence might include fp ins */
1603 switch (ins->opcode) {
1605 ins->opcode = OP_LCALL;
1608 ins->opcode = OP_LCALL_REG;
1610 case OP_FCALL_MEMBASE:
1611 ins->opcode = OP_LCALL_MEMBASE;
1614 g_assert_not_reached ();
1620 MonoJitICallInfo *info;
1621 MonoInst *iargs [2];
1622 MonoInst *call, *cmp, *br;
1624 /* Convert fcompare+fbcc to icall+icompare+beq */
1627 /* The branch might be optimized away */
1632 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1634 /* The branch might be optimized away */
1639 /* Create dummy MonoInst's for the arguments */
1640 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1641 iargs [0]->dreg = ins->sreg1;
1642 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1643 iargs [1]->dreg = ins->sreg2;
1645 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1647 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1648 cmp->sreg1 = call->dreg;
1650 MONO_ADD_INS (cfg->cbb, cmp);
1652 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1653 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1654 br->inst_true_bb = ins->next->inst_true_bb;
1655 br->inst_false_bb = ins->next->inst_false_bb;
1656 MONO_ADD_INS (cfg->cbb, br);
1658 /* The call sequence might include fp ins */
1661 /* Skip fbcc or fccc */
1662 NULLIFY_INS (ins->next);
1670 MonoJitICallInfo *info;
1671 MonoInst *iargs [2];
1674 /* Convert fccc to icall+icompare+iceq */
1676 info = mono_find_jit_opcode_emulation (ins->opcode);
1679 /* Create dummy MonoInst's for the arguments */
1680 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1681 iargs [0]->dreg = ins->sreg1;
1682 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1683 iargs [1]->dreg = ins->sreg2;
1685 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1687 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1688 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1690 /* The call sequence might include fp ins */
1695 MonoInst *iargs [2];
1696 MonoInst *call, *cmp;
1698 /* Convert to icall+icompare+cond_exc+move */
1700 /* Create dummy MonoInst's for the arguments */
1701 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1702 iargs [0]->dreg = ins->sreg1;
1704 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1706 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1707 cmp->sreg1 = call->dreg;
1709 MONO_ADD_INS (cfg->cbb, cmp);
1711 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1713 /* Do the assignment if the value is finite */
1714 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1720 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1721 mono_print_ins (ins);
1722 g_assert_not_reached ();
1727 g_assert (cfg->cbb == first_bb);
1729 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1730 /* Replace the original instruction with the new code sequence */
1732 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1733 first_bb->code = first_bb->last_ins = NULL;
1734 first_bb->in_count = first_bb->out_count = 0;
1735 cfg->cbb = first_bb;
1742 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1745 mono_decompose_long_opts (cfg);
1750 #endif /* DISABLE_JIT */