2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include "jit-icalls.h"
15 #include <mono/metadata/gc-internals.h>
16 #include <mono/metadata/abi-details.h>
20 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
21 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
22 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
23 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
26 * Decompose complex long opcodes on 64 bit machines.
27 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
30 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
32 MonoInst *repl = NULL;
36 switch (ins->opcode) {
38 ins->opcode = OP_SEXT_I4;
42 if (SIZEOF_VOID_P == 4)
43 ins->opcode = OP_LMOVE;
45 ins->opcode = OP_MOVE;
48 if (SIZEOF_VOID_P == 4)
50 ins->opcode = OP_SEXT_I4;
52 ins->opcode = OP_MOVE;
55 if (SIZEOF_VOID_P == 4) {
57 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
60 ins->opcode = OP_MOVE;
64 ins->opcode = OP_SEXT_I4;
67 ins->opcode = OP_ZEXT_I4;
70 /* Clean out the upper word */
71 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
77 if (COMPILE_LLVM (cfg))
79 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
83 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
84 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
88 case OP_LADD_OVF_UN: {
91 if (COMPILE_LLVM (cfg))
93 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
97 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
98 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
102 #ifndef __mono_ppc64__
106 if (COMPILE_LLVM (cfg))
108 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
112 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
113 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
117 case OP_LSUB_OVF_UN: {
120 if (COMPILE_LLVM (cfg))
122 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
126 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
127 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
133 case OP_ICONV_TO_OVF_I8:
134 case OP_ICONV_TO_OVF_I:
135 ins->opcode = OP_SEXT_I4;
137 case OP_ICONV_TO_OVF_U8:
138 case OP_ICONV_TO_OVF_U:
139 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
140 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
141 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
144 case OP_ICONV_TO_OVF_I8_UN:
145 case OP_ICONV_TO_OVF_U8_UN:
146 case OP_ICONV_TO_OVF_I_UN:
147 case OP_ICONV_TO_OVF_U_UN:
148 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
149 /* Clean out the upper word */
150 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
153 case OP_LCONV_TO_OVF_I1:
154 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
155 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
156 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
157 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
158 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
161 case OP_LCONV_TO_OVF_I1_UN:
162 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
163 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
164 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
167 case OP_LCONV_TO_OVF_U1:
168 /* probe value to be within 0 to 255 */
169 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
170 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
171 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
174 case OP_LCONV_TO_OVF_U1_UN:
175 /* probe value to be within 0 to 255 */
176 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
177 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
178 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
181 case OP_LCONV_TO_OVF_I2:
182 /* Probe value to be within -32768 and 32767 */
183 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
184 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
185 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
186 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
187 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
190 case OP_LCONV_TO_OVF_I2_UN:
191 /* Probe value to be within 0 and 32767 */
192 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
193 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
194 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
197 case OP_LCONV_TO_OVF_U2:
198 /* Probe value to be within 0 and 65535 */
199 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
200 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
201 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
204 case OP_LCONV_TO_OVF_U2_UN:
205 /* Probe value to be within 0 and 65535 */
206 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
207 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
211 case OP_LCONV_TO_OVF_I4:
212 #if SIZEOF_VOID_P == 4
213 case OP_LCONV_TO_OVF_I:
215 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
216 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
217 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
218 #if SIZEOF_REGISTER == 8
219 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
221 g_assert (COMPILE_LLVM (cfg));
222 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
224 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
225 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
228 case OP_LCONV_TO_OVF_I4_UN:
229 #if SIZEOF_VOID_P == 4
230 case OP_LCONV_TO_OVF_I_UN:
232 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
233 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
234 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
237 case OP_LCONV_TO_OVF_U4:
238 #if SIZEOF_VOID_P == 4
239 case OP_LCONV_TO_OVF_U:
241 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
242 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
243 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
244 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
245 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
248 case OP_LCONV_TO_OVF_U4_UN:
249 #if SIZEOF_VOID_P == 4
250 case OP_LCONV_TO_OVF_U_UN:
252 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
253 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
254 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
257 #if SIZEOF_VOID_P == 8
258 case OP_LCONV_TO_OVF_I:
259 case OP_LCONV_TO_OVF_U_UN:
261 case OP_LCONV_TO_OVF_U8_UN:
262 case OP_LCONV_TO_OVF_I8:
263 ins->opcode = OP_MOVE;
265 #if SIZEOF_VOID_P == 8
266 case OP_LCONV_TO_OVF_I_UN:
268 case OP_LCONV_TO_OVF_I8_UN:
269 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
270 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
271 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
274 case OP_LCONV_TO_OVF_U8:
275 #if SIZEOF_VOID_P == 8
276 case OP_LCONV_TO_OVF_U:
278 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
279 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
280 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
292 * mono_decompose_opcode:
294 * Decompose complex opcodes into ones closer to opcodes supported by
295 * the given architecture.
296 * Returns a MonoInst which represents the result of the decomposition, and can
297 * be pushed on the IL stack. This is needed because the original instruction is
299 * Sets the cfg exception if an opcode is not supported.
302 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
304 MonoInst *repl = NULL;
305 int type = ins->type;
306 int dreg = ins->dreg;
307 gboolean emulate = FALSE;
309 /* FIXME: Instead of = NOP, don't emit the original ins at all */
310 mono_arch_decompose_opts (cfg, ins);
313 * The code below assumes that we are called immediately after emitting
314 * ins. This means we can emit code using the normal code generation
317 switch (ins->opcode) {
318 /* this doesn't make sense on ppc and other architectures */
319 #if !defined(MONO_ARCH_NO_IOV_CHECK)
321 if (COMPILE_LLVM (cfg))
323 ins->opcode = OP_IADDCC;
324 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
327 if (COMPILE_LLVM (cfg))
329 ins->opcode = OP_IADDCC;
330 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
333 if (COMPILE_LLVM (cfg))
335 ins->opcode = OP_ISUBCC;
336 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
339 if (COMPILE_LLVM (cfg))
341 ins->opcode = OP_ISUBCC;
342 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
345 case OP_ICONV_TO_OVF_I1:
346 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
347 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
348 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
349 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
350 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
353 case OP_ICONV_TO_OVF_I1_UN:
354 /* probe values between 0 to 127 */
355 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
356 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
357 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
360 case OP_ICONV_TO_OVF_U1:
361 case OP_ICONV_TO_OVF_U1_UN:
362 /* probe value to be within 0 to 255 */
363 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
364 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
365 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
368 case OP_ICONV_TO_OVF_I2:
369 /* Probe value to be within -32768 and 32767 */
370 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
371 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
372 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
373 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
374 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
377 case OP_ICONV_TO_OVF_I2_UN:
378 /* Convert uint value into short, value within 0 and 32767 */
379 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
380 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
381 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
384 case OP_ICONV_TO_OVF_U2:
385 case OP_ICONV_TO_OVF_U2_UN:
386 /* Probe value to be within 0 and 65535 */
387 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
388 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
389 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
392 case OP_ICONV_TO_OVF_U4:
393 case OP_ICONV_TO_OVF_I4_UN:
394 #if SIZEOF_VOID_P == 4
395 case OP_ICONV_TO_OVF_U:
396 case OP_ICONV_TO_OVF_I_UN:
398 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
399 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
400 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
405 case OP_ICONV_TO_OVF_I4:
406 case OP_ICONV_TO_OVF_U4_UN:
407 #if SIZEOF_VOID_P == 4
408 case OP_ICONV_TO_OVF_I:
409 case OP_ICONV_TO_OVF_U_UN:
411 ins->opcode = OP_MOVE;
414 #if SIZEOF_VOID_P == 8
415 ins->opcode = OP_SEXT_I4;
417 ins->opcode = OP_MOVE;
421 #if SIZEOF_VOID_P == 8
422 ins->opcode = OP_ZEXT_I4;
424 ins->opcode = OP_MOVE;
429 ins->opcode = OP_FMOVE;
432 case OP_FCONV_TO_OVF_I1_UN:
433 case OP_FCONV_TO_OVF_I2_UN:
434 case OP_FCONV_TO_OVF_I4_UN:
435 case OP_FCONV_TO_OVF_I8_UN:
436 case OP_FCONV_TO_OVF_U1_UN:
437 case OP_FCONV_TO_OVF_U2_UN:
438 case OP_FCONV_TO_OVF_U4_UN:
439 case OP_FCONV_TO_OVF_U8_UN:
440 case OP_FCONV_TO_OVF_I_UN:
441 case OP_FCONV_TO_OVF_U_UN:
442 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
449 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
452 if (cfg->backend->need_div_check) {
453 int reg1 = alloc_ireg (cfg);
454 int reg2 = alloc_ireg (cfg);
456 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
457 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
458 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
459 /* b == -1 && a == 0x80000000 */
460 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
461 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
463 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
464 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
465 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
466 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
469 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
480 #if SIZEOF_REGISTER == 8
481 if (decompose_long_opcode (cfg, ins, &repl))
484 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
488 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
489 cfg->has_emulated_ops = TRUE;
492 if (ins->opcode == OP_NOP) {
497 /* Use the last emitted instruction */
498 ins = cfg->cbb->last_ins;
501 g_assert (ins->dreg == dreg);
509 #if SIZEOF_REGISTER == 4
510 static int lbr_decomp [][2] = {
512 {OP_IBGT, OP_IBGE_UN}, /* BGE */
513 {OP_IBGT, OP_IBGT_UN}, /* BGT */
514 {OP_IBLT, OP_IBLE_UN}, /* BLE */
515 {OP_IBLT, OP_IBLT_UN}, /* BLT */
517 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
518 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
519 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
520 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
523 static int lcset_decomp [][2] = {
525 {OP_IBLT, OP_IBLE_UN}, /* CGT */
526 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
527 {OP_IBGT, OP_IBGE_UN}, /* CLT */
528 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
533 * mono_decompose_long_opts:
535 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
538 mono_decompose_long_opts (MonoCompile *cfg)
540 #if SIZEOF_REGISTER == 4
541 MonoBasicBlock *bb, *first_bb;
544 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
545 * needs to be able to handle long vregs.
549 * Create a dummy bblock and emit code into it so we can use the normal
550 * code generation macros.
552 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
555 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
556 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
557 MonoInst *prev = NULL;
560 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
563 cfg->cbb->code = cfg->cbb->last_ins = NULL;
566 mono_arch_decompose_long_opts (cfg, tree);
568 switch (tree->opcode) {
570 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
571 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
573 case OP_DUMMY_I8CONST:
574 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
575 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
580 case OP_LCONV_TO_OVF_U8_UN:
581 case OP_LCONV_TO_OVF_I8:
582 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
583 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
585 case OP_STOREI8_MEMBASE_REG:
586 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (tree->sreg1));
587 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (tree->sreg1));
589 case OP_LOADI8_MEMBASE:
590 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_MS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
591 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_LS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
594 case OP_ICONV_TO_I8: {
595 guint32 tmpreg = alloc_ireg (cfg);
599 * tmp = low > -1 ? 1: 0;
600 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
602 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
603 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
604 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
605 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
609 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
610 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
612 case OP_ICONV_TO_OVF_I8:
613 /* a signed 32 bit num always fits in a signed 64 bit one */
614 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
615 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
617 case OP_ICONV_TO_OVF_U8:
618 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
619 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
620 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
621 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
623 case OP_ICONV_TO_OVF_I8_UN:
624 case OP_ICONV_TO_OVF_U8_UN:
625 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
626 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
627 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
630 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
633 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
636 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
639 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
645 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
647 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
649 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
652 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
654 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
657 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
658 case OP_LCONV_TO_R_UN:
659 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
662 case OP_LCONV_TO_OVF_I1: {
663 MonoBasicBlock *is_negative, *end_label;
665 NEW_BBLOCK (cfg, is_negative);
666 NEW_BBLOCK (cfg, end_label);
668 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
669 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
670 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
671 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
673 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
674 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
677 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
678 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
679 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
682 MONO_START_BB (cfg, is_negative);
683 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
684 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
686 MONO_START_BB (cfg, end_label);
688 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
691 case OP_LCONV_TO_OVF_I1_UN:
692 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
693 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
695 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
696 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
697 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
698 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
699 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
701 case OP_LCONV_TO_OVF_U1:
702 case OP_LCONV_TO_OVF_U1_UN:
703 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
704 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
706 /* probe value to be within 0 to 255 */
707 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
708 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
709 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
711 case OP_LCONV_TO_OVF_I2: {
712 MonoBasicBlock *is_negative, *end_label;
714 NEW_BBLOCK (cfg, is_negative);
715 NEW_BBLOCK (cfg, end_label);
717 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
718 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
719 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
720 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
722 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
723 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
726 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
727 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
728 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
731 MONO_START_BB (cfg, is_negative);
732 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
733 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
734 MONO_START_BB (cfg, end_label);
736 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
739 case OP_LCONV_TO_OVF_I2_UN:
740 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
741 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
743 /* Probe value to be within -32768 and 32767 */
744 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
745 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
746 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
747 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
748 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
750 case OP_LCONV_TO_OVF_U2:
751 case OP_LCONV_TO_OVF_U2_UN:
752 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
753 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
755 /* Probe value to be within 0 and 65535 */
756 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
757 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
760 case OP_LCONV_TO_OVF_I4:
761 case OP_LCONV_TO_OVF_I:
762 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
764 case OP_LCONV_TO_OVF_U4:
765 case OP_LCONV_TO_OVF_U:
766 case OP_LCONV_TO_OVF_U4_UN:
767 case OP_LCONV_TO_OVF_U_UN:
768 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
769 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
770 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
772 case OP_LCONV_TO_OVF_I_UN:
773 case OP_LCONV_TO_OVF_I4_UN:
774 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
775 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
776 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
777 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
778 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
780 case OP_LCONV_TO_OVF_U8:
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
782 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
784 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
785 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
787 case OP_LCONV_TO_OVF_I8_UN:
788 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
789 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
791 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
792 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
796 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
797 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
800 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
801 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
805 /* ADC sets the condition code */
806 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
807 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
808 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
811 /* ADC sets the condition code */
812 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
813 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
814 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
817 /* SBB sets the condition code */
818 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
819 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
820 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
823 /* SBB sets the condition code */
824 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
825 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
826 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
829 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
830 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
833 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
834 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
837 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
838 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
841 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
842 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
845 /* Handled in mono_arch_decompose_long_opts () */
846 g_assert_not_reached ();
850 /* FIXME: Add OP_BIGMUL optimization */
854 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
855 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
858 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
859 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
862 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
863 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
866 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
867 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
870 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
871 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
874 if (tree->inst_c1 == 32) {
876 /* The original code had this comment: */
877 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
878 * later apply the speedup to the left shift as well
881 /* FIXME: Move this to the strength reduction pass */
882 /* just move the upper half to the lower and zero the high word */
883 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
884 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
888 if (tree->inst_c1 == 32) {
889 /* just move the lower half to the upper and zero the lower word */
890 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
891 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
896 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
900 switch (next->opcode) {
905 /* Branchless version based on gcc code */
906 d1 = alloc_ireg (cfg);
907 d2 = alloc_ireg (cfg);
908 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
909 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
910 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
911 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
912 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
924 /* Convert into three comparisons + branches */
925 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
926 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
927 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
928 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
929 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
930 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
936 /* Branchless version based on gcc code */
937 d1 = alloc_ireg (cfg);
938 d2 = alloc_ireg (cfg);
939 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
940 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
941 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
943 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
944 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
952 MonoBasicBlock *set_to_0, *set_to_1;
954 NEW_BBLOCK (cfg, set_to_0);
955 NEW_BBLOCK (cfg, set_to_1);
957 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
958 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
959 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
960 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
961 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
962 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
963 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
964 MONO_START_BB (cfg, set_to_1);
965 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
966 MONO_START_BB (cfg, set_to_0);
971 g_assert_not_reached ();
976 /* Not yet used, since lcompare is decomposed before local cprop */
977 case OP_LCOMPARE_IMM: {
978 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
979 guint32 low_imm = tree->inst_ls_word;
980 guint32 high_imm = tree->inst_ms_word;
981 int low_reg = MONO_LVREG_LS (tree->sreg1);
982 int high_reg = MONO_LVREG_MS (tree->sreg1);
986 switch (next->opcode) {
991 /* Branchless version based on gcc code */
992 d1 = alloc_ireg (cfg);
993 d2 = alloc_ireg (cfg);
994 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
995 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
996 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
997 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
998 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1011 /* Convert into three comparisons + branches */
1012 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1013 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1014 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1015 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1016 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1017 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1023 /* Branchless version based on gcc code */
1024 d1 = alloc_ireg (cfg);
1025 d2 = alloc_ireg (cfg);
1026 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1027 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1028 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1030 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1031 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1039 MonoBasicBlock *set_to_0, *set_to_1;
1041 NEW_BBLOCK (cfg, set_to_0);
1042 NEW_BBLOCK (cfg, set_to_1);
1044 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1045 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1046 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1047 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1048 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1049 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1050 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1051 MONO_START_BB (cfg, set_to_1);
1052 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1053 MONO_START_BB (cfg, set_to_0);
1058 g_assert_not_reached ();
1067 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1070 /* Replace the original instruction with the new code sequence */
1072 /* Ignore the new value of prev */
1074 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1076 /* Process the newly added ops again since they can be long ops too */
1078 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1080 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1082 first_bb->code = first_bb->last_ins = NULL;
1083 first_bb->in_count = first_bb->out_count = 0;
1084 cfg->cbb = first_bb;
1088 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1095 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1096 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1101 * mono_decompose_vtype_opts:
1103 * Decompose valuetype opcodes.
1106 mono_decompose_vtype_opts (MonoCompile *cfg)
1108 MonoBasicBlock *bb, *first_bb;
1111 * Using OP_V opcodes and decomposing them later have two main benefits:
1112 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1114 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1115 * enabling optimizations to work on vtypes too.
1116 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1117 * can be executed anytime. It should be executed as late as possible so vtype
1118 * opcodes can be optimized by the other passes.
1119 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1120 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1122 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1123 * when OP_VMOVE opcodes are decomposed.
1127 * Vregs have no associated type information, so we store the type of the vregs
1132 * Create a dummy bblock and emit code into it so we can use the normal
1133 * code generation macros.
1135 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1136 first_bb = cfg->cbb;
1138 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1140 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1142 MonoInst *prev = NULL;
1143 MonoInst *src_var, *dest_var, *src, *dest;
1147 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1149 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1155 for (ins = bb->code; ins; ins = ins->next) {
1156 switch (ins->opcode) {
1158 g_assert (ins->klass);
1159 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1161 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1162 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1165 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1168 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1171 if (src_var->backend.is_pinvoke)
1172 dest_var->backend.is_pinvoke = 1;
1174 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1175 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1177 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1181 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1184 g_assert (ins->klass);
1186 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1187 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1189 if (cfg->compute_gc_maps) {
1193 * Tell the GC map code that the vtype is considered live after
1194 * the initialization.
1196 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1197 tmp->inst_c1 = ins->dreg;
1198 MONO_ADD_INS (cfg->cbb, tmp);
1201 case OP_DUMMY_VZERO:
1202 if (COMPILE_LLVM (cfg))
1207 case OP_STOREV_MEMBASE: {
1208 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1211 g_assert (ins->klass);
1212 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1215 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1217 dreg = alloc_preg (cfg);
1218 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1219 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1222 case OP_LOADV_MEMBASE: {
1223 g_assert (ins->klass);
1224 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1227 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1231 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1233 dreg = alloc_preg (cfg);
1234 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1235 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1236 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1239 case OP_OUTARG_VT: {
1240 if (COMPILE_LLVM (cfg))
1243 g_assert (ins->klass);
1245 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1247 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1248 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1250 mono_arch_emit_outarg_vt (cfg, ins, src);
1252 /* This might be decomposed into other vtype opcodes */
1256 case OP_OUTARG_VTRETADDR: {
1257 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1259 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1261 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1262 // FIXME: src_var->backend.is_pinvoke ?
1264 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1265 src->dreg = ins->dreg;
1270 case OP_VCALL_MEMBASE: {
1271 MonoCallInst *call = (MonoCallInst*)ins;
1274 if (COMPILE_LLVM (cfg))
1277 if (call->vret_in_reg) {
1278 MonoCallInst *call2;
1280 /* Replace the vcall with a scalar call */
1281 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1282 memcpy (call2, call, sizeof (MonoCallInst));
1283 switch (ins->opcode) {
1285 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1288 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1290 case OP_VCALL_MEMBASE:
1291 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1294 call2->inst.dreg = alloc_preg (cfg);
1295 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1297 /* Compute the vtype location */
1298 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1300 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1301 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1303 /* Save the result */
1304 if (dest_var->backend.is_pinvoke)
1305 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1307 size = mono_type_size (dest_var->inst_vtype, NULL);
1310 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1313 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1317 if (call->vret_in_reg_fp)
1318 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1320 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1326 if (call->vret_in_reg_fp) {
1327 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1330 #if SIZEOF_REGISTER == 4
1332 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1333 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1335 switch (call2->inst.opcode) {
1337 call2->inst.opcode = OP_LCALL;
1340 call2->inst.opcode = OP_LCALL_REG;
1342 case OP_CALL_MEMBASE:
1343 call2->inst.opcode = OP_LCALL_MEMBASE;
1346 call2->inst.dreg = alloc_lreg (cfg);
1347 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1348 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1350 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1354 /* This assumes the vtype is sizeof (gpointer) long */
1355 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1359 switch (ins->opcode) {
1361 ins->opcode = OP_VCALL2;
1364 ins->opcode = OP_VCALL2_REG;
1366 case OP_VCALL_MEMBASE:
1367 ins->opcode = OP_VCALL2_MEMBASE;
1378 g_assert (cfg->cbb == first_bb);
1380 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1381 /* Replace the original instruction with the new code sequence */
1383 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1384 first_bb->code = first_bb->last_ins = NULL;
1385 first_bb->in_count = first_bb->out_count = 0;
1386 cfg->cbb = first_bb;
1393 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1397 inline static MonoInst *
1398 mono_get_domainvar (MonoCompile *cfg)
1400 if (!cfg->domainvar)
1401 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1402 return cfg->domainvar;
1406 * mono_decompose_array_access_opts:
1408 * Decompose array access opcodes.
1411 mono_decompose_array_access_opts (MonoCompile *cfg)
1413 MonoBasicBlock *bb, *first_bb;
1416 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1417 * can be executed anytime. It should be run before decompose_long
1421 * Create a dummy bblock and emit code into it so we can use the normal
1422 * code generation macros.
1424 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1425 first_bb = cfg->cbb;
1427 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1429 MonoInst *prev = NULL;
1431 MonoInst *iargs [3];
1434 if (!bb->has_array_access)
1437 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1439 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1445 for (ins = bb->code; ins; ins = ins->next) {
1446 switch (ins->opcode) {
1448 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1449 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1450 MONO_ADD_INS (cfg->cbb, dest);
1452 case OP_BOUNDS_CHECK:
1453 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1454 if (COMPILE_LLVM (cfg))
1455 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1457 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1460 if (cfg->opt & MONO_OPT_SHARED) {
1461 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1462 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1463 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1464 iargs [2]->dreg = ins->sreg1;
1466 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1467 dest->dreg = ins->dreg;
1469 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1470 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1471 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1473 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1474 NEW_VTABLECONST (cfg, iargs [0], vtable);
1475 MONO_ADD_INS (cfg->cbb, iargs [0]);
1476 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1477 iargs [1]->dreg = ins->sreg1;
1480 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1482 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1483 dest->dreg = ins->dreg;
1487 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1488 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1494 g_assert (cfg->cbb == first_bb);
1496 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1497 /* Replace the original instruction with the new code sequence */
1499 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1500 first_bb->code = first_bb->last_ins = NULL;
1501 first_bb->in_count = first_bb->out_count = 0;
1502 cfg->cbb = first_bb;
1509 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1519 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1522 * mono_decompose_soft_float:
1524 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1525 * similar to long support on 32 bit platforms. 32 bit float values require special
1526 * handling when used as locals, arguments, and in calls.
1527 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1530 mono_decompose_soft_float (MonoCompile *cfg)
1532 MonoBasicBlock *bb, *first_bb;
1535 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1539 * Create a dummy bblock and emit code into it so we can use the normal
1540 * code generation macros.
1542 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1543 first_bb = cfg->cbb;
1545 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1547 MonoInst *prev = NULL;
1550 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1552 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1558 for (ins = bb->code; ins; ins = ins->next) {
1559 const char *spec = INS_INFO (ins->opcode);
1561 /* Most fp operations are handled automatically by opcode emulation */
1563 switch (ins->opcode) {
1566 d.vald = *(double*)ins->inst_p0;
1567 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1572 /* We load the r8 value */
1573 d.vald = *(float*)ins->inst_p0;
1574 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1578 ins->opcode = OP_LMOVE;
1581 ins->opcode = OP_MOVE;
1582 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1585 ins->opcode = OP_MOVE;
1586 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1589 int reg = ins->sreg1;
1591 ins->opcode = OP_SETLRET;
1593 ins->sreg1 = MONO_LVREG_LS (reg);
1594 ins->sreg2 = MONO_LVREG_MS (reg);
1597 case OP_LOADR8_MEMBASE:
1598 ins->opcode = OP_LOADI8_MEMBASE;
1600 case OP_STORER8_MEMBASE_REG:
1601 ins->opcode = OP_STOREI8_MEMBASE_REG;
1603 case OP_STORER4_MEMBASE_REG: {
1604 MonoInst *iargs [2];
1607 /* Arg 1 is the double value */
1608 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1609 iargs [0]->dreg = ins->sreg1;
1611 /* Arg 2 is the address to store to */
1612 addr_reg = mono_alloc_preg (cfg);
1613 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1614 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1618 case OP_LOADR4_MEMBASE: {
1619 MonoInst *iargs [1];
1623 addr_reg = mono_alloc_preg (cfg);
1624 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1625 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1626 conv->dreg = ins->dreg;
1631 case OP_FCALL_MEMBASE: {
1632 MonoCallInst *call = (MonoCallInst*)ins;
1633 if (call->signature->ret->type == MONO_TYPE_R4) {
1634 MonoCallInst *call2;
1635 MonoInst *iargs [1];
1639 /* Convert the call into a call returning an int */
1640 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1641 memcpy (call2, call, sizeof (MonoCallInst));
1642 switch (ins->opcode) {
1644 call2->inst.opcode = OP_CALL;
1647 call2->inst.opcode = OP_CALL_REG;
1649 case OP_FCALL_MEMBASE:
1650 call2->inst.opcode = OP_CALL_MEMBASE;
1653 g_assert_not_reached ();
1655 call2->inst.dreg = mono_alloc_ireg (cfg);
1656 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1658 /* Remap OUTARG_VT instructions referencing this call */
1659 for (l = call->outarg_vts; l; l = l->next)
1660 ((MonoInst*)(l->data))->inst_p0 = call2;
1662 /* FIXME: Optimize this */
1664 /* Emit an r4->r8 conversion */
1665 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1666 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1667 conv->dreg = ins->dreg;
1669 /* The call sequence might include fp ins */
1672 switch (ins->opcode) {
1674 ins->opcode = OP_LCALL;
1677 ins->opcode = OP_LCALL_REG;
1679 case OP_FCALL_MEMBASE:
1680 ins->opcode = OP_LCALL_MEMBASE;
1683 g_assert_not_reached ();
1689 MonoJitICallInfo *info;
1690 MonoInst *iargs [2];
1691 MonoInst *call, *cmp, *br;
1693 /* Convert fcompare+fbcc to icall+icompare+beq */
1696 /* The branch might be optimized away */
1701 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1703 /* The branch might be optimized away */
1708 /* Create dummy MonoInst's for the arguments */
1709 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1710 iargs [0]->dreg = ins->sreg1;
1711 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1712 iargs [1]->dreg = ins->sreg2;
1714 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1716 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1717 cmp->sreg1 = call->dreg;
1719 MONO_ADD_INS (cfg->cbb, cmp);
1721 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1722 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1723 br->inst_true_bb = ins->next->inst_true_bb;
1724 br->inst_false_bb = ins->next->inst_false_bb;
1725 MONO_ADD_INS (cfg->cbb, br);
1727 /* The call sequence might include fp ins */
1730 /* Skip fbcc or fccc */
1731 NULLIFY_INS (ins->next);
1739 MonoJitICallInfo *info;
1740 MonoInst *iargs [2];
1743 /* Convert fccc to icall+icompare+iceq */
1745 info = mono_find_jit_opcode_emulation (ins->opcode);
1748 /* Create dummy MonoInst's for the arguments */
1749 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1750 iargs [0]->dreg = ins->sreg1;
1751 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1752 iargs [1]->dreg = ins->sreg2;
1754 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1756 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1757 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1759 /* The call sequence might include fp ins */
1764 MonoInst *iargs [2];
1765 MonoInst *call, *cmp;
1767 /* Convert to icall+icompare+cond_exc+move */
1769 /* Create dummy MonoInst's for the arguments */
1770 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1771 iargs [0]->dreg = ins->sreg1;
1773 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1775 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1776 cmp->sreg1 = call->dreg;
1778 MONO_ADD_INS (cfg->cbb, cmp);
1780 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1782 /* Do the assignment if the value is finite */
1783 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1789 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1790 mono_print_ins (ins);
1791 g_assert_not_reached ();
1796 g_assert (cfg->cbb == first_bb);
1798 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1799 /* Replace the original instruction with the new code sequence */
1801 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1802 first_bb->code = first_bb->last_ins = NULL;
1803 first_bb->in_count = first_bb->out_count = 0;
1804 cfg->cbb = first_bb;
1811 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1814 mono_decompose_long_opts (cfg);
1820 mono_local_emulate_ops (MonoCompile *cfg)
1823 gboolean inlined_wrapper = FALSE;
1825 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1828 MONO_BB_FOR_EACH_INS (bb, ins) {
1829 int op_noimm = mono_op_imm_to_op (ins->opcode);
1830 MonoJitICallInfo *info;
1833 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1834 * to check whether its non-imm counterpart is emulated and, if so,
1835 * decompose it back to its non-imm counterpart.
1838 info = mono_find_jit_opcode_emulation (op_noimm);
1840 info = mono_find_jit_opcode_emulation (ins->opcode);
1845 MonoBasicBlock *first_bb;
1847 /* Create dummy MonoInst's for the arguments */
1848 g_assert (!info->sig->hasthis);
1849 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1852 mono_decompose_op_imm (cfg, bb, ins);
1854 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1855 if (info->sig->param_count > 0) {
1856 int sregs [MONO_MAX_SRC_REGS];
1858 num_sregs = mono_inst_get_src_registers (ins, sregs);
1859 g_assert (num_sregs == info->sig->param_count);
1860 for (i = 0; i < num_sregs; ++i) {
1861 MONO_INST_NEW (cfg, args [i], OP_ARG);
1862 args [i]->dreg = sregs [i];
1866 /* We emit the call on a separate dummy basic block */
1867 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1868 first_bb = cfg->cbb;
1870 call = mono_emit_jit_icall_by_info (cfg, info, args);
1871 call->dreg = ins->dreg;
1873 /* Replace ins with the emitted code and do the necessary bb linking */
1874 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1875 MonoInst *saved_prev = ins->prev;
1877 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1878 first_bb->code = first_bb->last_ins = NULL;
1879 first_bb->in_count = first_bb->out_count = 0;
1880 cfg->cbb = first_bb;
1882 /* ins is hanging, continue scanning the emitted code */
1885 g_error ("Failed to emit emulation code");
1887 inlined_wrapper = TRUE;
1893 * Avoid rerunning these passes by emitting directly the exception checkpoint
1894 * at IR level, instead of inlining the icall wrapper. FIXME
1896 if (inlined_wrapper) {
1897 if (!COMPILE_LLVM (cfg))
1898 mono_decompose_long_opts (cfg);
1899 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1900 mono_local_cprop (cfg);
1904 #endif /* DISABLE_JIT */