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 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
41 ins->opcode = OP_MOVE;
44 ins->opcode = OP_SEXT_I4;
47 ins->opcode = OP_ZEXT_I4;
50 /* Clean out the upper word */
51 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
55 if (COMPILE_LLVM (cfg))
57 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
58 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
62 if (COMPILE_LLVM (cfg))
64 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
65 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
68 #ifndef __mono_ppc64__
70 if (COMPILE_LLVM (cfg))
72 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
73 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
77 if (COMPILE_LLVM (cfg))
79 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
80 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
85 case OP_ICONV_TO_OVF_I8:
86 case OP_ICONV_TO_OVF_I:
87 ins->opcode = OP_SEXT_I4;
89 case OP_ICONV_TO_OVF_U8:
90 case OP_ICONV_TO_OVF_U:
91 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
92 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
93 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
96 case OP_ICONV_TO_OVF_I8_UN:
97 case OP_ICONV_TO_OVF_U8_UN:
98 case OP_ICONV_TO_OVF_I_UN:
99 case OP_ICONV_TO_OVF_U_UN:
100 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
101 /* Clean out the upper word */
102 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
105 case OP_LCONV_TO_OVF_I1:
106 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
107 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
108 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
109 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
110 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
113 case OP_LCONV_TO_OVF_I1_UN:
114 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
115 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
116 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
119 case OP_LCONV_TO_OVF_U1:
120 /* probe value to be within 0 to 255 */
121 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
122 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
123 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
126 case OP_LCONV_TO_OVF_U1_UN:
127 /* probe value to be within 0 to 255 */
128 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
129 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
130 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
133 case OP_LCONV_TO_OVF_I2:
134 /* Probe value to be within -32768 and 32767 */
135 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
136 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
137 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
138 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
139 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
142 case OP_LCONV_TO_OVF_I2_UN:
143 /* Probe value to be within 0 and 32767 */
144 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
145 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
146 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
149 case OP_LCONV_TO_OVF_U2:
150 /* Probe value to be within 0 and 65535 */
151 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
152 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
153 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
156 case OP_LCONV_TO_OVF_U2_UN:
157 /* Probe value to be within 0 and 65535 */
158 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
159 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
160 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
163 case OP_LCONV_TO_OVF_I4:
164 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
165 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
166 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
167 #if SIZEOF_REGISTER == 8
168 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
170 g_assert (COMPILE_LLVM (cfg));
171 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
173 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
174 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
177 case OP_LCONV_TO_OVF_I4_UN:
178 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
179 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
180 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
183 case OP_LCONV_TO_OVF_U4:
184 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
185 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
186 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
187 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
188 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
191 case OP_LCONV_TO_OVF_U4_UN:
192 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
193 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
194 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
197 case OP_LCONV_TO_OVF_I:
198 case OP_LCONV_TO_OVF_U_UN:
199 case OP_LCONV_TO_OVF_U8_UN:
200 case OP_LCONV_TO_OVF_I8:
201 ins->opcode = OP_MOVE;
203 case OP_LCONV_TO_OVF_I_UN:
204 case OP_LCONV_TO_OVF_I8_UN:
205 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
206 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
207 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
210 case OP_LCONV_TO_OVF_U8:
211 case OP_LCONV_TO_OVF_U:
212 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
213 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
214 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
226 * mono_decompose_opcode:
228 * Decompose complex opcodes into ones closer to opcodes supported by
229 * the given architecture.
230 * Returns a MonoInst which represents the result of the decomposition, and can
231 * be pushed on the IL stack. This is needed because the original instruction is
233 * Sets the cfg exception if an opcode is not supported.
236 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
238 MonoInst *repl = NULL;
239 int type = ins->type;
240 int dreg = ins->dreg;
242 /* FIXME: Instead of = NOP, don't emit the original ins at all */
244 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
245 mono_arch_decompose_opts (cfg, ins);
249 * The code below assumes that we are called immediately after emitting
250 * ins. This means we can emit code using the normal code generation
253 switch (ins->opcode) {
254 /* this doesn't make sense on ppc and other architectures */
255 #if !defined(MONO_ARCH_NO_IOV_CHECK)
257 if (COMPILE_LLVM (cfg))
259 ins->opcode = OP_IADDCC;
260 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
263 if (COMPILE_LLVM (cfg))
265 ins->opcode = OP_IADDCC;
266 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
269 if (COMPILE_LLVM (cfg))
271 ins->opcode = OP_ISUBCC;
272 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
275 if (COMPILE_LLVM (cfg))
277 ins->opcode = OP_ISUBCC;
278 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
281 case OP_ICONV_TO_OVF_I1:
282 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
283 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
284 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
285 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
286 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
289 case OP_ICONV_TO_OVF_I1_UN:
290 /* probe values between 0 to 127 */
291 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
292 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
293 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
296 case OP_ICONV_TO_OVF_U1:
297 case OP_ICONV_TO_OVF_U1_UN:
298 /* probe value to be within 0 to 255 */
299 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
300 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
301 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
304 case OP_ICONV_TO_OVF_I2:
305 /* Probe value to be within -32768 and 32767 */
306 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
307 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
308 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
309 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
310 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
313 case OP_ICONV_TO_OVF_I2_UN:
314 /* Convert uint value into short, value within 0 and 32767 */
315 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
316 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
317 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
320 case OP_ICONV_TO_OVF_U2:
321 case OP_ICONV_TO_OVF_U2_UN:
322 /* Probe value to be within 0 and 65535 */
323 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
324 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
325 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
328 case OP_ICONV_TO_OVF_U4:
329 case OP_ICONV_TO_OVF_I4_UN:
330 #if SIZEOF_REGISTER == 4
331 case OP_ICONV_TO_OVF_U:
332 case OP_ICONV_TO_OVF_I_UN:
334 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
335 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
336 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
341 case OP_ICONV_TO_OVF_I4:
342 case OP_ICONV_TO_OVF_U4_UN:
343 #if SIZEOF_REGISTER == 4
344 case OP_ICONV_TO_OVF_I:
345 case OP_ICONV_TO_OVF_U_UN:
347 ins->opcode = OP_MOVE;
350 #if SIZEOF_REGISTER == 8
351 ins->opcode = OP_SEXT_I4;
353 ins->opcode = OP_MOVE;
357 #if SIZEOF_REGISTER == 8
358 ins->opcode = OP_ZEXT_I4;
360 ins->opcode = OP_MOVE;
365 ins->opcode = OP_FMOVE;
368 case OP_FCONV_TO_OVF_I1_UN:
369 case OP_FCONV_TO_OVF_I2_UN:
370 case OP_FCONV_TO_OVF_I4_UN:
371 case OP_FCONV_TO_OVF_I8_UN:
372 case OP_FCONV_TO_OVF_U1_UN:
373 case OP_FCONV_TO_OVF_U2_UN:
374 case OP_FCONV_TO_OVF_U4_UN:
375 case OP_FCONV_TO_OVF_U8_UN:
376 case OP_FCONV_TO_OVF_I_UN:
377 case OP_FCONV_TO_OVF_U_UN:
378 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
379 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
383 MonoJitICallInfo *info;
385 #if SIZEOF_REGISTER == 8
386 if (decompose_long_opcode (cfg, ins, &repl))
389 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
393 info = mono_find_jit_opcode_emulation (ins->opcode);
398 /* Create dummy MonoInst's for the arguments */
399 g_assert (!info->sig->hasthis);
400 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
402 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
403 if (info->sig->param_count > 0) {
404 int sregs [MONO_MAX_SRC_REGS];
406 num_sregs = mono_inst_get_src_registers (ins, sregs);
407 g_assert (num_sregs == info->sig->param_count);
408 for (i = 0; i < num_sregs; ++i) {
409 MONO_INST_NEW (cfg, args [i], OP_ARG);
410 args [i]->dreg = sregs [i];
414 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
415 call->dreg = ins->dreg;
423 if (ins->opcode == OP_NOP) {
428 /* Use the last emitted instruction */
429 ins = cfg->cbb->last_ins;
432 g_assert (ins->dreg == dreg);
440 #if SIZEOF_REGISTER == 4
441 static int lbr_decomp [][2] = {
443 {OP_IBGT, OP_IBGE_UN}, /* BGE */
444 {OP_IBGT, OP_IBGT_UN}, /* BGT */
445 {OP_IBLT, OP_IBLE_UN}, /* BLE */
446 {OP_IBLT, OP_IBLT_UN}, /* BLT */
448 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
449 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
450 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
451 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
454 static int lcset_decomp [][2] = {
456 {OP_IBLT, OP_IBLE_UN}, /* CGT */
457 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
458 {OP_IBGT, OP_IBGE_UN}, /* CLT */
459 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
464 * mono_decompose_long_opts:
466 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
469 mono_decompose_long_opts (MonoCompile *cfg)
471 #if SIZEOF_REGISTER == 4
472 MonoBasicBlock *bb, *first_bb;
475 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
476 * needs to be able to handle long vregs.
479 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
482 * Create a dummy bblock and emit code into it so we can use the normal
483 * code generation macros.
485 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
488 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
489 MonoInst *tree = bb->code;
490 MonoInst *prev = NULL;
493 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
497 cfg->cbb->code = cfg->cbb->last_ins = NULL;
501 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
502 mono_arch_decompose_long_opts (cfg, tree);
505 switch (tree->opcode) {
507 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
508 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
513 case OP_LCONV_TO_OVF_U8_UN:
514 case OP_LCONV_TO_OVF_I8:
515 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
516 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
518 case OP_STOREI8_MEMBASE_REG:
519 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
520 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
522 case OP_LOADI8_MEMBASE:
523 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
524 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
527 case OP_ICONV_TO_I8: {
528 guint32 tmpreg = alloc_ireg (cfg);
532 * tmp = low > -1 ? 1: 0;
533 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
535 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
536 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
537 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
538 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
542 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
543 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
545 case OP_ICONV_TO_OVF_I8:
546 /* a signed 32 bit num always fits in a signed 64 bit one */
547 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
548 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
550 case OP_ICONV_TO_OVF_U8:
551 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
552 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
553 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
554 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
556 case OP_ICONV_TO_OVF_I8_UN:
557 case OP_ICONV_TO_OVF_U8_UN:
558 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
559 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
560 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
563 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
566 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
569 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
572 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
578 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
581 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
584 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
586 case OP_LCONV_TO_R_UN:
587 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
589 case OP_LCONV_TO_OVF_I1: {
590 MonoBasicBlock *is_negative, *end_label;
592 NEW_BBLOCK (cfg, is_negative);
593 NEW_BBLOCK (cfg, end_label);
595 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
596 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
597 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
598 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
600 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
601 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
604 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
605 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
606 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
609 MONO_START_BB (cfg, is_negative);
610 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
611 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
613 MONO_START_BB (cfg, end_label);
615 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
618 case OP_LCONV_TO_OVF_I1_UN:
619 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
620 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
622 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
623 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
624 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
625 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
626 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
628 case OP_LCONV_TO_OVF_U1:
629 case OP_LCONV_TO_OVF_U1_UN:
630 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
631 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
633 /* probe value to be within 0 to 255 */
634 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
635 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
636 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
638 case OP_LCONV_TO_OVF_I2: {
639 MonoBasicBlock *is_negative, *end_label;
641 NEW_BBLOCK (cfg, is_negative);
642 NEW_BBLOCK (cfg, end_label);
644 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
645 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
646 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
647 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
649 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
650 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
653 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
654 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
655 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
658 MONO_START_BB (cfg, is_negative);
659 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
660 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
661 MONO_START_BB (cfg, end_label);
663 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
666 case OP_LCONV_TO_OVF_I2_UN:
667 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
668 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
670 /* Probe value to be within -32768 and 32767 */
671 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
672 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
673 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
674 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
675 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
677 case OP_LCONV_TO_OVF_U2:
678 case OP_LCONV_TO_OVF_U2_UN:
679 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
680 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
682 /* Probe value to be within 0 and 65535 */
683 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
684 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
685 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
687 case OP_LCONV_TO_OVF_I4:
688 case OP_LCONV_TO_OVF_I:
689 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
691 case OP_LCONV_TO_OVF_U4:
692 case OP_LCONV_TO_OVF_U:
693 case OP_LCONV_TO_OVF_U4_UN:
694 case OP_LCONV_TO_OVF_U_UN:
695 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
696 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
697 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
699 case OP_LCONV_TO_OVF_I_UN:
700 case OP_LCONV_TO_OVF_I4_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");
703 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
704 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
705 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
707 case OP_LCONV_TO_OVF_U8:
708 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
709 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
711 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
712 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
714 case OP_LCONV_TO_OVF_I8_UN:
715 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
716 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
718 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
719 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
723 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
724 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
727 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
728 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
732 /* ADC sets the condition code */
733 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
734 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
735 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
738 /* ADC sets the condition code */
739 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
740 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
741 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
744 /* SBB sets the condition code */
745 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
746 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
747 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
750 /* SBB sets the condition code */
751 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
752 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
753 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
756 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
757 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
760 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
761 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
764 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
765 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
768 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
769 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
772 /* Handled in mono_arch_decompose_long_opts () */
773 g_assert_not_reached ();
777 /* FIXME: Add OP_BIGMUL optimization */
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
785 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
786 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
789 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
790 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
793 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
794 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
797 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
798 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
801 if (tree->inst_c1 == 32) {
803 /* The original code had this comment: */
804 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
805 * later apply the speedup to the left shift as well
808 /* FIXME: Move this to the strength reduction pass */
809 /* just move the upper half to the lower and zero the high word */
810 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
811 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
815 if (tree->inst_c1 == 32) {
816 /* just move the lower half to the upper and zero the lower word */
817 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
818 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
823 MonoInst *next = tree->next;
827 switch (next->opcode) {
832 /* Branchless version based on gcc code */
833 d1 = alloc_ireg (cfg);
834 d2 = alloc_ireg (cfg);
835 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
836 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
837 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
838 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
839 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
840 next->opcode = OP_NOP;
851 /* Convert into three comparisons + branches */
852 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
853 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
854 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
855 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
856 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
857 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
858 next->opcode = OP_NOP;
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);
870 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
871 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
872 next->opcode = OP_NOP;
879 MonoBasicBlock *set_to_0, *set_to_1;
881 NEW_BBLOCK (cfg, set_to_0);
882 NEW_BBLOCK (cfg, set_to_1);
884 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
885 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
886 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
887 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
888 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
889 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
890 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
891 MONO_START_BB (cfg, set_to_1);
892 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
893 MONO_START_BB (cfg, set_to_0);
894 next->opcode = OP_NOP;
898 g_assert_not_reached ();
903 /* Not yet used, since lcompare is decomposed before local cprop */
904 case OP_LCOMPARE_IMM: {
905 MonoInst *next = tree->next;
906 guint32 low_imm = tree->inst_ls_word;
907 guint32 high_imm = tree->inst_ms_word;
908 int low_reg = tree->sreg1 + 1;
909 int high_reg = tree->sreg1 + 2;
913 switch (next->opcode) {
918 /* Branchless version based on gcc code */
919 d1 = alloc_ireg (cfg);
920 d2 = alloc_ireg (cfg);
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
922 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
923 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
925 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
926 next->opcode = OP_NOP;
938 /* Convert into three comparisons + branches */
939 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
940 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
942 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
943 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
944 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
945 next->opcode = OP_NOP;
950 /* Branchless version based on gcc code */
951 d1 = alloc_ireg (cfg);
952 d2 = alloc_ireg (cfg);
953 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
954 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
955 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
957 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
958 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
959 next->opcode = OP_NOP;
966 MonoBasicBlock *set_to_0, *set_to_1;
968 NEW_BBLOCK (cfg, set_to_0);
969 NEW_BBLOCK (cfg, set_to_1);
971 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
972 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
973 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
974 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
975 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
976 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
977 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
978 MONO_START_BB (cfg, set_to_1);
979 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
980 MONO_START_BB (cfg, set_to_0);
981 next->opcode = OP_NOP;
985 g_assert_not_reached ();
994 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
997 /* Replace the original instruction with the new code sequence */
999 /* Ignore the new value of prev */
1001 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1003 /* Process the newly added ops again since they can be long ops too */
1009 first_bb->code = first_bb->last_ins = NULL;
1010 first_bb->in_count = first_bb->out_count = 0;
1011 cfg->cbb = first_bb;
1022 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1023 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1028 * mono_decompose_vtype_opts:
1030 * Decompose valuetype opcodes.
1033 mono_decompose_vtype_opts (MonoCompile *cfg)
1035 MonoBasicBlock *bb, *first_bb;
1038 * Using OP_V opcodes and decomposing them later have two main benefits:
1039 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1041 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1042 * enabling optimizations to work on vtypes too.
1043 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1044 * can be executed anytime. It should be executed as late as possible so vtype
1045 * opcodes can be optimized by the other passes.
1046 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1047 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1049 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1050 * when OP_VMOVE opcodes are decomposed.
1054 * Vregs have no associated type information, so we store the type of the vregs
1059 * Create a dummy bblock and emit code into it so we can use the normal
1060 * code generation macros.
1062 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1063 first_bb = cfg->cbb;
1065 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1067 MonoInst *prev = NULL;
1068 MonoInst *src_var, *dest_var, *src, *dest;
1072 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1074 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1080 for (ins = bb->code; ins; ins = ins->next) {
1081 switch (ins->opcode) {
1083 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1084 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1086 g_assert (ins->klass);
1089 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1092 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1095 if (src_var->backend.is_pinvoke)
1096 dest_var->backend.is_pinvoke = 1;
1098 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1099 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1101 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1105 g_assert (ins->klass);
1107 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1108 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1110 if (cfg->compute_gc_maps) {
1114 * Tell the GC map code that the vtype is considered live after
1115 * the initialization.
1117 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1118 tmp->inst_c1 = ins->dreg;
1119 MONO_ADD_INS (cfg->cbb, tmp);
1122 case OP_STOREV_MEMBASE: {
1123 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1126 g_assert (ins->klass);
1127 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1130 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1132 dreg = alloc_preg (cfg);
1133 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1134 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1137 case OP_LOADV_MEMBASE: {
1138 g_assert (ins->klass);
1140 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1143 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1145 dreg = alloc_preg (cfg);
1146 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1147 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1148 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1151 case OP_OUTARG_VT: {
1152 g_assert (ins->klass);
1154 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1156 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1157 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1159 mono_arch_emit_outarg_vt (cfg, ins, src);
1161 /* This might be decomposed into other vtype opcodes */
1165 case OP_OUTARG_VTRETADDR: {
1166 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1168 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1170 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1171 // FIXME: src_var->backend.is_pinvoke ?
1173 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1174 src->dreg = ins->dreg;
1179 case OP_VCALL_MEMBASE: {
1180 MonoCallInst *call = (MonoCallInst*)ins;
1183 if (call->vret_in_reg) {
1184 MonoCallInst *call2;
1186 /* Replace the vcall with an integer call */
1187 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1188 memcpy (call2, call, sizeof (MonoCallInst));
1189 switch (ins->opcode) {
1191 call2->inst.opcode = OP_CALL;
1194 call2->inst.opcode = OP_CALL_REG;
1196 case OP_VCALL_MEMBASE:
1197 call2->inst.opcode = OP_CALL_MEMBASE;
1200 call2->inst.dreg = alloc_preg (cfg);
1201 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1203 /* Compute the vtype location */
1204 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1206 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1207 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1209 /* Save the result */
1210 if (dest_var->backend.is_pinvoke)
1211 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1213 size = mono_type_size (dest_var->inst_vtype, NULL);
1216 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1219 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1222 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1225 #if SIZEOF_REGISTER == 4
1227 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1228 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1230 switch (call2->inst.opcode) {
1232 call2->inst.opcode = OP_LCALL;
1235 call2->inst.opcode = OP_LCALL_REG;
1237 case OP_CALL_MEMBASE:
1238 call2->inst.opcode = OP_LCALL_MEMBASE;
1241 call2->inst.dreg = alloc_lreg (cfg);
1242 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1243 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1245 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1249 /* This assumes the vtype is sizeof (gpointer) long */
1250 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1254 switch (ins->opcode) {
1256 ins->opcode = OP_VCALL2;
1259 ins->opcode = OP_VCALL2_REG;
1261 case OP_VCALL_MEMBASE:
1262 ins->opcode = OP_VCALL2_MEMBASE;
1273 g_assert (cfg->cbb == first_bb);
1275 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1276 /* Replace the original instruction with the new code sequence */
1278 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1279 first_bb->code = first_bb->last_ins = NULL;
1280 first_bb->in_count = first_bb->out_count = 0;
1281 cfg->cbb = first_bb;
1288 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1292 inline static MonoInst *
1293 mono_get_domainvar (MonoCompile *cfg)
1295 if (!cfg->domainvar)
1296 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1297 return cfg->domainvar;
1301 * mono_decompose_array_access_opts:
1303 * Decompose array access opcodes.
1306 mono_decompose_array_access_opts (MonoCompile *cfg)
1308 MonoBasicBlock *bb, *first_bb;
1311 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1312 * can be executed anytime. It should be run before decompose_long
1316 * Create a dummy bblock and emit code into it so we can use the normal
1317 * code generation macros.
1319 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1320 first_bb = cfg->cbb;
1322 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1324 MonoInst *prev = NULL;
1326 MonoInst *iargs [3];
1329 if (!bb->has_array_access)
1332 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1334 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1340 for (ins = bb->code; ins; ins = ins->next) {
1341 switch (ins->opcode) {
1343 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1344 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_CONSTANT_LOAD);
1345 MONO_ADD_INS (cfg->cbb, dest);
1347 case OP_BOUNDS_CHECK:
1348 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1349 if (COMPILE_LLVM (cfg))
1350 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1352 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1355 if (cfg->opt & MONO_OPT_SHARED) {
1356 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1357 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1358 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1359 iargs [2]->dreg = ins->sreg1;
1361 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1362 dest->dreg = ins->dreg;
1364 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1365 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1367 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1368 NEW_VTABLECONST (cfg, iargs [0], vtable);
1369 MONO_ADD_INS (cfg->cbb, iargs [0]);
1370 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1371 iargs [1]->dreg = ins->sreg1;
1374 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1376 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1377 dest->dreg = ins->dreg;
1381 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1382 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
1388 g_assert (cfg->cbb == first_bb);
1390 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1391 /* Replace the original instruction with the new code sequence */
1393 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1394 first_bb->code = first_bb->last_ins = NULL;
1395 first_bb->in_count = first_bb->out_count = 0;
1396 cfg->cbb = first_bb;
1403 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1413 #ifdef MONO_ARCH_SOFT_FLOAT
1416 * mono_decompose_soft_float:
1418 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1419 * similar to long support on 32 bit platforms. 32 bit float values require special
1420 * handling when used as locals, arguments, and in calls.
1421 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1424 mono_decompose_soft_float (MonoCompile *cfg)
1426 MonoBasicBlock *bb, *first_bb;
1429 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1433 * Create a dummy bblock and emit code into it so we can use the normal
1434 * code generation macros.
1436 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1437 first_bb = cfg->cbb;
1439 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1441 MonoInst *prev = NULL;
1444 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1446 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1452 for (ins = bb->code; ins; ins = ins->next) {
1453 const char *spec = INS_INFO (ins->opcode);
1455 /* Most fp operations are handled automatically by opcode emulation */
1457 switch (ins->opcode) {
1460 d.vald = *(double*)ins->inst_p0;
1461 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1466 /* We load the r8 value */
1467 d.vald = *(float*)ins->inst_p0;
1468 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1472 ins->opcode = OP_LMOVE;
1475 ins->opcode = OP_MOVE;
1476 ins->sreg1 = ins->sreg1 + 1;
1479 ins->opcode = OP_MOVE;
1480 ins->sreg1 = ins->sreg1 + 2;
1483 int reg = ins->sreg1;
1485 ins->opcode = OP_SETLRET;
1487 ins->sreg1 = reg + 1;
1488 ins->sreg2 = reg + 2;
1491 case OP_LOADR8_MEMBASE:
1492 ins->opcode = OP_LOADI8_MEMBASE;
1494 case OP_STORER8_MEMBASE_REG:
1495 ins->opcode = OP_STOREI8_MEMBASE_REG;
1497 case OP_STORER4_MEMBASE_REG: {
1498 MonoInst *iargs [2];
1501 /* Arg 1 is the double value */
1502 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1503 iargs [0]->dreg = ins->sreg1;
1505 /* Arg 2 is the address to store to */
1506 addr_reg = mono_alloc_preg (cfg);
1507 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1508 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1512 case OP_LOADR4_MEMBASE: {
1513 MonoInst *iargs [1];
1517 addr_reg = mono_alloc_preg (cfg);
1518 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1519 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1520 conv->dreg = ins->dreg;
1525 case OP_FCALL_MEMBASE: {
1526 MonoCallInst *call = (MonoCallInst*)ins;
1527 if (call->signature->ret->type == MONO_TYPE_R4) {
1528 MonoCallInst *call2;
1529 MonoInst *iargs [1];
1533 /* Convert the call into a call returning an int */
1534 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1535 memcpy (call2, call, sizeof (MonoCallInst));
1536 switch (ins->opcode) {
1538 call2->inst.opcode = OP_CALL;
1541 call2->inst.opcode = OP_CALL_REG;
1543 case OP_FCALL_MEMBASE:
1544 call2->inst.opcode = OP_CALL_MEMBASE;
1547 g_assert_not_reached ();
1549 call2->inst.dreg = mono_alloc_ireg (cfg);
1550 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1552 /* Remap OUTARG_VT instructions referencing this call */
1553 for (l = call->outarg_vts; l; l = l->next)
1554 ((MonoInst*)(l->data))->inst_p0 = call2;
1556 /* FIXME: Optimize this */
1558 /* Emit an r4->r8 conversion */
1559 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1560 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1561 conv->dreg = ins->dreg;
1563 /* The call sequence might include fp ins */
1566 switch (ins->opcode) {
1568 ins->opcode = OP_LCALL;
1571 ins->opcode = OP_LCALL_REG;
1573 case OP_FCALL_MEMBASE:
1574 ins->opcode = OP_LCALL_MEMBASE;
1577 g_assert_not_reached ();
1583 MonoJitICallInfo *info;
1584 MonoInst *iargs [2];
1585 MonoInst *call, *cmp, *br;
1587 /* Convert fcompare+fbcc to icall+icompare+beq */
1590 /* The branch might be optimized away */
1595 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1597 /* The branch might be optimized away */
1602 /* Create dummy MonoInst's for the arguments */
1603 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1604 iargs [0]->dreg = ins->sreg1;
1605 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1606 iargs [1]->dreg = ins->sreg2;
1608 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1610 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1611 cmp->sreg1 = call->dreg;
1613 MONO_ADD_INS (cfg->cbb, cmp);
1615 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1616 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1617 br->inst_true_bb = ins->next->inst_true_bb;
1618 br->inst_false_bb = ins->next->inst_false_bb;
1619 MONO_ADD_INS (cfg->cbb, br);
1621 /* The call sequence might include fp ins */
1624 /* Skip fbcc or fccc */
1625 NULLIFY_INS (ins->next);
1633 MonoJitICallInfo *info;
1634 MonoInst *iargs [2];
1637 /* Convert fccc to icall+icompare+iceq */
1639 info = mono_find_jit_opcode_emulation (ins->opcode);
1642 /* Create dummy MonoInst's for the arguments */
1643 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1644 iargs [0]->dreg = ins->sreg1;
1645 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1646 iargs [1]->dreg = ins->sreg2;
1648 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1650 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1651 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1653 /* The call sequence might include fp ins */
1658 MonoInst *iargs [2];
1659 MonoInst *call, *cmp;
1661 /* Convert to icall+icompare+cond_exc+move */
1663 /* Create dummy MonoInst's for the arguments */
1664 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1665 iargs [0]->dreg = ins->sreg1;
1667 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1669 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1670 cmp->sreg1 = call->dreg;
1672 MONO_ADD_INS (cfg->cbb, cmp);
1674 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1676 /* Do the assignment if the value is finite */
1677 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1683 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1684 mono_print_ins (ins);
1685 g_assert_not_reached ();
1690 g_assert (cfg->cbb == first_bb);
1692 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1693 /* Replace the original instruction with the new code sequence */
1695 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1696 first_bb->code = first_bb->last_ins = NULL;
1697 first_bb->in_count = first_bb->out_count = 0;
1698 cfg->cbb = first_bb;
1705 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1708 mono_decompose_long_opts (cfg);
1713 #endif /* DISABLE_JIT */