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 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
443 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
450 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
453 if (cfg->backend->need_div_check) {
454 int reg1 = alloc_ireg (cfg);
455 int reg2 = alloc_ireg (cfg);
457 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
458 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
459 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
460 /* b == -1 && a == 0x80000000 */
461 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
462 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
463 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
464 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
465 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
466 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
467 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
470 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
481 #if SIZEOF_REGISTER == 8
482 if (decompose_long_opcode (cfg, ins, &repl))
485 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
489 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
490 cfg->has_emulated_ops = TRUE;
493 if (ins->opcode == OP_NOP) {
498 /* Use the last emitted instruction */
499 ins = cfg->cbb->last_ins;
502 g_assert (ins->dreg == dreg);
510 #if SIZEOF_REGISTER == 4
511 static int lbr_decomp [][2] = {
513 {OP_IBGT, OP_IBGE_UN}, /* BGE */
514 {OP_IBGT, OP_IBGT_UN}, /* BGT */
515 {OP_IBLT, OP_IBLE_UN}, /* BLE */
516 {OP_IBLT, OP_IBLT_UN}, /* BLT */
518 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
519 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
520 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
521 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
524 static int lcset_decomp [][2] = {
526 {OP_IBLT, OP_IBLE_UN}, /* CGT */
527 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
528 {OP_IBGT, OP_IBGE_UN}, /* CLT */
529 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
534 * mono_decompose_long_opts:
536 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
539 mono_decompose_long_opts (MonoCompile *cfg)
541 #if SIZEOF_REGISTER == 4
542 MonoBasicBlock *bb, *first_bb;
545 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
546 * needs to be able to handle long vregs.
550 * Create a dummy bblock and emit code into it so we can use the normal
551 * code generation macros.
553 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
556 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
557 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
558 MonoInst *prev = NULL;
561 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
564 cfg->cbb->code = cfg->cbb->last_ins = NULL;
567 mono_arch_decompose_long_opts (cfg, tree);
569 switch (tree->opcode) {
571 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
572 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
574 case OP_DUMMY_I8CONST:
575 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
576 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
581 case OP_LCONV_TO_OVF_U8_UN:
582 case OP_LCONV_TO_OVF_I8:
583 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
584 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
586 case OP_STOREI8_MEMBASE_REG:
587 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));
588 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));
590 case OP_LOADI8_MEMBASE:
591 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);
592 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);
595 case OP_ICONV_TO_I8: {
596 guint32 tmpreg = alloc_ireg (cfg);
600 * tmp = low > -1 ? 1: 0;
601 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
603 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
604 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
605 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
606 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
610 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
611 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
613 case OP_ICONV_TO_OVF_I8:
614 /* a signed 32 bit num always fits in a signed 64 bit one */
615 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
616 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
618 case OP_ICONV_TO_OVF_U8:
619 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
620 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
621 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
622 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
624 case OP_ICONV_TO_OVF_I8_UN:
625 case OP_ICONV_TO_OVF_U8_UN:
626 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
627 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
628 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
631 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
634 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
637 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
640 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
646 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
648 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
650 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
653 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
655 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
658 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
659 case OP_LCONV_TO_R_UN:
660 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
663 case OP_LCONV_TO_OVF_I1: {
664 MonoBasicBlock *is_negative, *end_label;
666 NEW_BBLOCK (cfg, is_negative);
667 NEW_BBLOCK (cfg, end_label);
669 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
670 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
671 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
672 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
674 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
675 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
678 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
679 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
680 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
683 MONO_START_BB (cfg, is_negative);
684 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
685 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
687 MONO_START_BB (cfg, end_label);
689 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
692 case OP_LCONV_TO_OVF_I1_UN:
693 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
694 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
696 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
697 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
698 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
699 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
700 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
702 case OP_LCONV_TO_OVF_U1:
703 case OP_LCONV_TO_OVF_U1_UN:
704 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
705 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
707 /* probe value to be within 0 to 255 */
708 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
709 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
710 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
712 case OP_LCONV_TO_OVF_I2: {
713 MonoBasicBlock *is_negative, *end_label;
715 NEW_BBLOCK (cfg, is_negative);
716 NEW_BBLOCK (cfg, end_label);
718 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
719 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
720 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
721 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
723 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
724 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
727 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
728 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
729 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
732 MONO_START_BB (cfg, is_negative);
733 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
734 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
735 MONO_START_BB (cfg, end_label);
737 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
740 case OP_LCONV_TO_OVF_I2_UN:
741 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
742 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
744 /* Probe value to be within -32768 and 32767 */
745 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
746 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
747 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
748 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
749 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
751 case OP_LCONV_TO_OVF_U2:
752 case OP_LCONV_TO_OVF_U2_UN:
753 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
754 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
756 /* Probe value to be within 0 and 65535 */
757 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
758 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
759 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
761 case OP_LCONV_TO_OVF_I4:
762 case OP_LCONV_TO_OVF_I:
763 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
765 case OP_LCONV_TO_OVF_U4:
766 case OP_LCONV_TO_OVF_U:
767 case OP_LCONV_TO_OVF_U4_UN:
768 case OP_LCONV_TO_OVF_U_UN:
769 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
770 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
771 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
773 case OP_LCONV_TO_OVF_I_UN:
774 case OP_LCONV_TO_OVF_I4_UN:
775 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
776 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
777 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
778 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
779 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
781 case OP_LCONV_TO_OVF_U8:
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
783 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
785 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
786 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
788 case OP_LCONV_TO_OVF_I8_UN:
789 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
790 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
792 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
793 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
797 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
798 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
801 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
802 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
806 /* ADC sets the condition code */
807 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
808 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
809 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
812 /* ADC sets the condition code */
813 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
814 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
815 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
818 /* SBB sets the condition code */
819 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
820 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
821 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
824 /* SBB sets the condition code */
825 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
826 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
827 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
830 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
831 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
834 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
835 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
838 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
839 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
842 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
843 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
846 /* Handled in mono_arch_decompose_long_opts () */
847 g_assert_not_reached ();
851 /* FIXME: Add OP_BIGMUL optimization */
855 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
856 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
859 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
860 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
863 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
864 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
867 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
868 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
871 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
872 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
875 if (tree->inst_c1 == 32) {
877 /* The original code had this comment: */
878 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
879 * later apply the speedup to the left shift as well
882 /* FIXME: Move this to the strength reduction pass */
883 /* just move the upper half to the lower and zero the high word */
884 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
885 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
889 if (tree->inst_c1 == 32) {
890 /* just move the lower half to the upper and zero the lower word */
891 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
892 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
897 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
901 switch (next->opcode) {
906 /* Branchless version based on gcc code */
907 d1 = alloc_ireg (cfg);
908 d2 = alloc_ireg (cfg);
909 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
910 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
911 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
912 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
913 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
925 /* Convert into three comparisons + branches */
926 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
927 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
928 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
929 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
930 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
931 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
937 /* Branchless version based on gcc code */
938 d1 = alloc_ireg (cfg);
939 d2 = alloc_ireg (cfg);
940 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
941 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
942 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
944 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
945 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
953 MonoBasicBlock *set_to_0, *set_to_1;
955 NEW_BBLOCK (cfg, set_to_0);
956 NEW_BBLOCK (cfg, set_to_1);
958 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
959 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
960 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
961 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
962 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
963 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
964 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
965 MONO_START_BB (cfg, set_to_1);
966 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
967 MONO_START_BB (cfg, set_to_0);
972 g_assert_not_reached ();
977 /* Not yet used, since lcompare is decomposed before local cprop */
978 case OP_LCOMPARE_IMM: {
979 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
980 guint32 low_imm = tree->inst_ls_word;
981 guint32 high_imm = tree->inst_ms_word;
982 int low_reg = MONO_LVREG_LS (tree->sreg1);
983 int high_reg = MONO_LVREG_MS (tree->sreg1);
987 switch (next->opcode) {
992 /* Branchless version based on gcc code */
993 d1 = alloc_ireg (cfg);
994 d2 = alloc_ireg (cfg);
995 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
996 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
997 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
998 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
999 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1012 /* Convert into three comparisons + branches */
1013 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1014 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1015 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1016 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1017 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1018 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1024 /* Branchless version based on gcc code */
1025 d1 = alloc_ireg (cfg);
1026 d2 = alloc_ireg (cfg);
1027 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1028 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1029 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1031 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1032 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1040 MonoBasicBlock *set_to_0, *set_to_1;
1042 NEW_BBLOCK (cfg, set_to_0);
1043 NEW_BBLOCK (cfg, set_to_1);
1045 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1046 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1047 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1048 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1049 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1050 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1051 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1052 MONO_START_BB (cfg, set_to_1);
1053 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1054 MONO_START_BB (cfg, set_to_0);
1059 g_assert_not_reached ();
1068 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1071 /* Replace the original instruction with the new code sequence */
1073 /* Ignore the new value of prev */
1075 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1077 /* Process the newly added ops again since they can be long ops too */
1079 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1081 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1083 first_bb->code = first_bb->last_ins = NULL;
1084 first_bb->in_count = first_bb->out_count = 0;
1085 cfg->cbb = first_bb;
1089 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1096 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1097 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1102 * mono_decompose_vtype_opts:
1104 * Decompose valuetype opcodes.
1107 mono_decompose_vtype_opts (MonoCompile *cfg)
1109 MonoBasicBlock *bb, *first_bb;
1112 * Using OP_V opcodes and decomposing them later have two main benefits:
1113 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1115 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1116 * enabling optimizations to work on vtypes too.
1117 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1118 * can be executed anytime. It should be executed as late as possible so vtype
1119 * opcodes can be optimized by the other passes.
1120 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1121 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1123 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1124 * when OP_VMOVE opcodes are decomposed.
1128 * Vregs have no associated type information, so we store the type of the vregs
1133 * Create a dummy bblock and emit code into it so we can use the normal
1134 * code generation macros.
1136 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1137 first_bb = cfg->cbb;
1139 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1141 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1143 MonoInst *prev = NULL;
1144 MonoInst *src_var, *dest_var, *src, *dest;
1148 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1150 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1156 for (ins = bb->code; ins; ins = ins->next) {
1157 switch (ins->opcode) {
1159 g_assert (ins->klass);
1160 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1162 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1163 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1166 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1169 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1172 if (src_var->backend.is_pinvoke)
1173 dest_var->backend.is_pinvoke = 1;
1175 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1176 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1178 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1182 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1185 g_assert (ins->klass);
1187 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1188 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1190 if (cfg->compute_gc_maps) {
1194 * Tell the GC map code that the vtype is considered live after
1195 * the initialization.
1197 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1198 tmp->inst_c1 = ins->dreg;
1199 MONO_ADD_INS (cfg->cbb, tmp);
1202 case OP_DUMMY_VZERO:
1203 if (COMPILE_LLVM (cfg))
1208 case OP_STOREV_MEMBASE: {
1209 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1212 g_assert (ins->klass);
1213 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1216 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1218 dreg = alloc_preg (cfg);
1219 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1220 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1223 case OP_LOADV_MEMBASE: {
1224 g_assert (ins->klass);
1225 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1228 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1232 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1234 dreg = alloc_preg (cfg);
1235 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1236 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1237 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1240 case OP_OUTARG_VT: {
1241 if (COMPILE_LLVM (cfg))
1244 g_assert (ins->klass);
1246 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1248 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1249 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1251 mono_arch_emit_outarg_vt (cfg, ins, src);
1253 /* This might be decomposed into other vtype opcodes */
1257 case OP_OUTARG_VTRETADDR: {
1258 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1260 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1262 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1263 // FIXME: src_var->backend.is_pinvoke ?
1265 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1266 src->dreg = ins->dreg;
1271 case OP_VCALL_MEMBASE: {
1272 MonoCallInst *call = (MonoCallInst*)ins;
1275 if (COMPILE_LLVM (cfg))
1278 if (call->vret_in_reg) {
1279 MonoCallInst *call2;
1281 /* Replace the vcall with a scalar call */
1282 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1283 memcpy (call2, call, sizeof (MonoCallInst));
1284 switch (ins->opcode) {
1286 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1289 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1291 case OP_VCALL_MEMBASE:
1292 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1295 call2->inst.dreg = alloc_preg (cfg);
1296 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1298 /* Compute the vtype location */
1299 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1301 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1302 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1304 /* Save the result */
1305 if (dest_var->backend.is_pinvoke)
1306 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1308 size = mono_type_size (dest_var->inst_vtype, NULL);
1311 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1314 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1318 if (call->vret_in_reg_fp)
1319 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1321 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1327 if (call->vret_in_reg_fp) {
1328 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1331 #if SIZEOF_REGISTER == 4
1333 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1334 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1336 switch (call2->inst.opcode) {
1338 call2->inst.opcode = OP_LCALL;
1341 call2->inst.opcode = OP_LCALL_REG;
1343 case OP_CALL_MEMBASE:
1344 call2->inst.opcode = OP_LCALL_MEMBASE;
1347 call2->inst.dreg = alloc_lreg (cfg);
1348 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1349 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1351 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1355 /* This assumes the vtype is sizeof (gpointer) long */
1356 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1360 switch (ins->opcode) {
1362 ins->opcode = OP_VCALL2;
1365 ins->opcode = OP_VCALL2_REG;
1367 case OP_VCALL_MEMBASE:
1368 ins->opcode = OP_VCALL2_MEMBASE;
1379 g_assert (cfg->cbb == first_bb);
1381 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1382 /* Replace the original instruction with the new code sequence */
1384 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1385 first_bb->code = first_bb->last_ins = NULL;
1386 first_bb->in_count = first_bb->out_count = 0;
1387 cfg->cbb = first_bb;
1394 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1398 inline static MonoInst *
1399 mono_get_domainvar (MonoCompile *cfg)
1401 if (!cfg->domainvar)
1402 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1403 return cfg->domainvar;
1407 * mono_decompose_array_access_opts:
1409 * Decompose array access opcodes.
1412 mono_decompose_array_access_opts (MonoCompile *cfg)
1414 MonoBasicBlock *bb, *first_bb;
1417 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1418 * can be executed anytime. It should be run before decompose_long
1422 * Create a dummy bblock and emit code into it so we can use the normal
1423 * code generation macros.
1425 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1426 first_bb = cfg->cbb;
1428 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1430 MonoInst *prev = NULL;
1432 MonoInst *iargs [3];
1435 if (!bb->has_array_access)
1438 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1440 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1446 for (ins = bb->code; ins; ins = ins->next) {
1447 switch (ins->opcode) {
1449 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1450 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1451 MONO_ADD_INS (cfg->cbb, dest);
1453 case OP_BOUNDS_CHECK:
1454 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1455 if (COMPILE_LLVM (cfg))
1456 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1458 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1461 if (cfg->opt & MONO_OPT_SHARED) {
1462 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1463 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1464 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1465 iargs [2]->dreg = ins->sreg1;
1467 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1468 dest->dreg = ins->dreg;
1470 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1471 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1472 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1474 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1475 NEW_VTABLECONST (cfg, iargs [0], vtable);
1476 MONO_ADD_INS (cfg->cbb, iargs [0]);
1477 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1478 iargs [1]->dreg = ins->sreg1;
1481 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1483 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1484 dest->dreg = ins->dreg;
1488 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1489 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1495 g_assert (cfg->cbb == first_bb);
1497 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1498 /* Replace the original instruction with the new code sequence */
1500 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1501 first_bb->code = first_bb->last_ins = NULL;
1502 first_bb->in_count = first_bb->out_count = 0;
1503 cfg->cbb = first_bb;
1510 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1520 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1523 * mono_decompose_soft_float:
1525 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1526 * similar to long support on 32 bit platforms. 32 bit float values require special
1527 * handling when used as locals, arguments, and in calls.
1528 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1531 mono_decompose_soft_float (MonoCompile *cfg)
1533 MonoBasicBlock *bb, *first_bb;
1536 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1540 * Create a dummy bblock and emit code into it so we can use the normal
1541 * code generation macros.
1543 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1544 first_bb = cfg->cbb;
1546 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1548 MonoInst *prev = NULL;
1551 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1553 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1559 for (ins = bb->code; ins; ins = ins->next) {
1560 const char *spec = INS_INFO (ins->opcode);
1562 /* Most fp operations are handled automatically by opcode emulation */
1564 switch (ins->opcode) {
1567 d.vald = *(double*)ins->inst_p0;
1568 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1573 /* We load the r8 value */
1574 d.vald = *(float*)ins->inst_p0;
1575 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1579 ins->opcode = OP_LMOVE;
1582 ins->opcode = OP_MOVE;
1583 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1586 ins->opcode = OP_MOVE;
1587 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1590 int reg = ins->sreg1;
1592 ins->opcode = OP_SETLRET;
1594 ins->sreg1 = MONO_LVREG_LS (reg);
1595 ins->sreg2 = MONO_LVREG_MS (reg);
1598 case OP_LOADR8_MEMBASE:
1599 ins->opcode = OP_LOADI8_MEMBASE;
1601 case OP_STORER8_MEMBASE_REG:
1602 ins->opcode = OP_STOREI8_MEMBASE_REG;
1604 case OP_STORER4_MEMBASE_REG: {
1605 MonoInst *iargs [2];
1608 /* Arg 1 is the double value */
1609 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1610 iargs [0]->dreg = ins->sreg1;
1612 /* Arg 2 is the address to store to */
1613 addr_reg = mono_alloc_preg (cfg);
1614 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1615 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1619 case OP_LOADR4_MEMBASE: {
1620 MonoInst *iargs [1];
1624 addr_reg = mono_alloc_preg (cfg);
1625 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1626 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1627 conv->dreg = ins->dreg;
1632 case OP_FCALL_MEMBASE: {
1633 MonoCallInst *call = (MonoCallInst*)ins;
1634 if (call->signature->ret->type == MONO_TYPE_R4) {
1635 MonoCallInst *call2;
1636 MonoInst *iargs [1];
1640 /* Convert the call into a call returning an int */
1641 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1642 memcpy (call2, call, sizeof (MonoCallInst));
1643 switch (ins->opcode) {
1645 call2->inst.opcode = OP_CALL;
1648 call2->inst.opcode = OP_CALL_REG;
1650 case OP_FCALL_MEMBASE:
1651 call2->inst.opcode = OP_CALL_MEMBASE;
1654 g_assert_not_reached ();
1656 call2->inst.dreg = mono_alloc_ireg (cfg);
1657 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1659 /* Remap OUTARG_VT instructions referencing this call */
1660 for (l = call->outarg_vts; l; l = l->next)
1661 ((MonoInst*)(l->data))->inst_p0 = call2;
1663 /* FIXME: Optimize this */
1665 /* Emit an r4->r8 conversion */
1666 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1667 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1668 conv->dreg = ins->dreg;
1670 /* The call sequence might include fp ins */
1673 switch (ins->opcode) {
1675 ins->opcode = OP_LCALL;
1678 ins->opcode = OP_LCALL_REG;
1680 case OP_FCALL_MEMBASE:
1681 ins->opcode = OP_LCALL_MEMBASE;
1684 g_assert_not_reached ();
1690 MonoJitICallInfo *info;
1691 MonoInst *iargs [2];
1692 MonoInst *call, *cmp, *br;
1694 /* Convert fcompare+fbcc to icall+icompare+beq */
1697 /* The branch might be optimized away */
1702 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1704 /* The branch might be optimized away */
1709 /* Create dummy MonoInst's for the arguments */
1710 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1711 iargs [0]->dreg = ins->sreg1;
1712 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1713 iargs [1]->dreg = ins->sreg2;
1715 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1717 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1718 cmp->sreg1 = call->dreg;
1720 MONO_ADD_INS (cfg->cbb, cmp);
1722 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1723 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1724 br->inst_true_bb = ins->next->inst_true_bb;
1725 br->inst_false_bb = ins->next->inst_false_bb;
1726 MONO_ADD_INS (cfg->cbb, br);
1728 /* The call sequence might include fp ins */
1731 /* Skip fbcc or fccc */
1732 NULLIFY_INS (ins->next);
1740 MonoJitICallInfo *info;
1741 MonoInst *iargs [2];
1744 /* Convert fccc to icall+icompare+iceq */
1746 info = mono_find_jit_opcode_emulation (ins->opcode);
1749 /* Create dummy MonoInst's for the arguments */
1750 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1751 iargs [0]->dreg = ins->sreg1;
1752 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1753 iargs [1]->dreg = ins->sreg2;
1755 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1757 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1758 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1760 /* The call sequence might include fp ins */
1765 MonoInst *iargs [2];
1766 MonoInst *call, *cmp;
1768 /* Convert to icall+icompare+cond_exc+move */
1770 /* Create dummy MonoInst's for the arguments */
1771 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1772 iargs [0]->dreg = ins->sreg1;
1774 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1776 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1777 cmp->sreg1 = call->dreg;
1779 MONO_ADD_INS (cfg->cbb, cmp);
1781 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1783 /* Do the assignment if the value is finite */
1784 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1790 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1791 mono_print_ins (ins);
1792 g_assert_not_reached ();
1797 g_assert (cfg->cbb == first_bb);
1799 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1800 /* Replace the original instruction with the new code sequence */
1802 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1803 first_bb->code = first_bb->last_ins = NULL;
1804 first_bb->in_count = first_bb->out_count = 0;
1805 cfg->cbb = first_bb;
1812 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1815 mono_decompose_long_opts (cfg);
1821 mono_local_emulate_ops (MonoCompile *cfg)
1824 gboolean inlined_wrapper = FALSE;
1826 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1829 MONO_BB_FOR_EACH_INS (bb, ins) {
1830 int op_noimm = mono_op_imm_to_op (ins->opcode);
1831 MonoJitICallInfo *info;
1834 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1835 * to check whether its non-imm counterpart is emulated and, if so,
1836 * decompose it back to its non-imm counterpart.
1839 info = mono_find_jit_opcode_emulation (op_noimm);
1841 info = mono_find_jit_opcode_emulation (ins->opcode);
1846 MonoBasicBlock *first_bb;
1848 /* Create dummy MonoInst's for the arguments */
1849 g_assert (!info->sig->hasthis);
1850 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1853 mono_decompose_op_imm (cfg, bb, ins);
1855 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1856 if (info->sig->param_count > 0) {
1857 int sregs [MONO_MAX_SRC_REGS];
1859 num_sregs = mono_inst_get_src_registers (ins, sregs);
1860 g_assert (num_sregs == info->sig->param_count);
1861 for (i = 0; i < num_sregs; ++i) {
1862 MONO_INST_NEW (cfg, args [i], OP_ARG);
1863 args [i]->dreg = sregs [i];
1867 /* We emit the call on a separate dummy basic block */
1868 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1869 first_bb = cfg->cbb;
1871 call = mono_emit_jit_icall_by_info (cfg, info, args);
1872 call->dreg = ins->dreg;
1874 /* Replace ins with the emitted code and do the necessary bb linking */
1875 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1876 MonoInst *saved_prev = ins->prev;
1878 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1879 first_bb->code = first_bb->last_ins = NULL;
1880 first_bb->in_count = first_bb->out_count = 0;
1881 cfg->cbb = first_bb;
1883 /* ins is hanging, continue scanning the emitted code */
1886 g_error ("Failed to emit emulation code");
1888 inlined_wrapper = TRUE;
1894 * Avoid rerunning these passes by emitting directly the exception checkpoint
1895 * at IR level, instead of inlining the icall wrapper. FIXME
1897 if (inlined_wrapper) {
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 */