2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include "jit-icalls.h"
15 #include <mono/metadata/gc-internal.h>
19 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
20 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
21 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
22 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
24 /* Decompose complex long opcodes on 64 bit machines or when using LLVM */
26 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
28 MonoInst *repl = NULL;
32 switch (ins->opcode) {
34 ins->opcode = OP_SEXT_I4;
40 ins->opcode = OP_MOVE;
43 ins->opcode = OP_SEXT_I4;
46 ins->opcode = OP_ZEXT_I4;
49 /* Clean out the upper word */
50 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
54 if (COMPILE_LLVM (cfg))
58 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
63 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
65 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
69 if (COMPILE_LLVM (cfg))
73 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
78 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
80 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
83 #ifndef __mono_ppc64__
85 if (COMPILE_LLVM (cfg))
89 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
94 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
96 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
100 if (COMPILE_LLVM (cfg))
104 #if defined(__mono_ilp32__) && SIZEOF_REGISTER == 8
109 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
111 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
116 case OP_ICONV_TO_OVF_I8:
117 case OP_ICONV_TO_OVF_I:
118 ins->opcode = OP_SEXT_I4;
120 case OP_ICONV_TO_OVF_U8:
121 case OP_ICONV_TO_OVF_U:
122 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
123 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
124 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
127 case OP_ICONV_TO_OVF_I8_UN:
128 case OP_ICONV_TO_OVF_U8_UN:
129 case OP_ICONV_TO_OVF_I_UN:
130 case OP_ICONV_TO_OVF_U_UN:
131 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
132 /* Clean out the upper word */
133 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
136 case OP_LCONV_TO_OVF_I1:
137 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
138 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
139 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
140 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
141 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
144 case OP_LCONV_TO_OVF_I1_UN:
145 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
146 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
147 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
150 case OP_LCONV_TO_OVF_U1:
151 /* probe value to be within 0 to 255 */
152 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
153 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
154 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
157 case OP_LCONV_TO_OVF_U1_UN:
158 /* probe value to be within 0 to 255 */
159 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
160 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
161 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
164 case OP_LCONV_TO_OVF_I2:
165 /* Probe value to be within -32768 and 32767 */
166 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
167 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
168 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
169 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
170 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
173 case OP_LCONV_TO_OVF_I2_UN:
174 /* Probe value to be within 0 and 32767 */
175 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
176 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
177 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
180 case OP_LCONV_TO_OVF_U2:
181 /* Probe value to be within 0 and 65535 */
182 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
183 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
184 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
187 case OP_LCONV_TO_OVF_U2_UN:
188 /* Probe value to be within 0 and 65535 */
189 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
190 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
191 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
194 case OP_LCONV_TO_OVF_I4:
195 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
196 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
197 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
198 #if SIZEOF_REGISTER == 8
199 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
201 g_assert (COMPILE_LLVM (cfg));
202 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
204 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
205 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
208 case OP_LCONV_TO_OVF_I4_UN:
209 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
210 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
211 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
214 case OP_LCONV_TO_OVF_U4:
215 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
216 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
217 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
218 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
219 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
222 case OP_LCONV_TO_OVF_U4_UN:
223 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
224 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
225 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
228 case OP_LCONV_TO_OVF_I:
229 case OP_LCONV_TO_OVF_U_UN:
230 case OP_LCONV_TO_OVF_U8_UN:
231 case OP_LCONV_TO_OVF_I8:
232 ins->opcode = OP_MOVE;
234 case OP_LCONV_TO_OVF_I_UN:
235 case OP_LCONV_TO_OVF_I8_UN:
236 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
237 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
238 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
241 case OP_LCONV_TO_OVF_U8:
242 case OP_LCONV_TO_OVF_U:
243 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
244 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
245 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
257 * mono_decompose_opcode:
259 * Decompose complex opcodes into ones closer to opcodes supported by
260 * the given architecture.
261 * Returns a MonoInst which represents the result of the decomposition, and can
262 * be pushed on the IL stack. This is needed because the original instruction is
264 * Sets the cfg exception if an opcode is not supported.
267 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
269 MonoInst *repl = NULL;
270 int type = ins->type;
271 int dreg = ins->dreg;
272 gboolean emulate = FALSE;
274 /* FIXME: Instead of = NOP, don't emit the original ins at all */
276 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
277 mono_arch_decompose_opts (cfg, ins);
281 * The code below assumes that we are called immediately after emitting
282 * ins. This means we can emit code using the normal code generation
285 switch (ins->opcode) {
286 /* this doesn't make sense on ppc and other architectures */
287 #if !defined(MONO_ARCH_NO_IOV_CHECK)
289 if (COMPILE_LLVM (cfg))
291 ins->opcode = OP_IADDCC;
292 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
295 if (COMPILE_LLVM (cfg))
297 ins->opcode = OP_IADDCC;
298 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
301 if (COMPILE_LLVM (cfg))
303 ins->opcode = OP_ISUBCC;
304 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
307 if (COMPILE_LLVM (cfg))
309 ins->opcode = OP_ISUBCC;
310 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
313 case OP_ICONV_TO_OVF_I1:
314 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
315 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
316 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
317 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
318 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
321 case OP_ICONV_TO_OVF_I1_UN:
322 /* probe values between 0 to 127 */
323 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
324 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
325 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
328 case OP_ICONV_TO_OVF_U1:
329 case OP_ICONV_TO_OVF_U1_UN:
330 /* probe value to be within 0 to 255 */
331 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
332 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
333 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
336 case OP_ICONV_TO_OVF_I2:
337 /* Probe value to be within -32768 and 32767 */
338 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
339 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
340 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
341 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
342 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
345 case OP_ICONV_TO_OVF_I2_UN:
346 /* Convert uint value into short, value within 0 and 32767 */
347 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
348 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
349 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
352 case OP_ICONV_TO_OVF_U2:
353 case OP_ICONV_TO_OVF_U2_UN:
354 /* Probe value to be within 0 and 65535 */
355 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
356 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
357 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
360 case OP_ICONV_TO_OVF_U4:
361 case OP_ICONV_TO_OVF_I4_UN:
362 #if SIZEOF_VOID_P == 4
363 case OP_ICONV_TO_OVF_U:
364 case OP_ICONV_TO_OVF_I_UN:
366 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
367 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
368 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
373 case OP_ICONV_TO_OVF_I4:
374 case OP_ICONV_TO_OVF_U4_UN:
375 #if SIZEOF_VOID_P == 4
376 case OP_ICONV_TO_OVF_I:
377 case OP_ICONV_TO_OVF_U_UN:
379 ins->opcode = OP_MOVE;
382 #if SIZEOF_VOID_P == 8
383 ins->opcode = OP_SEXT_I4;
385 ins->opcode = OP_MOVE;
389 #if SIZEOF_VOID_P == 8
390 ins->opcode = OP_ZEXT_I4;
392 ins->opcode = OP_MOVE;
397 ins->opcode = OP_FMOVE;
400 case OP_FCONV_TO_OVF_I1_UN:
401 case OP_FCONV_TO_OVF_I2_UN:
402 case OP_FCONV_TO_OVF_I4_UN:
403 case OP_FCONV_TO_OVF_I8_UN:
404 case OP_FCONV_TO_OVF_U1_UN:
405 case OP_FCONV_TO_OVF_U2_UN:
406 case OP_FCONV_TO_OVF_U4_UN:
407 case OP_FCONV_TO_OVF_U8_UN:
408 case OP_FCONV_TO_OVF_I_UN:
409 case OP_FCONV_TO_OVF_U_UN:
410 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
411 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
414 #if defined(MONO_ARCH_EMULATE_DIV) && defined(MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION)
419 if (!mono_arch_opcode_needs_emulation (cfg, ins->opcode)) {
420 #ifdef MONO_ARCH_NEED_DIV_CHECK
421 int reg1 = alloc_ireg (cfg);
422 int reg2 = alloc_ireg (cfg);
424 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
425 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
426 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
427 /* b == -1 && a == 0x80000000 */
428 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
429 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
430 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
431 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
432 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
433 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
434 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
437 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
438 ins->opcode = OP_NOP;
451 MonoJitICallInfo *info = NULL;
453 #if SIZEOF_REGISTER == 8
454 if (decompose_long_opcode (cfg, ins, &repl))
457 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
462 info = mono_find_jit_opcode_emulation (ins->opcode);
467 /* Create dummy MonoInst's for the arguments */
468 g_assert (!info->sig->hasthis);
469 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
471 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
472 if (info->sig->param_count > 0) {
473 int sregs [MONO_MAX_SRC_REGS];
475 num_sregs = mono_inst_get_src_registers (ins, sregs);
476 g_assert (num_sregs == info->sig->param_count);
477 for (i = 0; i < num_sregs; ++i) {
478 MONO_INST_NEW (cfg, args [i], OP_ARG);
479 args [i]->dreg = sregs [i];
483 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
484 call->dreg = ins->dreg;
490 if (ins->opcode == OP_NOP) {
495 /* Use the last emitted instruction */
496 ins = cfg->cbb->last_ins;
499 g_assert (ins->dreg == dreg);
507 #if SIZEOF_REGISTER == 4
508 static int lbr_decomp [][2] = {
510 {OP_IBGT, OP_IBGE_UN}, /* BGE */
511 {OP_IBGT, OP_IBGT_UN}, /* BGT */
512 {OP_IBLT, OP_IBLE_UN}, /* BLE */
513 {OP_IBLT, OP_IBLT_UN}, /* BLT */
515 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
516 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
517 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
518 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
521 static int lcset_decomp [][2] = {
523 {OP_IBLT, OP_IBLE_UN}, /* CGT */
524 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
525 {OP_IBGT, OP_IBGE_UN}, /* CLT */
526 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
531 * mono_decompose_long_opts:
533 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
536 mono_decompose_long_opts (MonoCompile *cfg)
538 #if SIZEOF_REGISTER == 4
539 MonoBasicBlock *bb, *first_bb;
542 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
543 * needs to be able to handle long vregs.
546 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
549 * Create a dummy bblock and emit code into it so we can use the normal
550 * code generation macros.
552 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
555 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
556 MonoInst *tree = bb->code;
557 MonoInst *prev = NULL;
560 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
564 cfg->cbb->code = cfg->cbb->last_ins = NULL;
568 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
569 mono_arch_decompose_long_opts (cfg, tree);
572 switch (tree->opcode) {
574 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
575 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
580 case OP_LCONV_TO_OVF_U8_UN:
581 case OP_LCONV_TO_OVF_I8:
582 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
583 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
585 case OP_STOREI8_MEMBASE_REG:
586 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
587 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
589 case OP_LOADI8_MEMBASE:
590 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
591 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
594 case OP_ICONV_TO_I8: {
595 guint32 tmpreg = alloc_ireg (cfg);
599 * tmp = low > -1 ? 1: 0;
600 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
602 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
603 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
604 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
605 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
609 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
610 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
612 case OP_ICONV_TO_OVF_I8:
613 /* a signed 32 bit num always fits in a signed 64 bit one */
614 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
615 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
617 case OP_ICONV_TO_OVF_U8:
618 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
619 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
620 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
621 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
623 case OP_ICONV_TO_OVF_I8_UN:
624 case OP_ICONV_TO_OVF_U8_UN:
625 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
626 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
627 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
630 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
633 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
636 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
639 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
645 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
648 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
651 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
653 case OP_LCONV_TO_R_UN:
654 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
656 case OP_LCONV_TO_OVF_I1: {
657 MonoBasicBlock *is_negative, *end_label;
659 NEW_BBLOCK (cfg, is_negative);
660 NEW_BBLOCK (cfg, end_label);
662 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
663 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
664 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
665 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
667 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
668 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
671 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
672 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
673 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
676 MONO_START_BB (cfg, is_negative);
677 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
678 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
680 MONO_START_BB (cfg, end_label);
682 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
685 case OP_LCONV_TO_OVF_I1_UN:
686 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
687 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
689 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
690 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
691 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
692 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
693 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
695 case OP_LCONV_TO_OVF_U1:
696 case OP_LCONV_TO_OVF_U1_UN:
697 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
698 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
700 /* probe value to be within 0 to 255 */
701 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
702 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
703 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
705 case OP_LCONV_TO_OVF_I2: {
706 MonoBasicBlock *is_negative, *end_label;
708 NEW_BBLOCK (cfg, is_negative);
709 NEW_BBLOCK (cfg, end_label);
711 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
712 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
713 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
714 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
716 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
717 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
720 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
721 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
722 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
725 MONO_START_BB (cfg, is_negative);
726 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
727 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
728 MONO_START_BB (cfg, end_label);
730 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
733 case OP_LCONV_TO_OVF_I2_UN:
734 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
735 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
737 /* Probe value to be within -32768 and 32767 */
738 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
739 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
740 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
741 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
742 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
744 case OP_LCONV_TO_OVF_U2:
745 case OP_LCONV_TO_OVF_U2_UN:
746 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
747 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
749 /* Probe value to be within 0 and 65535 */
750 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
751 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
752 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
754 case OP_LCONV_TO_OVF_I4:
755 case OP_LCONV_TO_OVF_I:
756 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
758 case OP_LCONV_TO_OVF_U4:
759 case OP_LCONV_TO_OVF_U:
760 case OP_LCONV_TO_OVF_U4_UN:
761 case OP_LCONV_TO_OVF_U_UN:
762 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
763 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
764 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
766 case OP_LCONV_TO_OVF_I_UN:
767 case OP_LCONV_TO_OVF_I4_UN:
768 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
769 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
770 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
771 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
772 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
774 case OP_LCONV_TO_OVF_U8:
775 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
776 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
778 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
779 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
781 case OP_LCONV_TO_OVF_I8_UN:
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
783 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
785 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
786 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
790 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
791 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
794 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
795 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
799 /* ADC sets the condition code */
800 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
801 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
802 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
805 /* ADC sets the condition code */
806 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
807 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
808 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
811 /* SBB sets the condition code */
812 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
813 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
814 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
817 /* SBB sets the condition code */
818 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
819 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
820 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
823 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
824 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
827 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
828 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
831 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
832 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
835 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
836 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
839 /* Handled in mono_arch_decompose_long_opts () */
840 g_assert_not_reached ();
844 /* FIXME: Add OP_BIGMUL optimization */
848 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
849 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
852 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
853 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
856 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
857 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
860 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
861 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
864 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
865 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
868 if (tree->inst_c1 == 32) {
870 /* The original code had this comment: */
871 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
872 * later apply the speedup to the left shift as well
875 /* FIXME: Move this to the strength reduction pass */
876 /* just move the upper half to the lower and zero the high word */
877 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
878 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
882 if (tree->inst_c1 == 32) {
883 /* just move the lower half to the upper and zero the lower word */
884 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
885 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
890 MonoInst *next = tree->next;
894 switch (next->opcode) {
899 /* Branchless version based on gcc code */
900 d1 = alloc_ireg (cfg);
901 d2 = alloc_ireg (cfg);
902 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
903 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
904 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
905 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
906 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
907 next->opcode = OP_NOP;
918 /* Convert into three comparisons + branches */
919 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
920 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
921 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
922 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
923 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
924 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
925 next->opcode = OP_NOP;
930 /* Branchless version based on gcc code */
931 d1 = alloc_ireg (cfg);
932 d2 = alloc_ireg (cfg);
933 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
934 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
935 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
937 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
938 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
939 next->opcode = OP_NOP;
946 MonoBasicBlock *set_to_0, *set_to_1;
948 NEW_BBLOCK (cfg, set_to_0);
949 NEW_BBLOCK (cfg, set_to_1);
951 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
952 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
953 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
954 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
955 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
956 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
957 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
958 MONO_START_BB (cfg, set_to_1);
959 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
960 MONO_START_BB (cfg, set_to_0);
961 next->opcode = OP_NOP;
965 g_assert_not_reached ();
970 /* Not yet used, since lcompare is decomposed before local cprop */
971 case OP_LCOMPARE_IMM: {
972 MonoInst *next = tree->next;
973 guint32 low_imm = tree->inst_ls_word;
974 guint32 high_imm = tree->inst_ms_word;
975 int low_reg = tree->sreg1 + 1;
976 int high_reg = tree->sreg1 + 2;
980 switch (next->opcode) {
985 /* Branchless version based on gcc code */
986 d1 = alloc_ireg (cfg);
987 d2 = alloc_ireg (cfg);
988 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
989 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
990 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
991 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
992 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
993 next->opcode = OP_NOP;
1005 /* Convert into three comparisons + branches */
1006 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1007 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1008 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1009 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1010 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1011 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1012 next->opcode = OP_NOP;
1017 /* Branchless version based on gcc code */
1018 d1 = alloc_ireg (cfg);
1019 d2 = alloc_ireg (cfg);
1020 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1021 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1022 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1024 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1025 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1026 next->opcode = OP_NOP;
1033 MonoBasicBlock *set_to_0, *set_to_1;
1035 NEW_BBLOCK (cfg, set_to_0);
1036 NEW_BBLOCK (cfg, set_to_1);
1038 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1039 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1040 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1041 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1042 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1043 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1044 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1045 MONO_START_BB (cfg, set_to_1);
1046 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1047 MONO_START_BB (cfg, set_to_0);
1048 next->opcode = OP_NOP;
1052 g_assert_not_reached ();
1061 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1064 /* Replace the original instruction with the new code sequence */
1066 /* Ignore the new value of prev */
1068 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1070 /* Process the newly added ops again since they can be long ops too */
1076 first_bb->code = first_bb->last_ins = NULL;
1077 first_bb->in_count = first_bb->out_count = 0;
1078 cfg->cbb = first_bb;
1089 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1090 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1095 * mono_decompose_vtype_opts:
1097 * Decompose valuetype opcodes.
1100 mono_decompose_vtype_opts (MonoCompile *cfg)
1102 MonoBasicBlock *bb, *first_bb;
1105 * Using OP_V opcodes and decomposing them later have two main benefits:
1106 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1108 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1109 * enabling optimizations to work on vtypes too.
1110 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1111 * can be executed anytime. It should be executed as late as possible so vtype
1112 * opcodes can be optimized by the other passes.
1113 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1114 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1116 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1117 * when OP_VMOVE opcodes are decomposed.
1121 * Vregs have no associated type information, so we store the type of the vregs
1126 * Create a dummy bblock and emit code into it so we can use the normal
1127 * code generation macros.
1129 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1130 first_bb = cfg->cbb;
1132 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1134 MonoInst *prev = NULL;
1135 MonoInst *src_var, *dest_var, *src, *dest;
1139 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1141 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1147 for (ins = bb->code; ins; ins = ins->next) {
1148 switch (ins->opcode) {
1150 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1151 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1153 g_assert (ins->klass);
1156 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1159 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1162 if (src_var->backend.is_pinvoke)
1163 dest_var->backend.is_pinvoke = 1;
1165 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1166 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1168 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1172 g_assert (ins->klass);
1174 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1175 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1177 if (cfg->compute_gc_maps) {
1181 * Tell the GC map code that the vtype is considered live after
1182 * the initialization.
1184 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1185 tmp->inst_c1 = ins->dreg;
1186 MONO_ADD_INS (cfg->cbb, tmp);
1189 case OP_STOREV_MEMBASE: {
1190 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1193 g_assert (ins->klass);
1194 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1197 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1199 dreg = alloc_preg (cfg);
1200 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1201 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1204 case OP_LOADV_MEMBASE: {
1205 g_assert (ins->klass);
1207 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1211 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1213 dreg = alloc_preg (cfg);
1214 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1215 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1216 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1219 case OP_OUTARG_VT: {
1220 g_assert (ins->klass);
1222 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1224 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1225 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1227 mono_arch_emit_outarg_vt (cfg, ins, src);
1229 /* This might be decomposed into other vtype opcodes */
1233 case OP_OUTARG_VTRETADDR: {
1234 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1236 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1238 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1239 // FIXME: src_var->backend.is_pinvoke ?
1241 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1242 src->dreg = ins->dreg;
1247 case OP_VCALL_MEMBASE: {
1248 MonoCallInst *call = (MonoCallInst*)ins;
1251 if (call->vret_in_reg) {
1252 MonoCallInst *call2;
1254 /* Replace the vcall with an integer call */
1255 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1256 memcpy (call2, call, sizeof (MonoCallInst));
1257 switch (ins->opcode) {
1259 call2->inst.opcode = OP_CALL;
1262 call2->inst.opcode = OP_CALL_REG;
1264 case OP_VCALL_MEMBASE:
1265 call2->inst.opcode = OP_CALL_MEMBASE;
1268 call2->inst.dreg = alloc_preg (cfg);
1269 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1271 /* Compute the vtype location */
1272 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1274 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1275 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1277 /* Save the result */
1278 if (dest_var->backend.is_pinvoke)
1279 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1281 size = mono_type_size (dest_var->inst_vtype, NULL);
1284 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1287 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1291 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1297 #if SIZEOF_REGISTER == 4
1299 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1300 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1302 switch (call2->inst.opcode) {
1304 call2->inst.opcode = OP_LCALL;
1307 call2->inst.opcode = OP_LCALL_REG;
1309 case OP_CALL_MEMBASE:
1310 call2->inst.opcode = OP_LCALL_MEMBASE;
1313 call2->inst.dreg = alloc_lreg (cfg);
1314 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1315 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1317 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1321 /* This assumes the vtype is sizeof (gpointer) long */
1322 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1326 switch (ins->opcode) {
1328 ins->opcode = OP_VCALL2;
1331 ins->opcode = OP_VCALL2_REG;
1333 case OP_VCALL_MEMBASE:
1334 ins->opcode = OP_VCALL2_MEMBASE;
1345 g_assert (cfg->cbb == first_bb);
1347 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1348 /* Replace the original instruction with the new code sequence */
1350 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1351 first_bb->code = first_bb->last_ins = NULL;
1352 first_bb->in_count = first_bb->out_count = 0;
1353 cfg->cbb = first_bb;
1360 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1365 mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
1367 MonoBasicBlock *bb, *first_bb;
1369 /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
1371 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1372 first_bb = cfg->cbb;
1374 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1376 MonoInst *prev = NULL;
1377 MonoInst *src_var, *src, *dest;
1381 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
1383 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1389 for (ins = bb->code; ins; ins = ins->next) {
1390 switch (ins->opcode) {
1391 case OP_STOREV_MEMBASE: {
1392 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1395 g_assert (ins->klass);
1396 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1399 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1401 dreg = alloc_preg (cfg);
1402 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1403 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1410 g_assert (cfg->cbb == first_bb);
1412 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1413 /* Replace the original instruction with the new code sequence */
1415 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1416 first_bb->code = first_bb->last_ins = NULL;
1417 first_bb->in_count = first_bb->out_count = 0;
1418 cfg->cbb = first_bb;
1425 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
1429 inline static MonoInst *
1430 mono_get_domainvar (MonoCompile *cfg)
1432 if (!cfg->domainvar)
1433 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1434 return cfg->domainvar;
1438 * mono_decompose_array_access_opts:
1440 * Decompose array access opcodes.
1443 mono_decompose_array_access_opts (MonoCompile *cfg)
1445 MonoBasicBlock *bb, *first_bb;
1448 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1449 * can be executed anytime. It should be run before decompose_long
1453 * Create a dummy bblock and emit code into it so we can use the normal
1454 * code generation macros.
1456 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1457 first_bb = cfg->cbb;
1459 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1461 MonoInst *prev = NULL;
1463 MonoInst *iargs [3];
1466 if (!bb->has_array_access)
1469 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1471 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1477 for (ins = bb->code; ins; ins = ins->next) {
1478 switch (ins->opcode) {
1480 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1481 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1482 MONO_ADD_INS (cfg->cbb, dest);
1484 case OP_BOUNDS_CHECK:
1485 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1486 if (COMPILE_LLVM (cfg))
1487 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1489 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1492 if (cfg->opt & MONO_OPT_SHARED) {
1493 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1494 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1495 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1496 iargs [2]->dreg = ins->sreg1;
1498 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1499 dest->dreg = ins->dreg;
1501 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1502 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1503 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1505 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1506 NEW_VTABLECONST (cfg, iargs [0], vtable);
1507 MONO_ADD_INS (cfg->cbb, iargs [0]);
1508 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1509 iargs [1]->dreg = ins->sreg1;
1512 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1514 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1515 dest->dreg = ins->dreg;
1519 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1520 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1526 g_assert (cfg->cbb == first_bb);
1528 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1529 /* Replace the original instruction with the new code sequence */
1531 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1532 first_bb->code = first_bb->last_ins = NULL;
1533 first_bb->in_count = first_bb->out_count = 0;
1534 cfg->cbb = first_bb;
1541 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1551 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1554 * mono_decompose_soft_float:
1556 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1557 * similar to long support on 32 bit platforms. 32 bit float values require special
1558 * handling when used as locals, arguments, and in calls.
1559 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1562 mono_decompose_soft_float (MonoCompile *cfg)
1564 MonoBasicBlock *bb, *first_bb;
1567 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1571 * Create a dummy bblock and emit code into it so we can use the normal
1572 * code generation macros.
1574 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1575 first_bb = cfg->cbb;
1577 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1579 MonoInst *prev = NULL;
1582 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1584 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1590 for (ins = bb->code; ins; ins = ins->next) {
1591 const char *spec = INS_INFO (ins->opcode);
1593 /* Most fp operations are handled automatically by opcode emulation */
1595 switch (ins->opcode) {
1598 d.vald = *(double*)ins->inst_p0;
1599 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1604 /* We load the r8 value */
1605 d.vald = *(float*)ins->inst_p0;
1606 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1610 ins->opcode = OP_LMOVE;
1613 ins->opcode = OP_MOVE;
1614 ins->sreg1 = ins->sreg1 + 1;
1617 ins->opcode = OP_MOVE;
1618 ins->sreg1 = ins->sreg1 + 2;
1621 int reg = ins->sreg1;
1623 ins->opcode = OP_SETLRET;
1625 ins->sreg1 = reg + 1;
1626 ins->sreg2 = reg + 2;
1629 case OP_LOADR8_MEMBASE:
1630 ins->opcode = OP_LOADI8_MEMBASE;
1632 case OP_STORER8_MEMBASE_REG:
1633 ins->opcode = OP_STOREI8_MEMBASE_REG;
1635 case OP_STORER4_MEMBASE_REG: {
1636 MonoInst *iargs [2];
1639 /* Arg 1 is the double value */
1640 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1641 iargs [0]->dreg = ins->sreg1;
1643 /* Arg 2 is the address to store to */
1644 addr_reg = mono_alloc_preg (cfg);
1645 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1646 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1650 case OP_LOADR4_MEMBASE: {
1651 MonoInst *iargs [1];
1655 addr_reg = mono_alloc_preg (cfg);
1656 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1657 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1658 conv->dreg = ins->dreg;
1663 case OP_FCALL_MEMBASE: {
1664 MonoCallInst *call = (MonoCallInst*)ins;
1665 if (call->signature->ret->type == MONO_TYPE_R4) {
1666 MonoCallInst *call2;
1667 MonoInst *iargs [1];
1671 /* Convert the call into a call returning an int */
1672 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1673 memcpy (call2, call, sizeof (MonoCallInst));
1674 switch (ins->opcode) {
1676 call2->inst.opcode = OP_CALL;
1679 call2->inst.opcode = OP_CALL_REG;
1681 case OP_FCALL_MEMBASE:
1682 call2->inst.opcode = OP_CALL_MEMBASE;
1685 g_assert_not_reached ();
1687 call2->inst.dreg = mono_alloc_ireg (cfg);
1688 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1690 /* Remap OUTARG_VT instructions referencing this call */
1691 for (l = call->outarg_vts; l; l = l->next)
1692 ((MonoInst*)(l->data))->inst_p0 = call2;
1694 /* FIXME: Optimize this */
1696 /* Emit an r4->r8 conversion */
1697 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1698 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1699 conv->dreg = ins->dreg;
1701 /* The call sequence might include fp ins */
1704 switch (ins->opcode) {
1706 ins->opcode = OP_LCALL;
1709 ins->opcode = OP_LCALL_REG;
1711 case OP_FCALL_MEMBASE:
1712 ins->opcode = OP_LCALL_MEMBASE;
1715 g_assert_not_reached ();
1721 MonoJitICallInfo *info;
1722 MonoInst *iargs [2];
1723 MonoInst *call, *cmp, *br;
1725 /* Convert fcompare+fbcc to icall+icompare+beq */
1728 /* The branch might be optimized away */
1733 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1735 /* The branch might be optimized away */
1740 /* Create dummy MonoInst's for the arguments */
1741 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1742 iargs [0]->dreg = ins->sreg1;
1743 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1744 iargs [1]->dreg = ins->sreg2;
1746 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1748 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1749 cmp->sreg1 = call->dreg;
1751 MONO_ADD_INS (cfg->cbb, cmp);
1753 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1754 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1755 br->inst_true_bb = ins->next->inst_true_bb;
1756 br->inst_false_bb = ins->next->inst_false_bb;
1757 MONO_ADD_INS (cfg->cbb, br);
1759 /* The call sequence might include fp ins */
1762 /* Skip fbcc or fccc */
1763 NULLIFY_INS (ins->next);
1771 MonoJitICallInfo *info;
1772 MonoInst *iargs [2];
1775 /* Convert fccc to icall+icompare+iceq */
1777 info = mono_find_jit_opcode_emulation (ins->opcode);
1780 /* Create dummy MonoInst's for the arguments */
1781 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1782 iargs [0]->dreg = ins->sreg1;
1783 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1784 iargs [1]->dreg = ins->sreg2;
1786 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1788 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1789 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1791 /* The call sequence might include fp ins */
1796 MonoInst *iargs [2];
1797 MonoInst *call, *cmp;
1799 /* Convert to icall+icompare+cond_exc+move */
1801 /* Create dummy MonoInst's for the arguments */
1802 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1803 iargs [0]->dreg = ins->sreg1;
1805 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1807 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1808 cmp->sreg1 = call->dreg;
1810 MONO_ADD_INS (cfg->cbb, cmp);
1812 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1814 /* Do the assignment if the value is finite */
1815 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1821 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1822 mono_print_ins (ins);
1823 g_assert_not_reached ();
1828 g_assert (cfg->cbb == first_bb);
1830 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1831 /* Replace the original instruction with the new code sequence */
1833 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1834 first_bb->code = first_bb->last_ins = NULL;
1835 first_bb->in_count = first_bb->out_count = 0;
1836 cfg->cbb = first_bb;
1843 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1846 mono_decompose_long_opts (cfg);
1851 #endif /* DISABLE_JIT */