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);
1144 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1146 dreg = alloc_preg (cfg);
1147 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1148 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1149 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1152 case OP_OUTARG_VT: {
1153 g_assert (ins->klass);
1155 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1157 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1158 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1160 mono_arch_emit_outarg_vt (cfg, ins, src);
1162 /* This might be decomposed into other vtype opcodes */
1166 case OP_OUTARG_VTRETADDR: {
1167 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1169 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1171 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1172 // FIXME: src_var->backend.is_pinvoke ?
1174 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1175 src->dreg = ins->dreg;
1180 case OP_VCALL_MEMBASE: {
1181 MonoCallInst *call = (MonoCallInst*)ins;
1184 if (call->vret_in_reg) {
1185 MonoCallInst *call2;
1187 /* Replace the vcall with an integer call */
1188 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1189 memcpy (call2, call, sizeof (MonoCallInst));
1190 switch (ins->opcode) {
1192 call2->inst.opcode = OP_CALL;
1195 call2->inst.opcode = OP_CALL_REG;
1197 case OP_VCALL_MEMBASE:
1198 call2->inst.opcode = OP_CALL_MEMBASE;
1201 call2->inst.dreg = alloc_preg (cfg);
1202 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1204 /* Compute the vtype location */
1205 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1207 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1208 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1210 /* Save the result */
1211 if (dest_var->backend.is_pinvoke)
1212 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1214 size = mono_type_size (dest_var->inst_vtype, NULL);
1217 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1220 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1223 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1226 #if SIZEOF_REGISTER == 4
1228 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1229 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1231 switch (call2->inst.opcode) {
1233 call2->inst.opcode = OP_LCALL;
1236 call2->inst.opcode = OP_LCALL_REG;
1238 case OP_CALL_MEMBASE:
1239 call2->inst.opcode = OP_LCALL_MEMBASE;
1242 call2->inst.dreg = alloc_lreg (cfg);
1243 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1244 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1246 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1250 /* This assumes the vtype is sizeof (gpointer) long */
1251 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1255 switch (ins->opcode) {
1257 ins->opcode = OP_VCALL2;
1260 ins->opcode = OP_VCALL2_REG;
1262 case OP_VCALL_MEMBASE:
1263 ins->opcode = OP_VCALL2_MEMBASE;
1274 g_assert (cfg->cbb == first_bb);
1276 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1277 /* Replace the original instruction with the new code sequence */
1279 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1280 first_bb->code = first_bb->last_ins = NULL;
1281 first_bb->in_count = first_bb->out_count = 0;
1282 cfg->cbb = first_bb;
1289 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1293 inline static MonoInst *
1294 mono_get_domainvar (MonoCompile *cfg)
1296 if (!cfg->domainvar)
1297 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1298 return cfg->domainvar;
1302 * mono_decompose_array_access_opts:
1304 * Decompose array access opcodes.
1307 mono_decompose_array_access_opts (MonoCompile *cfg)
1309 MonoBasicBlock *bb, *first_bb;
1312 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1313 * can be executed anytime. It should be run before decompose_long
1317 * Create a dummy bblock and emit code into it so we can use the normal
1318 * code generation macros.
1320 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1321 first_bb = cfg->cbb;
1323 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1325 MonoInst *prev = NULL;
1327 MonoInst *iargs [3];
1330 if (!bb->has_array_access)
1333 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1335 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1341 for (ins = bb->code; ins; ins = ins->next) {
1342 switch (ins->opcode) {
1344 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1345 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_CONSTANT_LOAD);
1346 MONO_ADD_INS (cfg->cbb, dest);
1348 case OP_BOUNDS_CHECK:
1349 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1350 if (COMPILE_LLVM (cfg))
1351 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1353 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1356 if (cfg->opt & MONO_OPT_SHARED) {
1357 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1358 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1359 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1360 iargs [2]->dreg = ins->sreg1;
1362 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1363 dest->dreg = ins->dreg;
1365 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1366 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1368 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1369 NEW_VTABLECONST (cfg, iargs [0], vtable);
1370 MONO_ADD_INS (cfg->cbb, iargs [0]);
1371 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1372 iargs [1]->dreg = ins->sreg1;
1375 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1377 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1378 dest->dreg = ins->dreg;
1382 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1383 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
1389 g_assert (cfg->cbb == first_bb);
1391 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1392 /* Replace the original instruction with the new code sequence */
1394 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1395 first_bb->code = first_bb->last_ins = NULL;
1396 first_bb->in_count = first_bb->out_count = 0;
1397 cfg->cbb = first_bb;
1404 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1414 #ifdef MONO_ARCH_SOFT_FLOAT
1417 * mono_decompose_soft_float:
1419 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1420 * similar to long support on 32 bit platforms. 32 bit float values require special
1421 * handling when used as locals, arguments, and in calls.
1422 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1425 mono_decompose_soft_float (MonoCompile *cfg)
1427 MonoBasicBlock *bb, *first_bb;
1430 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1434 * Create a dummy bblock and emit code into it so we can use the normal
1435 * code generation macros.
1437 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1438 first_bb = cfg->cbb;
1440 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1442 MonoInst *prev = NULL;
1445 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1447 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1453 for (ins = bb->code; ins; ins = ins->next) {
1454 const char *spec = INS_INFO (ins->opcode);
1456 /* Most fp operations are handled automatically by opcode emulation */
1458 switch (ins->opcode) {
1461 d.vald = *(double*)ins->inst_p0;
1462 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1467 /* We load the r8 value */
1468 d.vald = *(float*)ins->inst_p0;
1469 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1473 ins->opcode = OP_LMOVE;
1476 ins->opcode = OP_MOVE;
1477 ins->sreg1 = ins->sreg1 + 1;
1480 ins->opcode = OP_MOVE;
1481 ins->sreg1 = ins->sreg1 + 2;
1484 int reg = ins->sreg1;
1486 ins->opcode = OP_SETLRET;
1488 ins->sreg1 = reg + 1;
1489 ins->sreg2 = reg + 2;
1492 case OP_LOADR8_MEMBASE:
1493 ins->opcode = OP_LOADI8_MEMBASE;
1495 case OP_STORER8_MEMBASE_REG:
1496 ins->opcode = OP_STOREI8_MEMBASE_REG;
1498 case OP_STORER4_MEMBASE_REG: {
1499 MonoInst *iargs [2];
1502 /* Arg 1 is the double value */
1503 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1504 iargs [0]->dreg = ins->sreg1;
1506 /* Arg 2 is the address to store to */
1507 addr_reg = mono_alloc_preg (cfg);
1508 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1509 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1513 case OP_LOADR4_MEMBASE: {
1514 MonoInst *iargs [1];
1518 addr_reg = mono_alloc_preg (cfg);
1519 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1520 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1521 conv->dreg = ins->dreg;
1526 case OP_FCALL_MEMBASE: {
1527 MonoCallInst *call = (MonoCallInst*)ins;
1528 if (call->signature->ret->type == MONO_TYPE_R4) {
1529 MonoCallInst *call2;
1530 MonoInst *iargs [1];
1534 /* Convert the call into a call returning an int */
1535 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1536 memcpy (call2, call, sizeof (MonoCallInst));
1537 switch (ins->opcode) {
1539 call2->inst.opcode = OP_CALL;
1542 call2->inst.opcode = OP_CALL_REG;
1544 case OP_FCALL_MEMBASE:
1545 call2->inst.opcode = OP_CALL_MEMBASE;
1548 g_assert_not_reached ();
1550 call2->inst.dreg = mono_alloc_ireg (cfg);
1551 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1553 /* Remap OUTARG_VT instructions referencing this call */
1554 for (l = call->outarg_vts; l; l = l->next)
1555 ((MonoInst*)(l->data))->inst_p0 = call2;
1557 /* FIXME: Optimize this */
1559 /* Emit an r4->r8 conversion */
1560 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1561 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1562 conv->dreg = ins->dreg;
1564 /* The call sequence might include fp ins */
1567 switch (ins->opcode) {
1569 ins->opcode = OP_LCALL;
1572 ins->opcode = OP_LCALL_REG;
1574 case OP_FCALL_MEMBASE:
1575 ins->opcode = OP_LCALL_MEMBASE;
1578 g_assert_not_reached ();
1584 MonoJitICallInfo *info;
1585 MonoInst *iargs [2];
1586 MonoInst *call, *cmp, *br;
1588 /* Convert fcompare+fbcc to icall+icompare+beq */
1591 /* The branch might be optimized away */
1596 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1598 /* The branch might be optimized away */
1603 /* Create dummy MonoInst's for the arguments */
1604 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1605 iargs [0]->dreg = ins->sreg1;
1606 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1607 iargs [1]->dreg = ins->sreg2;
1609 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1611 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1612 cmp->sreg1 = call->dreg;
1614 MONO_ADD_INS (cfg->cbb, cmp);
1616 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1617 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1618 br->inst_true_bb = ins->next->inst_true_bb;
1619 br->inst_false_bb = ins->next->inst_false_bb;
1620 MONO_ADD_INS (cfg->cbb, br);
1622 /* The call sequence might include fp ins */
1625 /* Skip fbcc or fccc */
1626 NULLIFY_INS (ins->next);
1634 MonoJitICallInfo *info;
1635 MonoInst *iargs [2];
1638 /* Convert fccc to icall+icompare+iceq */
1640 info = mono_find_jit_opcode_emulation (ins->opcode);
1643 /* Create dummy MonoInst's for the arguments */
1644 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1645 iargs [0]->dreg = ins->sreg1;
1646 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1647 iargs [1]->dreg = ins->sreg2;
1649 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1651 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1652 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1654 /* The call sequence might include fp ins */
1659 MonoInst *iargs [2];
1660 MonoInst *call, *cmp;
1662 /* Convert to icall+icompare+cond_exc+move */
1664 /* Create dummy MonoInst's for the arguments */
1665 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1666 iargs [0]->dreg = ins->sreg1;
1668 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1670 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1671 cmp->sreg1 = call->dreg;
1673 MONO_ADD_INS (cfg->cbb, cmp);
1675 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1677 /* Do the assignment if the value is finite */
1678 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1684 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1685 mono_print_ins (ins);
1686 g_assert_not_reached ();
1691 g_assert (cfg->cbb == first_bb);
1693 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1694 /* Replace the original instruction with the new code sequence */
1696 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1697 first_bb->code = first_bb->last_ins = NULL;
1698 first_bb->in_count = first_bb->out_count = 0;
1699 cfg->cbb = first_bb;
1706 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1709 mono_decompose_long_opts (cfg);
1714 #endif /* DISABLE_JIT */