2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
12 #include "jit-icalls.h"
14 #include <mono/metadata/gc-internal.h>
18 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
19 MonoInst
* mono_emit_native_call (MonoCompile
*cfg
, gconstpointer func
, MonoMethodSignature
*sig
, MonoInst
**args
);
20 void mini_emit_stobj (MonoCompile
*cfg
, MonoInst
*dest
, MonoInst
*src
, MonoClass
*klass
, gboolean native
);
21 void mini_emit_initobj (MonoCompile
*cfg
, MonoInst
*dest
, const guchar
*ip
, MonoClass
*klass
);
24 * mono_decompose_opcode:
26 * Decompose complex opcodes into ones closer to opcodes supported by
27 * the given architecture.
28 * Returns a MonoInst which represents the result of the decomposition, and can
29 * be pushed on the IL stack. This is needed because the original instruction is
31 * Sets the cfg exception if an opcode is not supported.
34 mono_decompose_opcode (MonoCompile
*cfg
, MonoInst
*ins
)
36 MonoInst
*repl
= NULL
;
40 /* FIXME: Instead of = NOP, don't emit the original ins at all */
42 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
43 mono_arch_decompose_opts (cfg
, ins
);
47 * The code below assumes that we are called immediately after emitting
48 * ins. This means we can emit code using the normal code generation
51 switch (ins
->opcode
) {
52 /* this doesn't make sense on ppc and other architectures */
53 #if !defined(MONO_ARCH_NO_IOV_CHECK)
55 if (COMPILE_LLVM (cfg
))
57 ins
->opcode
= OP_IADDCC
;
58 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
61 if (COMPILE_LLVM (cfg
))
63 ins
->opcode
= OP_IADDCC
;
64 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
67 if (COMPILE_LLVM (cfg
))
69 ins
->opcode
= OP_ISUBCC
;
70 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
73 if (COMPILE_LLVM (cfg
))
75 ins
->opcode
= OP_ISUBCC
;
76 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
79 case OP_ICONV_TO_OVF_I1
:
80 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
81 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
82 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -128);
83 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
84 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
87 case OP_ICONV_TO_OVF_I1_UN
:
88 /* probe values between 0 to 127 */
89 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
90 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
91 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
94 case OP_ICONV_TO_OVF_U1
:
95 case OP_ICONV_TO_OVF_U1_UN
:
96 /* probe value to be within 0 to 255 */
97 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 255);
98 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
99 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
102 case OP_ICONV_TO_OVF_I2
:
103 /* Probe value to be within -32768 and 32767 */
104 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
105 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
106 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
107 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
108 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
111 case OP_ICONV_TO_OVF_I2_UN
:
112 /* Convert uint value into short, value within 0 and 32767 */
113 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
114 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
115 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
118 case OP_ICONV_TO_OVF_U2
:
119 case OP_ICONV_TO_OVF_U2_UN
:
120 /* Probe value to be within 0 and 65535 */
121 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
122 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
123 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
126 case OP_ICONV_TO_OVF_U4
:
127 case OP_ICONV_TO_OVF_I4_UN
:
128 #if SIZEOF_REGISTER == 4
129 case OP_ICONV_TO_OVF_U
:
130 case OP_ICONV_TO_OVF_I_UN
:
132 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0);
133 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
134 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
139 case OP_ICONV_TO_OVF_I4
:
140 case OP_ICONV_TO_OVF_U4_UN
:
141 #if SIZEOF_REGISTER == 4
142 case OP_ICONV_TO_OVF_I
:
143 case OP_ICONV_TO_OVF_U_UN
:
145 ins
->opcode
= OP_MOVE
;
148 #if SIZEOF_REGISTER == 8
149 ins
->opcode
= OP_SEXT_I4
;
151 ins
->opcode
= OP_MOVE
;
155 #if SIZEOF_REGISTER == 8
156 ins
->opcode
= OP_ZEXT_I4
;
158 ins
->opcode
= OP_MOVE
;
163 ins
->opcode
= OP_FMOVE
;
166 case OP_FCONV_TO_OVF_I1_UN
:
167 case OP_FCONV_TO_OVF_I2_UN
:
168 case OP_FCONV_TO_OVF_I4_UN
:
169 case OP_FCONV_TO_OVF_I8_UN
:
170 case OP_FCONV_TO_OVF_U1_UN
:
171 case OP_FCONV_TO_OVF_U2_UN
:
172 case OP_FCONV_TO_OVF_U4_UN
:
173 case OP_FCONV_TO_OVF_U8_UN
:
174 case OP_FCONV_TO_OVF_I_UN
:
175 case OP_FCONV_TO_OVF_U_UN
:
176 cfg
->exception_type
= MONO_EXCEPTION_INVALID_PROGRAM
;
177 cfg
->exception_message
= g_strdup_printf ("float conv.ovf.un opcodes not supported.");
180 /* Long opcodes on 64 bit machines */
181 #if SIZEOF_REGISTER == 8
183 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_LSHR_IMM
, ins
->dreg
, ins
->sreg1
, 0);
190 ins
->opcode
= OP_MOVE
;
193 ins
->opcode
= OP_SEXT_I4
;
196 ins
->opcode
= OP_ZEXT_I4
;
199 /* Clean out the upper word */
200 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
204 if (COMPILE_LLVM (cfg
))
206 EMIT_NEW_BIALU (cfg
, repl
, OP_ADDCC
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
207 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
211 if (COMPILE_LLVM (cfg
))
213 EMIT_NEW_BIALU (cfg
, repl
, OP_ADDCC
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
214 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
217 #ifndef __mono_ppc64__
219 if (COMPILE_LLVM (cfg
))
221 EMIT_NEW_BIALU (cfg
, repl
, OP_SUBCC
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
222 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
226 if (COMPILE_LLVM (cfg
))
228 EMIT_NEW_BIALU (cfg
, repl
, OP_SUBCC
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
229 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
234 case OP_ICONV_TO_OVF_I8
:
235 case OP_ICONV_TO_OVF_I
:
236 ins
->opcode
= OP_SEXT_I4
;
238 case OP_ICONV_TO_OVF_U8
:
239 case OP_ICONV_TO_OVF_U
:
240 MONO_EMIT_NEW_COMPARE_IMM (cfg
,ins
->sreg1
, 0);
241 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
242 MONO_EMIT_NEW_UNALU (cfg
, OP_ZEXT_I4
, ins
->dreg
, ins
->sreg1
);
245 case OP_ICONV_TO_OVF_I8_UN
:
246 case OP_ICONV_TO_OVF_U8_UN
:
247 case OP_ICONV_TO_OVF_I_UN
:
248 case OP_ICONV_TO_OVF_U_UN
:
249 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
250 /* Clean out the upper word */
251 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
254 case OP_LCONV_TO_OVF_I1
:
255 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 127);
256 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
257 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, -128);
258 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
259 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
262 case OP_LCONV_TO_OVF_I1_UN
:
263 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 127);
264 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
265 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
268 case OP_LCONV_TO_OVF_U1
:
269 /* probe value to be within 0 to 255 */
270 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 255);
271 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
272 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
275 case OP_LCONV_TO_OVF_U1_UN
:
276 /* probe value to be within 0 to 255 */
277 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 255);
278 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
279 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
282 case OP_LCONV_TO_OVF_I2
:
283 /* Probe value to be within -32768 and 32767 */
284 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 32767);
285 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
286 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, -32768);
287 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
288 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
291 case OP_LCONV_TO_OVF_I2_UN
:
292 /* Probe value to be within 0 and 32767 */
293 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 32767);
294 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
295 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
298 case OP_LCONV_TO_OVF_U2
:
299 /* Probe value to be within 0 and 65535 */
300 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
301 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
302 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
305 case OP_LCONV_TO_OVF_U2_UN
:
306 /* Probe value to be within 0 and 65535 */
307 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
308 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
309 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
312 case OP_LCONV_TO_OVF_I4
:
313 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
314 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
315 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
316 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, ((int)-2147483648));
317 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
318 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
321 case OP_LCONV_TO_OVF_I4_UN
:
322 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
323 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
324 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
327 case OP_LCONV_TO_OVF_U4
:
328 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffffUL
);
329 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
330 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, ins
->sreg1
, 0);
331 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
332 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
335 case OP_LCONV_TO_OVF_U4_UN
:
336 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffff);
337 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
338 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
341 case OP_LCONV_TO_OVF_I
:
342 case OP_LCONV_TO_OVF_U_UN
:
343 case OP_LCONV_TO_OVF_U8_UN
:
344 case OP_LCONV_TO_OVF_I8
:
345 ins
->opcode
= OP_MOVE
;
347 case OP_LCONV_TO_OVF_I_UN
:
348 case OP_LCONV_TO_OVF_I8_UN
:
349 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, ins
->sreg1
, 0);
350 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
351 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
354 case OP_LCONV_TO_OVF_U8
:
355 case OP_LCONV_TO_OVF_U
:
356 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, ins
->sreg1
, 0);
357 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
358 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
364 MonoJitICallInfo
*info
;
366 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
371 /* Create dummy MonoInst's for the arguments */
372 g_assert (!info
->sig
->hasthis
);
373 g_assert (info
->sig
->param_count
<= MONO_MAX_SRC_REGS
);
375 args
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
*) * info
->sig
->param_count
);
376 if (info
->sig
->param_count
> 0) {
377 int sregs
[MONO_MAX_SRC_REGS
];
379 num_sregs
= mono_inst_get_src_registers (ins
, sregs
);
380 g_assert (num_sregs
== info
->sig
->param_count
);
381 for (i
= 0; i
< num_sregs
; ++i
) {
382 MONO_INST_NEW (cfg
, args
[i
], OP_ARG
);
383 args
[i
]->dreg
= sregs
[i
];
387 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, args
);
388 call
->dreg
= ins
->dreg
;
396 if (ins
->opcode
== OP_NOP
) {
401 /* Use the last emitted instruction */
402 ins
= cfg
->cbb
->last_ins
;
405 g_assert (ins
->dreg
== dreg
);
413 #if SIZEOF_REGISTER == 4
414 static int lbr_decomp
[][2] = {
416 {OP_IBGT
, OP_IBGE_UN
}, /* BGE */
417 {OP_IBGT
, OP_IBGT_UN
}, /* BGT */
418 {OP_IBLT
, OP_IBLE_UN
}, /* BLE */
419 {OP_IBLT
, OP_IBLT_UN
}, /* BLT */
421 {OP_IBGT_UN
, OP_IBGE_UN
}, /* BGE_UN */
422 {OP_IBGT_UN
, OP_IBGT_UN
}, /* BGT_UN */
423 {OP_IBLT_UN
, OP_IBLE_UN
}, /* BLE_UN */
424 {OP_IBLT_UN
, OP_IBLT_UN
}, /* BLT_UN */
427 static int lcset_decomp
[][2] = {
429 {OP_IBLT
, OP_IBLE_UN
}, /* CGT */
430 {OP_IBLT_UN
, OP_IBLE_UN
}, /* CGT_UN */
431 {OP_IBGT
, OP_IBGE_UN
}, /* CLT */
432 {OP_IBGT_UN
, OP_IBGE_UN
}, /* CLT_UN */
437 * mono_decompose_long_opts:
439 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
442 mono_decompose_long_opts (MonoCompile
*cfg
)
444 #if SIZEOF_REGISTER == 4
445 MonoBasicBlock
*bb
, *first_bb
;
448 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
449 * needs to be able to handle long vregs.
452 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
455 * Create a dummy bblock and emit code into it so we can use the normal
456 * code generation macros.
458 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
461 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
462 MonoInst
*tree
= bb
->code
;
463 MonoInst
*prev
= NULL
;
466 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
470 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
474 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
475 mono_arch_decompose_long_opts (cfg
, tree
);
478 switch (tree
->opcode
) {
480 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 1, tree
->inst_ls_word
);
481 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, tree
->inst_ms_word
);
486 case OP_LCONV_TO_OVF_U8_UN
:
487 case OP_LCONV_TO_OVF_I8
:
488 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
+ 1);
489 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 2, tree
->sreg1
+ 2);
491 case OP_STOREI8_MEMBASE_REG
:
492 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, tree
->inst_destbasereg
, tree
->inst_offset
+ MINI_MS_WORD_OFFSET
, tree
->sreg1
+ 2);
493 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, tree
->inst_destbasereg
, tree
->inst_offset
+ MINI_LS_WORD_OFFSET
, tree
->sreg1
+ 1);
495 case OP_LOADI8_MEMBASE
:
496 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, tree
->dreg
+ 2, tree
->inst_basereg
, tree
->inst_offset
+ MINI_MS_WORD_OFFSET
);
497 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, tree
->dreg
+ 1, tree
->inst_basereg
, tree
->inst_offset
+ MINI_LS_WORD_OFFSET
);
500 case OP_ICONV_TO_I8
: {
501 guint32 tmpreg
= alloc_ireg (cfg
);
505 * tmp = low > -1 ? 1: 0;
506 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
508 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
509 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, tree
->dreg
+ 1, -1);
510 MONO_EMIT_NEW_BIALU (cfg
, OP_ICGT
, tmpreg
, -1, -1);
511 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, tree
->dreg
+ 2, tmpreg
, 1);
515 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
516 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, 0);
518 case OP_ICONV_TO_OVF_I8
:
519 /* a signed 32 bit num always fits in a signed 64 bit one */
520 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tree
->dreg
+ 2, tree
->sreg1
, 31);
521 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
523 case OP_ICONV_TO_OVF_U8
:
524 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
, 0);
525 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
526 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, 0);
527 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
529 case OP_ICONV_TO_OVF_I8_UN
:
530 case OP_ICONV_TO_OVF_U8_UN
:
531 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
532 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, 0);
533 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
536 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, tree
->sreg1
+ 1);
539 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U1
, tree
->dreg
, tree
->sreg1
+ 1);
542 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, tree
->sreg1
+ 1);
545 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U2
, tree
->dreg
, tree
->sreg1
+ 1);
551 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, tree
->sreg1
+ 1);
554 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R8_2
, tree
->dreg
, tree
->sreg1
+ 1, tree
->sreg1
+ 2);
557 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R4_2
, tree
->dreg
, tree
->sreg1
+ 1, tree
->sreg1
+ 2);
559 case OP_LCONV_TO_R_UN
:
560 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R_UN_2
, tree
->dreg
, tree
->sreg1
+ 1, tree
->sreg1
+ 2);
562 case OP_LCONV_TO_OVF_I1
: {
563 MonoBasicBlock
*is_negative
, *end_label
;
565 NEW_BBLOCK (cfg
, is_negative
);
566 NEW_BBLOCK (cfg
, end_label
);
568 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
569 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
570 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, -1);
571 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
573 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
574 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
577 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 127);
578 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
579 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
582 MONO_START_BB (cfg
, is_negative
);
583 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, -128);
584 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
586 MONO_START_BB (cfg
, end_label
);
588 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, tree
->sreg1
+ 1);
591 case OP_LCONV_TO_OVF_I1_UN
:
592 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
593 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
595 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 127);
596 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
597 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, -128);
598 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
599 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, tree
->sreg1
+ 1);
601 case OP_LCONV_TO_OVF_U1
:
602 case OP_LCONV_TO_OVF_U1_UN
:
603 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
604 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
606 /* probe value to be within 0 to 255 */
607 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 255);
608 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
609 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, tree
->sreg1
+ 1, 0xff);
611 case OP_LCONV_TO_OVF_I2
: {
612 MonoBasicBlock
*is_negative
, *end_label
;
614 NEW_BBLOCK (cfg
, is_negative
);
615 NEW_BBLOCK (cfg
, end_label
);
617 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
618 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
619 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, -1);
620 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
622 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
623 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
626 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 32767);
627 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
628 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
631 MONO_START_BB (cfg
, is_negative
);
632 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, -32768);
633 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
634 MONO_START_BB (cfg
, end_label
);
636 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, tree
->sreg1
+ 1);
639 case OP_LCONV_TO_OVF_I2_UN
:
640 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
641 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
643 /* Probe value to be within -32768 and 32767 */
644 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 32767);
645 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
646 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, -32768);
647 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
648 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, tree
->sreg1
+ 1);
650 case OP_LCONV_TO_OVF_U2
:
651 case OP_LCONV_TO_OVF_U2_UN
:
652 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
653 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
655 /* Probe value to be within 0 and 65535 */
656 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 0xffff);
657 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
658 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, tree
->sreg1
+ 1, 0xffff);
660 case OP_LCONV_TO_OVF_I4
:
661 case OP_LCONV_TO_OVF_I
:
662 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_OVF_I4_2
, tree
->dreg
, tree
->sreg1
+ 1, tree
->sreg1
+ 2);
664 case OP_LCONV_TO_OVF_U4
:
665 case OP_LCONV_TO_OVF_U
:
666 case OP_LCONV_TO_OVF_U4_UN
:
667 case OP_LCONV_TO_OVF_U_UN
:
668 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
669 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
670 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, tree
->sreg1
+ 1);
672 case OP_LCONV_TO_OVF_I_UN
:
673 case OP_LCONV_TO_OVF_I4_UN
:
674 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
675 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
676 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 1, 0);
677 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
678 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, tree
->sreg1
+ 1);
680 case OP_LCONV_TO_OVF_U8
:
681 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
682 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
684 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
+ 1);
685 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 2, tree
->sreg1
+ 2);
687 case OP_LCONV_TO_OVF_I8_UN
:
688 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
689 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
691 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
+ 1);
692 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 2, tree
->sreg1
+ 2);
696 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
697 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
700 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
701 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
705 /* ADC sets the condition code */
706 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
707 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
708 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
711 /* ADC sets the condition code */
712 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
713 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
714 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
717 /* SBB sets the condition code */
718 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
719 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
720 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
723 /* SBB sets the condition code */
724 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
725 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
726 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
729 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
730 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
733 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
734 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
737 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
738 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
741 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tree
->dreg
+ 1, tree
->sreg1
+ 1);
742 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tree
->dreg
+ 2, tree
->sreg1
+ 2);
745 /* Handled in mono_arch_decompose_long_opts () */
746 g_assert_not_reached ();
750 /* FIXME: Add OP_BIGMUL optimization */
754 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADDCC_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
755 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADC_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
758 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SUBCC_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
759 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SBB_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
762 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
763 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
766 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
767 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
770 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
771 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
774 if (tree
->inst_c1
== 32) {
776 /* The original code had this comment: */
777 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
778 * later apply the speedup to the left shift as well
781 /* FIXME: Move this to the strength reduction pass */
782 /* just move the upper half to the lower and zero the high word */
783 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
+ 2);
784 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, 0);
788 if (tree
->inst_c1
== 32) {
789 /* just move the lower half to the upper and zero the lower word */
790 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 2, tree
->sreg1
+ 1);
791 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 1, 0);
796 MonoInst
*next
= tree
->next
;
800 switch (next
->opcode
) {
805 /* Branchless version based on gcc code */
806 d1
= alloc_ireg (cfg
);
807 d2
= alloc_ireg (cfg
);
808 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
809 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
810 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
811 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
812 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
813 next
->opcode
= OP_NOP
;
824 /* Convert into three comparisons + branches */
825 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
826 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
827 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
828 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
829 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
830 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
831 next
->opcode
= OP_NOP
;
836 /* Branchless version based on gcc code */
837 d1
= alloc_ireg (cfg
);
838 d2
= alloc_ireg (cfg
);
839 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
840 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
841 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
843 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
844 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
845 next
->opcode
= OP_NOP
;
852 MonoBasicBlock
*set_to_0
, *set_to_1
;
854 NEW_BBLOCK (cfg
, set_to_0
);
855 NEW_BBLOCK (cfg
, set_to_1
);
857 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
858 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
859 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
860 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
861 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
862 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
863 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
864 MONO_START_BB (cfg
, set_to_1
);
865 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
866 MONO_START_BB (cfg
, set_to_0
);
867 next
->opcode
= OP_NOP
;
871 g_assert_not_reached ();
876 /* Not yet used, since lcompare is decomposed before local cprop */
877 case OP_LCOMPARE_IMM
: {
878 MonoInst
*next
= tree
->next
;
879 guint32 low_imm
= tree
->inst_ls_word
;
880 guint32 high_imm
= tree
->inst_ms_word
;
881 int low_reg
= tree
->sreg1
+ 1;
882 int high_reg
= tree
->sreg1
+ 2;
886 switch (next
->opcode
) {
891 /* Branchless version based on gcc code */
892 d1
= alloc_ireg (cfg
);
893 d2
= alloc_ireg (cfg
);
894 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
895 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
896 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
897 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
898 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
899 next
->opcode
= OP_NOP
;
911 /* Convert into three comparisons + branches */
912 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
913 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
914 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
915 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
916 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
917 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
918 next
->opcode
= OP_NOP
;
923 /* Branchless version based on gcc code */
924 d1
= alloc_ireg (cfg
);
925 d2
= alloc_ireg (cfg
);
926 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
927 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
928 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
930 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
931 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
932 next
->opcode
= OP_NOP
;
939 MonoBasicBlock
*set_to_0
, *set_to_1
;
941 NEW_BBLOCK (cfg
, set_to_0
);
942 NEW_BBLOCK (cfg
, set_to_1
);
944 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
945 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
946 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
947 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
948 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
949 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
950 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
951 MONO_START_BB (cfg
, set_to_1
);
952 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
953 MONO_START_BB (cfg
, set_to_0
);
954 next
->opcode
= OP_NOP
;
958 g_assert_not_reached ();
967 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
970 /* Replace the original instruction with the new code sequence */
972 /* Ignore the new value of prev */
974 mono_replace_ins (cfg
, bb
, tree
, &new_prev
, first_bb
, cfg
->cbb
);
976 /* Process the newly added ops again since they can be long ops too */
982 first_bb
->code
= first_bb
->last_ins
= NULL
;
983 first_bb
->in_count
= first_bb
->out_count
= 0;
995 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
996 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1001 * mono_decompose_vtype_opts:
1003 * Decompose valuetype opcodes.
1006 mono_decompose_vtype_opts (MonoCompile
*cfg
)
1008 MonoBasicBlock
*bb
, *first_bb
;
1011 * Using OP_V opcodes and decomposing them later have two main benefits:
1012 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1014 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1015 * enabling optimizations to work on vtypes too.
1016 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1017 * can be executed anytime. It should be executed as late as possible so vtype
1018 * opcodes can be optimized by the other passes.
1019 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1020 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1022 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1023 * when OP_VMOVE opcodes are decomposed.
1027 * Vregs have no associated type information, so we store the type of the vregs
1032 * Create a dummy bblock and emit code into it so we can use the normal
1033 * code generation macros.
1035 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1036 first_bb
= cfg
->cbb
;
1038 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1040 MonoInst
*prev
= NULL
;
1041 MonoInst
*src_var
, *dest_var
, *src
, *dest
;
1045 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "BEFORE LOWER-VTYPE-OPTS ");
1047 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1053 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1054 switch (ins
->opcode
) {
1056 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1057 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1059 g_assert (ins
->klass
);
1062 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1065 dest_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1068 if (src_var
->backend
.is_pinvoke
)
1069 dest_var
->backend
.is_pinvoke
= 1;
1071 EMIT_NEW_VARLOADA ((cfg
), (src
), src_var
, src_var
->inst_vtype
);
1072 EMIT_NEW_VARLOADA ((cfg
), (dest
), dest_var
, dest_var
->inst_vtype
);
1074 mini_emit_stobj (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
);
1078 g_assert (ins
->klass
);
1080 EMIT_NEW_VARLOADA_VREG (cfg
, dest
, ins
->dreg
, &ins
->klass
->byval_arg
);
1081 mini_emit_initobj (cfg
, dest
, NULL
, ins
->klass
);
1083 case OP_STOREV_MEMBASE
: {
1084 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1087 g_assert (ins
->klass
);
1088 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->sreg1
);
1091 EMIT_NEW_VARLOADA_VREG ((cfg
), (src
), ins
->sreg1
, &ins
->klass
->byval_arg
);
1093 dreg
= alloc_preg (cfg
);
1094 EMIT_NEW_BIALU_IMM (cfg
, dest
, OP_ADD_IMM
, dreg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1095 mini_emit_stobj (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
);
1098 case OP_LOADV_MEMBASE
: {
1099 g_assert (ins
->klass
);
1101 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1104 dest_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1106 dreg
= alloc_preg (cfg
);
1107 EMIT_NEW_BIALU_IMM (cfg
, src
, OP_ADD_IMM
, dreg
, ins
->inst_basereg
, ins
->inst_offset
);
1108 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1109 mini_emit_stobj (cfg
, dest
, src
, dest_var
->klass
, dest_var
->backend
.is_pinvoke
);
1112 case OP_OUTARG_VT
: {
1113 g_assert (ins
->klass
);
1115 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1117 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->sreg1
);
1118 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1120 mono_arch_emit_outarg_vt (cfg
, ins
, src
);
1122 /* This might be decomposed into other vtype opcodes */
1126 case OP_OUTARG_VTRETADDR
: {
1127 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p1
;
1129 src_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1131 src_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1132 // FIXME: src_var->backend.is_pinvoke ?
1134 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1135 src
->dreg
= ins
->dreg
;
1140 case OP_VCALL_MEMBASE
: {
1141 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1144 if (call
->vret_in_reg
) {
1145 MonoCallInst
*call2
;
1147 /* Replace the vcall with an integer call */
1148 MONO_INST_NEW_CALL (cfg
, call2
, OP_NOP
);
1149 memcpy (call2
, call
, sizeof (MonoCallInst
));
1150 switch (ins
->opcode
) {
1152 call2
->inst
.opcode
= OP_CALL
;
1155 call2
->inst
.opcode
= OP_CALL_REG
;
1157 case OP_VCALL_MEMBASE
:
1158 call2
->inst
.opcode
= OP_CALL_MEMBASE
;
1161 call2
->inst
.dreg
= alloc_preg (cfg
);
1162 MONO_ADD_INS (cfg
->cbb
, ((MonoInst
*)call2
));
1164 /* Compute the vtype location */
1165 dest_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1167 dest_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1168 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1170 /* Save the result */
1171 if (dest_var
->backend
.is_pinvoke
)
1172 size
= mono_class_native_size (mono_class_from_mono_type (dest_var
->inst_vtype
), NULL
);
1174 size
= mono_type_size (dest_var
->inst_vtype
, NULL
);
1177 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI1_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1180 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI2_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1183 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1186 #if SIZEOF_REGISTER == 4
1188 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1189 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1191 switch (call2
->inst
.opcode
) {
1193 call2
->inst
.opcode
= OP_LCALL
;
1196 call2
->inst
.opcode
= OP_LCALL_REG
;
1198 case OP_CALL_MEMBASE
:
1199 call2
->inst
.opcode
= OP_LCALL_MEMBASE
;
1202 call2
->inst
.dreg
= alloc_lreg (cfg
);
1203 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_MS_WORD_OFFSET
, call2
->inst
.dreg
+ 2);
1204 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_LS_WORD_OFFSET
, call2
->inst
.dreg
+ 1);
1206 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1210 /* This assumes the vtype is sizeof (gpointer) long */
1211 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1215 switch (ins
->opcode
) {
1217 ins
->opcode
= OP_VCALL2
;
1220 ins
->opcode
= OP_VCALL2_REG
;
1222 case OP_VCALL_MEMBASE
:
1223 ins
->opcode
= OP_VCALL2_MEMBASE
;
1234 g_assert (cfg
->cbb
== first_bb
);
1236 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1237 /* Replace the original instruction with the new code sequence */
1239 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1240 first_bb
->code
= first_bb
->last_ins
= NULL
;
1241 first_bb
->in_count
= first_bb
->out_count
= 0;
1242 cfg
->cbb
= first_bb
;
1249 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "AFTER LOWER-VTYPE-OPTS ");
1253 inline static MonoInst
*
1254 mono_get_domainvar (MonoCompile
*cfg
)
1256 if (!cfg
->domainvar
)
1257 cfg
->domainvar
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_LOCAL
);
1258 return cfg
->domainvar
;
1262 * mono_decompose_array_access_opts:
1264 * Decompose array access opcodes.
1267 mono_decompose_array_access_opts (MonoCompile
*cfg
)
1269 MonoBasicBlock
*bb
, *first_bb
;
1272 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1273 * can be executed anytime. It should be run before decompose_long
1277 * Create a dummy bblock and emit code into it so we can use the normal
1278 * code generation macros.
1280 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1281 first_bb
= cfg
->cbb
;
1283 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1285 MonoInst
*prev
= NULL
;
1287 MonoInst
*iargs
[3];
1290 if (!bb
->has_array_access
)
1293 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1295 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1301 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1302 switch (ins
->opcode
) {
1304 NEW_LOAD_MEMBASE_FLAGS (cfg
, dest
, OP_LOADI4_MEMBASE
, ins
->dreg
, ins
->sreg1
,
1305 G_STRUCT_OFFSET (MonoArray
, max_length
), ins
->flags
| MONO_INST_CONSTANT_LOAD
);
1306 MONO_ADD_INS (cfg
->cbb
, dest
);
1308 case OP_BOUNDS_CHECK
:
1309 MONO_EMIT_NULL_CHECK (cfg
, ins
->sreg1
);
1310 if (COMPILE_LLVM (cfg
))
1311 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, ins
->sreg2
, ins
->flags
& MONO_INST_FAULT
);
1313 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, ins
->sreg2
);
1316 if (cfg
->opt
& MONO_OPT_SHARED
) {
1317 EMIT_NEW_DOMAINCONST (cfg
, iargs
[0]);
1318 EMIT_NEW_CLASSCONST (cfg
, iargs
[1], ins
->inst_newa_class
);
1319 MONO_INST_NEW (cfg
, iargs
[2], OP_MOVE
);
1320 iargs
[2]->dreg
= ins
->sreg1
;
1322 dest
= mono_emit_jit_icall (cfg
, mono_array_new
, iargs
);
1323 dest
->dreg
= ins
->dreg
;
1325 MonoVTable
*vtable
= mono_class_vtable (cfg
->domain
, mono_array_class_get (ins
->inst_newa_class
, 1));
1326 MonoMethod
*managed_alloc
= mono_gc_get_managed_array_allocator (vtable
, 1);
1328 g_assert (vtable
); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1329 NEW_VTABLECONST (cfg
, iargs
[0], vtable
);
1330 MONO_ADD_INS (cfg
->cbb
, iargs
[0]);
1331 MONO_INST_NEW (cfg
, iargs
[1], OP_MOVE
);
1332 iargs
[1]->dreg
= ins
->sreg1
;
1335 dest
= mono_emit_method_call (cfg
, managed_alloc
, iargs
, NULL
);
1337 dest
= mono_emit_jit_icall (cfg
, mono_array_new_specific
, iargs
);
1338 dest
->dreg
= ins
->dreg
;
1342 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg
, OP_LOADI4_MEMBASE
, ins
->dreg
,
1343 ins
->sreg1
, G_STRUCT_OFFSET (MonoString
, length
), ins
->flags
| MONO_INST_CONSTANT_LOAD
);
1349 g_assert (cfg
->cbb
== first_bb
);
1351 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1352 /* Replace the original instruction with the new code sequence */
1354 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1355 first_bb
->code
= first_bb
->last_ins
= NULL
;
1356 first_bb
->in_count
= first_bb
->out_count
= 0;
1357 cfg
->cbb
= first_bb
;
1364 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1374 #ifdef MONO_ARCH_SOFT_FLOAT
1377 * mono_decompose_soft_float:
1379 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1380 * similar to long support on 32 bit platforms. 32 bit float values require special
1381 * handling when used as locals, arguments, and in calls.
1382 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1385 mono_decompose_soft_float (MonoCompile
*cfg
)
1387 MonoBasicBlock
*bb
, *first_bb
;
1390 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1394 * Create a dummy bblock and emit code into it so we can use the normal
1395 * code generation macros.
1397 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1398 first_bb
= cfg
->cbb
;
1400 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1402 MonoInst
*prev
= NULL
;
1405 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE HANDLE-SOFT-FLOAT ");
1407 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1413 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1414 const char *spec
= INS_INFO (ins
->opcode
);
1416 /* Most fp operations are handled automatically by opcode emulation */
1418 switch (ins
->opcode
) {
1421 d
.vald
= *(double*)ins
->inst_p0
;
1422 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1427 /* We load the r8 value */
1428 d
.vald
= *(float*)ins
->inst_p0
;
1429 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1433 ins
->opcode
= OP_LMOVE
;
1436 ins
->opcode
= OP_MOVE
;
1437 ins
->sreg1
= ins
->sreg1
+ 1;
1440 ins
->opcode
= OP_MOVE
;
1441 ins
->sreg1
= ins
->sreg1
+ 2;
1444 int reg
= ins
->sreg1
;
1446 ins
->opcode
= OP_SETLRET
;
1448 ins
->sreg1
= reg
+ 1;
1449 ins
->sreg2
= reg
+ 2;
1452 case OP_LOADR8_MEMBASE
:
1453 ins
->opcode
= OP_LOADI8_MEMBASE
;
1455 case OP_STORER8_MEMBASE_REG
:
1456 ins
->opcode
= OP_STOREI8_MEMBASE_REG
;
1458 case OP_STORER4_MEMBASE_REG
: {
1459 MonoInst
*iargs
[2];
1462 /* Arg 1 is the double value */
1463 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1464 iargs
[0]->dreg
= ins
->sreg1
;
1466 /* Arg 2 is the address to store to */
1467 addr_reg
= mono_alloc_preg (cfg
);
1468 EMIT_NEW_BIALU_IMM (cfg
, iargs
[1], OP_PADD_IMM
, addr_reg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1469 mono_emit_jit_icall (cfg
, mono_fstore_r4
, iargs
);
1473 case OP_LOADR4_MEMBASE
: {
1474 MonoInst
*iargs
[1];
1478 addr_reg
= mono_alloc_preg (cfg
);
1479 EMIT_NEW_BIALU_IMM (cfg
, iargs
[0], OP_PADD_IMM
, addr_reg
, ins
->inst_basereg
, ins
->inst_offset
);
1480 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1481 conv
->dreg
= ins
->dreg
;
1486 case OP_FCALL_MEMBASE
: {
1487 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1488 if (call
->signature
->ret
->type
== MONO_TYPE_R4
) {
1489 MonoCallInst
*call2
;
1490 MonoInst
*iargs
[1];
1493 /* Convert the call into a call returning an int */
1494 MONO_INST_NEW_CALL (cfg
, call2
, OP_CALL
);
1495 memcpy (call2
, call
, sizeof (MonoCallInst
));
1496 switch (ins
->opcode
) {
1498 call2
->inst
.opcode
= OP_CALL
;
1501 call2
->inst
.opcode
= OP_CALL_REG
;
1503 case OP_FCALL_MEMBASE
:
1504 call2
->inst
.opcode
= OP_CALL_MEMBASE
;
1507 g_assert_not_reached ();
1509 call2
->inst
.dreg
= mono_alloc_ireg (cfg
);
1510 MONO_ADD_INS (cfg
->cbb
, (MonoInst
*)call2
);
1512 /* FIXME: Optimize this */
1514 /* Emit an r4->r8 conversion */
1515 EMIT_NEW_VARLOADA_VREG (cfg
, iargs
[0], call2
->inst
.dreg
, &mono_defaults
.int32_class
->byval_arg
);
1516 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1517 conv
->dreg
= ins
->dreg
;
1519 /* The call sequence might include fp ins */
1522 switch (ins
->opcode
) {
1524 ins
->opcode
= OP_LCALL
;
1527 ins
->opcode
= OP_LCALL_REG
;
1529 case OP_FCALL_MEMBASE
:
1530 ins
->opcode
= OP_LCALL_MEMBASE
;
1533 g_assert_not_reached ();
1539 MonoJitICallInfo
*info
;
1540 MonoInst
*iargs
[2];
1541 MonoInst
*call
, *cmp
, *br
;
1543 /* Convert fcompare+fbcc to icall+icompare+beq */
1545 info
= mono_find_jit_opcode_emulation (ins
->next
->opcode
);
1548 /* Create dummy MonoInst's for the arguments */
1549 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1550 iargs
[0]->dreg
= ins
->sreg1
;
1551 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1552 iargs
[1]->dreg
= ins
->sreg2
;
1554 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, iargs
);
1556 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1557 cmp
->sreg1
= call
->dreg
;
1559 MONO_ADD_INS (cfg
->cbb
, cmp
);
1561 MONO_INST_NEW (cfg
, br
, OP_IBNE_UN
);
1562 br
->inst_many_bb
= mono_mempool_alloc (cfg
->mempool
, sizeof (gpointer
) * 2);
1563 br
->inst_true_bb
= ins
->next
->inst_true_bb
;
1564 br
->inst_false_bb
= ins
->next
->inst_false_bb
;
1565 MONO_ADD_INS (cfg
->cbb
, br
);
1567 /* The call sequence might include fp ins */
1570 /* Skip fbcc or fccc */
1571 NULLIFY_INS (ins
->next
);
1579 MonoJitICallInfo
*info
;
1580 MonoInst
*iargs
[2];
1583 /* Convert fccc to icall+icompare+iceq */
1585 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
1588 /* Create dummy MonoInst's for the arguments */
1589 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1590 iargs
[0]->dreg
= ins
->sreg1
;
1591 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1592 iargs
[1]->dreg
= ins
->sreg2
;
1594 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, iargs
);
1596 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, call
->dreg
, 1);
1597 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, ins
->dreg
, -1);
1599 /* The call sequence might include fp ins */
1604 MonoInst
*iargs
[2];
1605 MonoInst
*call
, *cmp
;
1607 /* Convert to icall+icompare+cond_exc+move */
1609 /* Create dummy MonoInst's for the arguments */
1610 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1611 iargs
[0]->dreg
= ins
->sreg1
;
1613 call
= mono_emit_jit_icall (cfg
, mono_isfinite
, iargs
);
1615 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1616 cmp
->sreg1
= call
->dreg
;
1618 MONO_ADD_INS (cfg
->cbb
, cmp
);
1620 MONO_EMIT_NEW_COND_EXC (cfg
, INE_UN
, "ArithmeticException");
1622 /* Do the assignment if the value is finite */
1623 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, ins
->dreg
, ins
->sreg1
);
1629 if (spec
[MONO_INST_SRC1
] == 'f' || spec
[MONO_INST_SRC2
] == 'f' || spec
[MONO_INST_DEST
] == 'f') {
1630 mono_print_ins (ins
);
1631 g_assert_not_reached ();
1636 g_assert (cfg
->cbb
== first_bb
);
1638 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1639 /* Replace the original instruction with the new code sequence */
1641 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1642 first_bb
->code
= first_bb
->last_ins
= NULL
;
1643 first_bb
->in_count
= first_bb
->out_count
= 0;
1644 cfg
->cbb
= first_bb
;
1651 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER HANDLE-SOFT-FLOAT ");
1654 mono_decompose_long_opts (cfg
);
1659 #endif /* DISABLE_JIT */