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
);
23 /* Decompose complex long opcodes on 64 bit machines or when using LLVM */
25 decompose_long_opcode (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
**repl_ins
)
27 MonoInst
*repl
= NULL
;
31 switch (ins
->opcode
) {
33 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_LSHR_IMM
, ins
->dreg
, ins
->sreg1
, 0);
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
))
56 EMIT_NEW_BIALU (cfg
, repl
, OP_ADDCC
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
57 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
61 if (COMPILE_LLVM (cfg
))
63 EMIT_NEW_BIALU (cfg
, repl
, OP_ADDCC
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
64 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
67 #ifndef __mono_ppc64__
69 if (COMPILE_LLVM (cfg
))
71 EMIT_NEW_BIALU (cfg
, repl
, OP_SUBCC
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
72 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
76 if (COMPILE_LLVM (cfg
))
78 EMIT_NEW_BIALU (cfg
, repl
, OP_SUBCC
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
79 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
84 case OP_ICONV_TO_OVF_I8
:
85 case OP_ICONV_TO_OVF_I
:
86 ins
->opcode
= OP_SEXT_I4
;
88 case OP_ICONV_TO_OVF_U8
:
89 case OP_ICONV_TO_OVF_U
:
90 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
,ins
->sreg1
, 0);
91 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
92 MONO_EMIT_NEW_UNALU (cfg
, OP_ZEXT_I4
, ins
->dreg
, ins
->sreg1
);
95 case OP_ICONV_TO_OVF_I8_UN
:
96 case OP_ICONV_TO_OVF_U8_UN
:
97 case OP_ICONV_TO_OVF_I_UN
:
98 case OP_ICONV_TO_OVF_U_UN
:
99 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
100 /* Clean out the upper word */
101 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
104 case OP_LCONV_TO_OVF_I1
:
105 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 127);
106 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
107 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -128);
108 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
109 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
112 case OP_LCONV_TO_OVF_I1_UN
:
113 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 127);
114 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
115 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
118 case OP_LCONV_TO_OVF_U1
:
119 /* probe value to be within 0 to 255 */
120 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 255);
121 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
122 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
125 case OP_LCONV_TO_OVF_U1_UN
:
126 /* probe value to be within 0 to 255 */
127 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 255);
128 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
129 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
132 case OP_LCONV_TO_OVF_I2
:
133 /* Probe value to be within -32768 and 32767 */
134 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
135 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
136 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
137 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
138 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
141 case OP_LCONV_TO_OVF_I2_UN
:
142 /* Probe value to be within 0 and 32767 */
143 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
144 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
145 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
148 case OP_LCONV_TO_OVF_U2
:
149 /* Probe value to be within 0 and 65535 */
150 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
151 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
152 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
155 case OP_LCONV_TO_OVF_U2_UN
:
156 /* Probe value to be within 0 and 65535 */
157 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
158 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
159 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
162 case OP_LCONV_TO_OVF_I4
:
163 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
164 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
165 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
166 #if SIZEOF_REGISTER == 8
167 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, ((int)-2147483648));
169 g_assert (COMPILE_LLVM (cfg
));
170 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -2147483648LL);
172 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
173 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
176 case OP_LCONV_TO_OVF_I4_UN
:
177 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
178 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
179 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
182 case OP_LCONV_TO_OVF_U4
:
183 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffffUL
);
184 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
185 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
186 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
187 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
190 case OP_LCONV_TO_OVF_U4_UN
:
191 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffff);
192 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
193 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
196 case OP_LCONV_TO_OVF_I
:
197 case OP_LCONV_TO_OVF_U_UN
:
198 case OP_LCONV_TO_OVF_U8_UN
:
199 case OP_LCONV_TO_OVF_I8
:
200 ins
->opcode
= OP_MOVE
;
202 case OP_LCONV_TO_OVF_I_UN
:
203 case OP_LCONV_TO_OVF_I8_UN
:
204 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
205 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
206 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
209 case OP_LCONV_TO_OVF_U8
:
210 case OP_LCONV_TO_OVF_U
:
211 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
212 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
213 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
225 * mono_decompose_opcode:
227 * Decompose complex opcodes into ones closer to opcodes supported by
228 * the given architecture.
229 * Returns a MonoInst which represents the result of the decomposition, and can
230 * be pushed on the IL stack. This is needed because the original instruction is
232 * Sets the cfg exception if an opcode is not supported.
235 mono_decompose_opcode (MonoCompile
*cfg
, MonoInst
*ins
)
237 MonoInst
*repl
= NULL
;
238 int type
= ins
->type
;
239 int dreg
= ins
->dreg
;
241 /* FIXME: Instead of = NOP, don't emit the original ins at all */
243 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
244 mono_arch_decompose_opts (cfg
, ins
);
248 * The code below assumes that we are called immediately after emitting
249 * ins. This means we can emit code using the normal code generation
252 switch (ins
->opcode
) {
253 /* this doesn't make sense on ppc and other architectures */
254 #if !defined(MONO_ARCH_NO_IOV_CHECK)
256 if (COMPILE_LLVM (cfg
))
258 ins
->opcode
= OP_IADDCC
;
259 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
262 if (COMPILE_LLVM (cfg
))
264 ins
->opcode
= OP_IADDCC
;
265 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
268 if (COMPILE_LLVM (cfg
))
270 ins
->opcode
= OP_ISUBCC
;
271 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
274 if (COMPILE_LLVM (cfg
))
276 ins
->opcode
= OP_ISUBCC
;
277 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
280 case OP_ICONV_TO_OVF_I1
:
281 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
282 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
283 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -128);
284 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
285 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
288 case OP_ICONV_TO_OVF_I1_UN
:
289 /* probe values between 0 to 127 */
290 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
291 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
292 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
295 case OP_ICONV_TO_OVF_U1
:
296 case OP_ICONV_TO_OVF_U1_UN
:
297 /* probe value to be within 0 to 255 */
298 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 255);
299 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
300 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
303 case OP_ICONV_TO_OVF_I2
:
304 /* Probe value to be within -32768 and 32767 */
305 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
306 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
307 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
308 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
309 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
312 case OP_ICONV_TO_OVF_I2_UN
:
313 /* Convert uint value into short, value within 0 and 32767 */
314 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
315 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
316 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
319 case OP_ICONV_TO_OVF_U2
:
320 case OP_ICONV_TO_OVF_U2_UN
:
321 /* Probe value to be within 0 and 65535 */
322 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
323 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
324 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
327 case OP_ICONV_TO_OVF_U4
:
328 case OP_ICONV_TO_OVF_I4_UN
:
329 #if SIZEOF_REGISTER == 4
330 case OP_ICONV_TO_OVF_U
:
331 case OP_ICONV_TO_OVF_I_UN
:
333 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0);
334 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
335 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
340 case OP_ICONV_TO_OVF_I4
:
341 case OP_ICONV_TO_OVF_U4_UN
:
342 #if SIZEOF_REGISTER == 4
343 case OP_ICONV_TO_OVF_I
:
344 case OP_ICONV_TO_OVF_U_UN
:
346 ins
->opcode
= OP_MOVE
;
349 #if SIZEOF_REGISTER == 8
350 ins
->opcode
= OP_SEXT_I4
;
352 ins
->opcode
= OP_MOVE
;
356 #if SIZEOF_REGISTER == 8
357 ins
->opcode
= OP_ZEXT_I4
;
359 ins
->opcode
= OP_MOVE
;
364 ins
->opcode
= OP_FMOVE
;
367 case OP_FCONV_TO_OVF_I1_UN
:
368 case OP_FCONV_TO_OVF_I2_UN
:
369 case OP_FCONV_TO_OVF_I4_UN
:
370 case OP_FCONV_TO_OVF_I8_UN
:
371 case OP_FCONV_TO_OVF_U1_UN
:
372 case OP_FCONV_TO_OVF_U2_UN
:
373 case OP_FCONV_TO_OVF_U4_UN
:
374 case OP_FCONV_TO_OVF_U8_UN
:
375 case OP_FCONV_TO_OVF_I_UN
:
376 case OP_FCONV_TO_OVF_U_UN
:
377 cfg
->exception_type
= MONO_EXCEPTION_INVALID_PROGRAM
;
378 cfg
->exception_message
= g_strdup_printf ("float conv.ovf.un opcodes not supported.");
382 MonoJitICallInfo
*info
;
384 #if SIZEOF_REGISTER == 8
385 if (decompose_long_opcode (cfg
, ins
, &repl
))
388 if (COMPILE_LLVM (cfg
) && decompose_long_opcode (cfg
, ins
, &repl
))
392 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
397 /* Create dummy MonoInst's for the arguments */
398 g_assert (!info
->sig
->hasthis
);
399 g_assert (info
->sig
->param_count
<= MONO_MAX_SRC_REGS
);
401 args
= mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
*) * info
->sig
->param_count
);
402 if (info
->sig
->param_count
> 0) {
403 int sregs
[MONO_MAX_SRC_REGS
];
405 num_sregs
= mono_inst_get_src_registers (ins
, sregs
);
406 g_assert (num_sregs
== info
->sig
->param_count
);
407 for (i
= 0; i
< num_sregs
; ++i
) {
408 MONO_INST_NEW (cfg
, args
[i
], OP_ARG
);
409 args
[i
]->dreg
= sregs
[i
];
413 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, args
);
414 call
->dreg
= ins
->dreg
;
422 if (ins
->opcode
== OP_NOP
) {
427 /* Use the last emitted instruction */
428 ins
= cfg
->cbb
->last_ins
;
431 g_assert (ins
->dreg
== dreg
);
439 #if SIZEOF_REGISTER == 4
440 static int lbr_decomp
[][2] = {
442 {OP_IBGT
, OP_IBGE_UN
}, /* BGE */
443 {OP_IBGT
, OP_IBGT_UN
}, /* BGT */
444 {OP_IBLT
, OP_IBLE_UN
}, /* BLE */
445 {OP_IBLT
, OP_IBLT_UN
}, /* BLT */
447 {OP_IBGT_UN
, OP_IBGE_UN
}, /* BGE_UN */
448 {OP_IBGT_UN
, OP_IBGT_UN
}, /* BGT_UN */
449 {OP_IBLT_UN
, OP_IBLE_UN
}, /* BLE_UN */
450 {OP_IBLT_UN
, OP_IBLT_UN
}, /* BLT_UN */
453 static int lcset_decomp
[][2] = {
455 {OP_IBLT
, OP_IBLE_UN
}, /* CGT */
456 {OP_IBLT_UN
, OP_IBLE_UN
}, /* CGT_UN */
457 {OP_IBGT
, OP_IBGE_UN
}, /* CLT */
458 {OP_IBGT_UN
, OP_IBGE_UN
}, /* CLT_UN */
463 * mono_decompose_long_opts:
465 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
468 mono_decompose_long_opts (MonoCompile
*cfg
)
470 #if SIZEOF_REGISTER == 4
471 MonoBasicBlock
*bb
, *first_bb
;
474 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
475 * needs to be able to handle long vregs.
478 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
481 * Create a dummy bblock and emit code into it so we can use the normal
482 * code generation macros.
484 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
487 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
488 MonoInst
*tree
= bb
->code
;
489 MonoInst
*prev
= NULL
;
492 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
496 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
500 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
501 mono_arch_decompose_long_opts (cfg
, tree
);
504 switch (tree
->opcode
) {
506 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 1, tree
->inst_ls_word
);
507 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, tree
->inst_ms_word
);
512 case OP_LCONV_TO_OVF_U8_UN
:
513 case OP_LCONV_TO_OVF_I8
:
514 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
+ 1);
515 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 2, tree
->sreg1
+ 2);
517 case OP_STOREI8_MEMBASE_REG
:
518 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, tree
->inst_destbasereg
, tree
->inst_offset
+ MINI_MS_WORD_OFFSET
, tree
->sreg1
+ 2);
519 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, tree
->inst_destbasereg
, tree
->inst_offset
+ MINI_LS_WORD_OFFSET
, tree
->sreg1
+ 1);
521 case OP_LOADI8_MEMBASE
:
522 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, tree
->dreg
+ 2, tree
->inst_basereg
, tree
->inst_offset
+ MINI_MS_WORD_OFFSET
);
523 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, tree
->dreg
+ 1, tree
->inst_basereg
, tree
->inst_offset
+ MINI_LS_WORD_OFFSET
);
526 case OP_ICONV_TO_I8
: {
527 guint32 tmpreg
= alloc_ireg (cfg
);
531 * tmp = low > -1 ? 1: 0;
532 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
534 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
535 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, tree
->dreg
+ 1, -1);
536 MONO_EMIT_NEW_BIALU (cfg
, OP_ICGT
, tmpreg
, -1, -1);
537 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, tree
->dreg
+ 2, tmpreg
, 1);
541 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
542 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, 0);
544 case OP_ICONV_TO_OVF_I8
:
545 /* a signed 32 bit num always fits in a signed 64 bit one */
546 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, tree
->dreg
+ 2, tree
->sreg1
, 31);
547 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
549 case OP_ICONV_TO_OVF_U8
:
550 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
, 0);
551 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
552 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, 0);
553 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
555 case OP_ICONV_TO_OVF_I8_UN
:
556 case OP_ICONV_TO_OVF_U8_UN
:
557 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
558 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, 0);
559 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
);
562 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, tree
->sreg1
+ 1);
565 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U1
, tree
->dreg
, tree
->sreg1
+ 1);
568 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, tree
->sreg1
+ 1);
571 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U2
, tree
->dreg
, tree
->sreg1
+ 1);
577 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, tree
->sreg1
+ 1);
580 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R8_2
, tree
->dreg
, tree
->sreg1
+ 1, tree
->sreg1
+ 2);
583 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R4_2
, tree
->dreg
, tree
->sreg1
+ 1, tree
->sreg1
+ 2);
585 case OP_LCONV_TO_R_UN
:
586 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R_UN_2
, tree
->dreg
, tree
->sreg1
+ 1, tree
->sreg1
+ 2);
588 case OP_LCONV_TO_OVF_I1
: {
589 MonoBasicBlock
*is_negative
, *end_label
;
591 NEW_BBLOCK (cfg
, is_negative
);
592 NEW_BBLOCK (cfg
, end_label
);
594 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
595 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
596 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, -1);
597 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
599 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
600 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
603 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 127);
604 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
605 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
608 MONO_START_BB (cfg
, is_negative
);
609 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, -128);
610 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
612 MONO_START_BB (cfg
, end_label
);
614 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, tree
->sreg1
+ 1);
617 case OP_LCONV_TO_OVF_I1_UN
:
618 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
619 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
621 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 127);
622 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
623 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, -128);
624 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
625 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, tree
->sreg1
+ 1);
627 case OP_LCONV_TO_OVF_U1
:
628 case OP_LCONV_TO_OVF_U1_UN
:
629 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
630 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
632 /* probe value to be within 0 to 255 */
633 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 255);
634 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
635 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, tree
->sreg1
+ 1, 0xff);
637 case OP_LCONV_TO_OVF_I2
: {
638 MonoBasicBlock
*is_negative
, *end_label
;
640 NEW_BBLOCK (cfg
, is_negative
);
641 NEW_BBLOCK (cfg
, end_label
);
643 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
644 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
645 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, -1);
646 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
648 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
649 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
652 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 32767);
653 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
654 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
657 MONO_START_BB (cfg
, is_negative
);
658 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, -32768);
659 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
660 MONO_START_BB (cfg
, end_label
);
662 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, tree
->sreg1
+ 1);
665 case OP_LCONV_TO_OVF_I2_UN
:
666 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
667 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
669 /* Probe value to be within -32768 and 32767 */
670 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 32767);
671 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
672 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, -32768);
673 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
674 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, tree
->sreg1
+ 1);
676 case OP_LCONV_TO_OVF_U2
:
677 case OP_LCONV_TO_OVF_U2_UN
:
678 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
679 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
681 /* Probe value to be within 0 and 65535 */
682 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
+ 1, 0xffff);
683 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
684 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, tree
->sreg1
+ 1, 0xffff);
686 case OP_LCONV_TO_OVF_I4
:
687 case OP_LCONV_TO_OVF_I
:
688 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_OVF_I4_2
, tree
->dreg
, tree
->sreg1
+ 1, tree
->sreg1
+ 2);
690 case OP_LCONV_TO_OVF_U4
:
691 case OP_LCONV_TO_OVF_U
:
692 case OP_LCONV_TO_OVF_U4_UN
:
693 case OP_LCONV_TO_OVF_U_UN
:
694 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
695 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
696 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, tree
->sreg1
+ 1);
698 case OP_LCONV_TO_OVF_I_UN
:
699 case OP_LCONV_TO_OVF_I4_UN
:
700 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
701 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
702 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 1, 0);
703 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
704 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, tree
->sreg1
+ 1);
706 case OP_LCONV_TO_OVF_U8
:
707 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
708 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
710 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
+ 1);
711 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 2, tree
->sreg1
+ 2);
713 case OP_LCONV_TO_OVF_I8_UN
:
714 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, tree
->sreg1
+ 2, 0);
715 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
717 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
+ 1);
718 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 2, tree
->sreg1
+ 2);
722 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
723 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
726 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
727 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
731 /* ADC sets the condition code */
732 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
733 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
734 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
737 /* ADC sets the condition code */
738 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
739 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
740 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
743 /* SBB sets the condition code */
744 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
745 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
746 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
749 /* SBB sets the condition code */
750 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
751 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
752 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
755 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
756 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
759 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
760 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
763 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
764 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
767 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tree
->dreg
+ 1, tree
->sreg1
+ 1);
768 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, tree
->dreg
+ 2, tree
->sreg1
+ 2);
771 /* Handled in mono_arch_decompose_long_opts () */
772 g_assert_not_reached ();
776 /* FIXME: Add OP_BIGMUL optimization */
780 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADDCC_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
781 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADC_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
784 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SUBCC_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
785 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SBB_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
788 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
789 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
792 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
793 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
796 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, tree
->dreg
+ 1, tree
->sreg1
+ 1, tree
->inst_ls_word
);
797 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, tree
->dreg
+ 2, tree
->sreg1
+ 2, tree
->inst_ms_word
);
800 if (tree
->inst_c1
== 32) {
802 /* The original code had this comment: */
803 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
804 * later apply the speedup to the left shift as well
807 /* FIXME: Move this to the strength reduction pass */
808 /* just move the upper half to the lower and zero the high word */
809 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 1, tree
->sreg1
+ 2);
810 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 2, 0);
814 if (tree
->inst_c1
== 32) {
815 /* just move the lower half to the upper and zero the lower word */
816 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
+ 2, tree
->sreg1
+ 1);
817 MONO_EMIT_NEW_ICONST (cfg
, tree
->dreg
+ 1, 0);
822 MonoInst
*next
= tree
->next
;
826 switch (next
->opcode
) {
831 /* Branchless version based on gcc code */
832 d1
= alloc_ireg (cfg
);
833 d2
= alloc_ireg (cfg
);
834 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
835 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
836 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
837 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
838 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
839 next
->opcode
= OP_NOP
;
850 /* Convert into three comparisons + branches */
851 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
852 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
853 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
854 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
855 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
856 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
857 next
->opcode
= OP_NOP
;
862 /* Branchless version based on gcc code */
863 d1
= alloc_ireg (cfg
);
864 d2
= alloc_ireg (cfg
);
865 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
866 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
867 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
869 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
870 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
871 next
->opcode
= OP_NOP
;
878 MonoBasicBlock
*set_to_0
, *set_to_1
;
880 NEW_BBLOCK (cfg
, set_to_0
);
881 NEW_BBLOCK (cfg
, set_to_1
);
883 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
884 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
885 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
886 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 2, tree
->sreg2
+ 2);
887 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
888 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, tree
->sreg1
+ 1, tree
->sreg2
+ 1);
889 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
890 MONO_START_BB (cfg
, set_to_1
);
891 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
892 MONO_START_BB (cfg
, set_to_0
);
893 next
->opcode
= OP_NOP
;
897 g_assert_not_reached ();
902 /* Not yet used, since lcompare is decomposed before local cprop */
903 case OP_LCOMPARE_IMM
: {
904 MonoInst
*next
= tree
->next
;
905 guint32 low_imm
= tree
->inst_ls_word
;
906 guint32 high_imm
= tree
->inst_ms_word
;
907 int low_reg
= tree
->sreg1
+ 1;
908 int high_reg
= tree
->sreg1
+ 2;
912 switch (next
->opcode
) {
917 /* Branchless version based on gcc code */
918 d1
= alloc_ireg (cfg
);
919 d2
= alloc_ireg (cfg
);
920 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
921 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
922 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
923 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
924 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
925 next
->opcode
= OP_NOP
;
937 /* Convert into three comparisons + branches */
938 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
939 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
940 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
941 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
942 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
943 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
944 next
->opcode
= OP_NOP
;
949 /* Branchless version based on gcc code */
950 d1
= alloc_ireg (cfg
);
951 d2
= alloc_ireg (cfg
);
952 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
953 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
954 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
956 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
957 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
958 next
->opcode
= OP_NOP
;
965 MonoBasicBlock
*set_to_0
, *set_to_1
;
967 NEW_BBLOCK (cfg
, set_to_0
);
968 NEW_BBLOCK (cfg
, set_to_1
);
970 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
971 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
972 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
973 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
974 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
975 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
976 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
977 MONO_START_BB (cfg
, set_to_1
);
978 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
979 MONO_START_BB (cfg
, set_to_0
);
980 next
->opcode
= OP_NOP
;
984 g_assert_not_reached ();
993 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
996 /* Replace the original instruction with the new code sequence */
998 /* Ignore the new value of prev */
1000 mono_replace_ins (cfg
, bb
, tree
, &new_prev
, first_bb
, cfg
->cbb
);
1002 /* Process the newly added ops again since they can be long ops too */
1008 first_bb
->code
= first_bb
->last_ins
= NULL
;
1009 first_bb
->in_count
= first_bb
->out_count
= 0;
1010 cfg
->cbb
= first_bb
;
1021 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1022 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1027 * mono_decompose_vtype_opts:
1029 * Decompose valuetype opcodes.
1032 mono_decompose_vtype_opts (MonoCompile
*cfg
)
1034 MonoBasicBlock
*bb
, *first_bb
;
1037 * Using OP_V opcodes and decomposing them later have two main benefits:
1038 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1040 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1041 * enabling optimizations to work on vtypes too.
1042 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1043 * can be executed anytime. It should be executed as late as possible so vtype
1044 * opcodes can be optimized by the other passes.
1045 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1046 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1048 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1049 * when OP_VMOVE opcodes are decomposed.
1053 * Vregs have no associated type information, so we store the type of the vregs
1058 * Create a dummy bblock and emit code into it so we can use the normal
1059 * code generation macros.
1061 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1062 first_bb
= cfg
->cbb
;
1064 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1066 MonoInst
*prev
= NULL
;
1067 MonoInst
*src_var
, *dest_var
, *src
, *dest
;
1071 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "BEFORE LOWER-VTYPE-OPTS ");
1073 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1079 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1080 switch (ins
->opcode
) {
1082 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1083 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1085 g_assert (ins
->klass
);
1088 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1091 dest_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1094 if (src_var
->backend
.is_pinvoke
)
1095 dest_var
->backend
.is_pinvoke
= 1;
1097 EMIT_NEW_VARLOADA ((cfg
), (src
), src_var
, src_var
->inst_vtype
);
1098 EMIT_NEW_VARLOADA ((cfg
), (dest
), dest_var
, dest_var
->inst_vtype
);
1100 mini_emit_stobj (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
);
1104 g_assert (ins
->klass
);
1106 EMIT_NEW_VARLOADA_VREG (cfg
, dest
, ins
->dreg
, &ins
->klass
->byval_arg
);
1107 mini_emit_initobj (cfg
, dest
, NULL
, ins
->klass
);
1109 if (cfg
->compute_gc_maps
) {
1113 * Tell the GC map code that the vtype is considered live after
1114 * the initialization.
1116 MONO_INST_NEW (cfg
, tmp
, OP_GC_LIVENESS_DEF
);
1117 tmp
->inst_c1
= ins
->dreg
;
1118 MONO_ADD_INS (cfg
->cbb
, tmp
);
1121 case OP_STOREV_MEMBASE
: {
1122 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1125 g_assert (ins
->klass
);
1126 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->sreg1
);
1129 EMIT_NEW_VARLOADA_VREG ((cfg
), (src
), ins
->sreg1
, &ins
->klass
->byval_arg
);
1131 dreg
= alloc_preg (cfg
);
1132 EMIT_NEW_BIALU_IMM (cfg
, dest
, OP_ADD_IMM
, dreg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1133 mini_emit_stobj (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
);
1136 case OP_LOADV_MEMBASE
: {
1137 g_assert (ins
->klass
);
1139 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1142 dest_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1144 dreg
= alloc_preg (cfg
);
1145 EMIT_NEW_BIALU_IMM (cfg
, src
, OP_ADD_IMM
, dreg
, ins
->inst_basereg
, ins
->inst_offset
);
1146 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1147 mini_emit_stobj (cfg
, dest
, src
, dest_var
->klass
, dest_var
->backend
.is_pinvoke
);
1150 case OP_OUTARG_VT
: {
1151 g_assert (ins
->klass
);
1153 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1155 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->sreg1
);
1156 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1158 mono_arch_emit_outarg_vt (cfg
, ins
, src
);
1160 /* This might be decomposed into other vtype opcodes */
1164 case OP_OUTARG_VTRETADDR
: {
1165 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p1
;
1167 src_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1169 src_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1170 // FIXME: src_var->backend.is_pinvoke ?
1172 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1173 src
->dreg
= ins
->dreg
;
1178 case OP_VCALL_MEMBASE
: {
1179 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1182 if (call
->vret_in_reg
) {
1183 MonoCallInst
*call2
;
1185 /* Replace the vcall with an integer call */
1186 MONO_INST_NEW_CALL (cfg
, call2
, OP_NOP
);
1187 memcpy (call2
, call
, sizeof (MonoCallInst
));
1188 switch (ins
->opcode
) {
1190 call2
->inst
.opcode
= OP_CALL
;
1193 call2
->inst
.opcode
= OP_CALL_REG
;
1195 case OP_VCALL_MEMBASE
:
1196 call2
->inst
.opcode
= OP_CALL_MEMBASE
;
1199 call2
->inst
.dreg
= alloc_preg (cfg
);
1200 MONO_ADD_INS (cfg
->cbb
, ((MonoInst
*)call2
));
1202 /* Compute the vtype location */
1203 dest_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1205 dest_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1206 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1208 /* Save the result */
1209 if (dest_var
->backend
.is_pinvoke
)
1210 size
= mono_class_native_size (mono_class_from_mono_type (dest_var
->inst_vtype
), NULL
);
1212 size
= mono_type_size (dest_var
->inst_vtype
, NULL
);
1215 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI1_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1218 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI2_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1221 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1224 #if SIZEOF_REGISTER == 4
1226 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1227 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1229 switch (call2
->inst
.opcode
) {
1231 call2
->inst
.opcode
= OP_LCALL
;
1234 call2
->inst
.opcode
= OP_LCALL_REG
;
1236 case OP_CALL_MEMBASE
:
1237 call2
->inst
.opcode
= OP_LCALL_MEMBASE
;
1240 call2
->inst
.dreg
= alloc_lreg (cfg
);
1241 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_MS_WORD_OFFSET
, call2
->inst
.dreg
+ 2);
1242 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_LS_WORD_OFFSET
, call2
->inst
.dreg
+ 1);
1244 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1248 /* This assumes the vtype is sizeof (gpointer) long */
1249 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1253 switch (ins
->opcode
) {
1255 ins
->opcode
= OP_VCALL2
;
1258 ins
->opcode
= OP_VCALL2_REG
;
1260 case OP_VCALL_MEMBASE
:
1261 ins
->opcode
= OP_VCALL2_MEMBASE
;
1272 g_assert (cfg
->cbb
== first_bb
);
1274 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1275 /* Replace the original instruction with the new code sequence */
1277 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1278 first_bb
->code
= first_bb
->last_ins
= NULL
;
1279 first_bb
->in_count
= first_bb
->out_count
= 0;
1280 cfg
->cbb
= first_bb
;
1287 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "AFTER LOWER-VTYPE-OPTS ");
1291 inline static MonoInst
*
1292 mono_get_domainvar (MonoCompile
*cfg
)
1294 if (!cfg
->domainvar
)
1295 cfg
->domainvar
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_LOCAL
);
1296 return cfg
->domainvar
;
1300 * mono_decompose_array_access_opts:
1302 * Decompose array access opcodes.
1305 mono_decompose_array_access_opts (MonoCompile
*cfg
)
1307 MonoBasicBlock
*bb
, *first_bb
;
1310 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1311 * can be executed anytime. It should be run before decompose_long
1315 * Create a dummy bblock and emit code into it so we can use the normal
1316 * code generation macros.
1318 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1319 first_bb
= cfg
->cbb
;
1321 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1323 MonoInst
*prev
= NULL
;
1325 MonoInst
*iargs
[3];
1328 if (!bb
->has_array_access
)
1331 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1333 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1339 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1340 switch (ins
->opcode
) {
1342 NEW_LOAD_MEMBASE_FLAGS (cfg
, dest
, OP_LOADI4_MEMBASE
, ins
->dreg
, ins
->sreg1
,
1343 G_STRUCT_OFFSET (MonoArray
, max_length
), ins
->flags
| MONO_INST_CONSTANT_LOAD
);
1344 MONO_ADD_INS (cfg
->cbb
, dest
);
1346 case OP_BOUNDS_CHECK
:
1347 MONO_EMIT_NULL_CHECK (cfg
, ins
->sreg1
);
1348 if (COMPILE_LLVM (cfg
))
1349 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, ins
->sreg2
, ins
->flags
& MONO_INST_FAULT
);
1351 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, ins
->sreg2
);
1354 if (cfg
->opt
& MONO_OPT_SHARED
) {
1355 EMIT_NEW_DOMAINCONST (cfg
, iargs
[0]);
1356 EMIT_NEW_CLASSCONST (cfg
, iargs
[1], ins
->inst_newa_class
);
1357 MONO_INST_NEW (cfg
, iargs
[2], OP_MOVE
);
1358 iargs
[2]->dreg
= ins
->sreg1
;
1360 dest
= mono_emit_jit_icall (cfg
, mono_array_new
, iargs
);
1361 dest
->dreg
= ins
->dreg
;
1363 MonoVTable
*vtable
= mono_class_vtable (cfg
->domain
, mono_array_class_get (ins
->inst_newa_class
, 1));
1364 MonoMethod
*managed_alloc
= mono_gc_get_managed_array_allocator (vtable
, 1);
1366 g_assert (vtable
); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1367 NEW_VTABLECONST (cfg
, iargs
[0], vtable
);
1368 MONO_ADD_INS (cfg
->cbb
, iargs
[0]);
1369 MONO_INST_NEW (cfg
, iargs
[1], OP_MOVE
);
1370 iargs
[1]->dreg
= ins
->sreg1
;
1373 dest
= mono_emit_method_call (cfg
, managed_alloc
, iargs
, NULL
);
1375 dest
= mono_emit_jit_icall (cfg
, mono_array_new_specific
, iargs
);
1376 dest
->dreg
= ins
->dreg
;
1380 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg
, OP_LOADI4_MEMBASE
, ins
->dreg
,
1381 ins
->sreg1
, G_STRUCT_OFFSET (MonoString
, length
), ins
->flags
| MONO_INST_CONSTANT_LOAD
);
1387 g_assert (cfg
->cbb
== first_bb
);
1389 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1390 /* Replace the original instruction with the new code sequence */
1392 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1393 first_bb
->code
= first_bb
->last_ins
= NULL
;
1394 first_bb
->in_count
= first_bb
->out_count
= 0;
1395 cfg
->cbb
= first_bb
;
1402 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1412 #ifdef MONO_ARCH_SOFT_FLOAT
1415 * mono_decompose_soft_float:
1417 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1418 * similar to long support on 32 bit platforms. 32 bit float values require special
1419 * handling when used as locals, arguments, and in calls.
1420 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1423 mono_decompose_soft_float (MonoCompile
*cfg
)
1425 MonoBasicBlock
*bb
, *first_bb
;
1428 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1432 * Create a dummy bblock and emit code into it so we can use the normal
1433 * code generation macros.
1435 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1436 first_bb
= cfg
->cbb
;
1438 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1440 MonoInst
*prev
= NULL
;
1443 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE HANDLE-SOFT-FLOAT ");
1445 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1451 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1452 const char *spec
= INS_INFO (ins
->opcode
);
1454 /* Most fp operations are handled automatically by opcode emulation */
1456 switch (ins
->opcode
) {
1459 d
.vald
= *(double*)ins
->inst_p0
;
1460 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1465 /* We load the r8 value */
1466 d
.vald
= *(float*)ins
->inst_p0
;
1467 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1471 ins
->opcode
= OP_LMOVE
;
1474 ins
->opcode
= OP_MOVE
;
1475 ins
->sreg1
= ins
->sreg1
+ 1;
1478 ins
->opcode
= OP_MOVE
;
1479 ins
->sreg1
= ins
->sreg1
+ 2;
1482 int reg
= ins
->sreg1
;
1484 ins
->opcode
= OP_SETLRET
;
1486 ins
->sreg1
= reg
+ 1;
1487 ins
->sreg2
= reg
+ 2;
1490 case OP_LOADR8_MEMBASE
:
1491 ins
->opcode
= OP_LOADI8_MEMBASE
;
1493 case OP_STORER8_MEMBASE_REG
:
1494 ins
->opcode
= OP_STOREI8_MEMBASE_REG
;
1496 case OP_STORER4_MEMBASE_REG
: {
1497 MonoInst
*iargs
[2];
1500 /* Arg 1 is the double value */
1501 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1502 iargs
[0]->dreg
= ins
->sreg1
;
1504 /* Arg 2 is the address to store to */
1505 addr_reg
= mono_alloc_preg (cfg
);
1506 EMIT_NEW_BIALU_IMM (cfg
, iargs
[1], OP_PADD_IMM
, addr_reg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1507 mono_emit_jit_icall (cfg
, mono_fstore_r4
, iargs
);
1511 case OP_LOADR4_MEMBASE
: {
1512 MonoInst
*iargs
[1];
1516 addr_reg
= mono_alloc_preg (cfg
);
1517 EMIT_NEW_BIALU_IMM (cfg
, iargs
[0], OP_PADD_IMM
, addr_reg
, ins
->inst_basereg
, ins
->inst_offset
);
1518 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1519 conv
->dreg
= ins
->dreg
;
1524 case OP_FCALL_MEMBASE
: {
1525 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1526 if (call
->signature
->ret
->type
== MONO_TYPE_R4
) {
1527 MonoCallInst
*call2
;
1528 MonoInst
*iargs
[1];
1532 /* Convert the call into a call returning an int */
1533 MONO_INST_NEW_CALL (cfg
, call2
, OP_CALL
);
1534 memcpy (call2
, call
, sizeof (MonoCallInst
));
1535 switch (ins
->opcode
) {
1537 call2
->inst
.opcode
= OP_CALL
;
1540 call2
->inst
.opcode
= OP_CALL_REG
;
1542 case OP_FCALL_MEMBASE
:
1543 call2
->inst
.opcode
= OP_CALL_MEMBASE
;
1546 g_assert_not_reached ();
1548 call2
->inst
.dreg
= mono_alloc_ireg (cfg
);
1549 MONO_ADD_INS (cfg
->cbb
, (MonoInst
*)call2
);
1551 /* Remap OUTARG_VT instructions referencing this call */
1552 for (l
= call
->outarg_vts
; l
; l
= l
->next
)
1553 ((MonoInst
*)(l
->data
))->inst_p0
= call2
;
1555 /* FIXME: Optimize this */
1557 /* Emit an r4->r8 conversion */
1558 EMIT_NEW_VARLOADA_VREG (cfg
, iargs
[0], call2
->inst
.dreg
, &mono_defaults
.int32_class
->byval_arg
);
1559 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1560 conv
->dreg
= ins
->dreg
;
1562 /* The call sequence might include fp ins */
1565 switch (ins
->opcode
) {
1567 ins
->opcode
= OP_LCALL
;
1570 ins
->opcode
= OP_LCALL_REG
;
1572 case OP_FCALL_MEMBASE
:
1573 ins
->opcode
= OP_LCALL_MEMBASE
;
1576 g_assert_not_reached ();
1582 MonoJitICallInfo
*info
;
1583 MonoInst
*iargs
[2];
1584 MonoInst
*call
, *cmp
, *br
;
1586 /* Convert fcompare+fbcc to icall+icompare+beq */
1588 info
= mono_find_jit_opcode_emulation (ins
->next
->opcode
);
1591 /* Create dummy MonoInst's for the arguments */
1592 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1593 iargs
[0]->dreg
= ins
->sreg1
;
1594 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1595 iargs
[1]->dreg
= ins
->sreg2
;
1597 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, iargs
);
1599 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1600 cmp
->sreg1
= call
->dreg
;
1602 MONO_ADD_INS (cfg
->cbb
, cmp
);
1604 MONO_INST_NEW (cfg
, br
, OP_IBNE_UN
);
1605 br
->inst_many_bb
= mono_mempool_alloc (cfg
->mempool
, sizeof (gpointer
) * 2);
1606 br
->inst_true_bb
= ins
->next
->inst_true_bb
;
1607 br
->inst_false_bb
= ins
->next
->inst_false_bb
;
1608 MONO_ADD_INS (cfg
->cbb
, br
);
1610 /* The call sequence might include fp ins */
1613 /* Skip fbcc or fccc */
1614 NULLIFY_INS (ins
->next
);
1622 MonoJitICallInfo
*info
;
1623 MonoInst
*iargs
[2];
1626 /* Convert fccc to icall+icompare+iceq */
1628 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
1631 /* Create dummy MonoInst's for the arguments */
1632 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1633 iargs
[0]->dreg
= ins
->sreg1
;
1634 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1635 iargs
[1]->dreg
= ins
->sreg2
;
1637 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, iargs
);
1639 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, call
->dreg
, 1);
1640 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, ins
->dreg
, -1);
1642 /* The call sequence might include fp ins */
1647 MonoInst
*iargs
[2];
1648 MonoInst
*call
, *cmp
;
1650 /* Convert to icall+icompare+cond_exc+move */
1652 /* Create dummy MonoInst's for the arguments */
1653 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1654 iargs
[0]->dreg
= ins
->sreg1
;
1656 call
= mono_emit_jit_icall (cfg
, mono_isfinite
, iargs
);
1658 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1659 cmp
->sreg1
= call
->dreg
;
1661 MONO_ADD_INS (cfg
->cbb
, cmp
);
1663 MONO_EMIT_NEW_COND_EXC (cfg
, INE_UN
, "ArithmeticException");
1665 /* Do the assignment if the value is finite */
1666 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, ins
->dreg
, ins
->sreg1
);
1672 if (spec
[MONO_INST_SRC1
] == 'f' || spec
[MONO_INST_SRC2
] == 'f' || spec
[MONO_INST_DEST
] == 'f') {
1673 mono_print_ins (ins
);
1674 g_assert_not_reached ();
1679 g_assert (cfg
->cbb
== first_bb
);
1681 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1682 /* Replace the original instruction with the new code sequence */
1684 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1685 first_bb
->code
= first_bb
->last_ins
= NULL
;
1686 first_bb
->in_count
= first_bb
->out_count
= 0;
1687 cfg
->cbb
= first_bb
;
1694 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER HANDLE-SOFT-FLOAT ");
1697 mono_decompose_long_opts (cfg
);
1702 #endif /* DISABLE_JIT */