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);
475 #if SIZEOF_REGISTER == 8
479 int power = mono_is_power_of_two (ins->inst_imm);
480 if (ins->inst_imm == 1) {
481 ins->opcode = OP_ICONST;
482 MONO_INST_NULLIFY_SREGS (ins);
487 } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
488 gboolean is_long = ins->opcode == OP_LREM_IMM;
489 int compensator_reg = alloc_ireg (cfg);
490 int intermediate_reg;
492 /* Based on gcc code */
494 /* Add compensation for negative numerators */
497 intermediate_reg = compensator_reg;
498 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
500 intermediate_reg = ins->sreg1;
503 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_ISHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
504 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
505 /* Compute remainder */
506 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
507 /* Remove compensation */
508 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LSUB : OP_ISUB, ins->dreg, ins->dreg, compensator_reg);
522 #if SIZEOF_REGISTER == 8
523 if (decompose_long_opcode (cfg, ins, &repl))
526 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
530 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
531 cfg->has_emulated_ops = TRUE;
534 if (ins->opcode == OP_NOP) {
539 /* Use the last emitted instruction */
540 ins = cfg->cbb->last_ins;
543 g_assert (ins->dreg == dreg);
551 #if SIZEOF_REGISTER == 4
552 static int lbr_decomp [][2] = {
554 {OP_IBGT, OP_IBGE_UN}, /* BGE */
555 {OP_IBGT, OP_IBGT_UN}, /* BGT */
556 {OP_IBLT, OP_IBLE_UN}, /* BLE */
557 {OP_IBLT, OP_IBLT_UN}, /* BLT */
559 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
560 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
561 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
562 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
565 static int lcset_decomp [][2] = {
567 {OP_IBLT, OP_IBLE_UN}, /* CGT */
568 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
569 {OP_IBGT, OP_IBGE_UN}, /* CLT */
570 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
575 * mono_decompose_long_opts:
577 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
580 mono_decompose_long_opts (MonoCompile *cfg)
582 #if SIZEOF_REGISTER == 4
583 MonoBasicBlock *bb, *first_bb;
586 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
587 * needs to be able to handle long vregs.
591 * Create a dummy bblock and emit code into it so we can use the normal
592 * code generation macros.
594 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
597 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
598 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
599 MonoInst *prev = NULL;
602 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
605 cfg->cbb->code = cfg->cbb->last_ins = NULL;
608 mono_arch_decompose_long_opts (cfg, tree);
610 switch (tree->opcode) {
612 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
613 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
615 case OP_DUMMY_I8CONST:
616 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
617 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
622 case OP_LCONV_TO_OVF_U8_UN:
623 case OP_LCONV_TO_OVF_I8:
624 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
625 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
627 case OP_STOREI8_MEMBASE_REG:
628 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));
629 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));
631 case OP_LOADI8_MEMBASE:
632 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);
633 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);
636 case OP_ICONV_TO_I8: {
637 guint32 tmpreg = alloc_ireg (cfg);
641 * tmp = low > -1 ? 1: 0;
642 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
644 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
645 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
646 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
647 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
651 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
652 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
654 case OP_ICONV_TO_OVF_I8:
655 /* a signed 32 bit num always fits in a signed 64 bit one */
656 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
657 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
659 case OP_ICONV_TO_OVF_U8:
660 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
661 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
662 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
663 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
665 case OP_ICONV_TO_OVF_I8_UN:
666 case OP_ICONV_TO_OVF_U8_UN:
667 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
668 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
669 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
672 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
675 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
678 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
681 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
687 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
689 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
691 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
694 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
696 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
699 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
700 case OP_LCONV_TO_R_UN:
701 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
704 case OP_LCONV_TO_OVF_I1: {
705 MonoBasicBlock *is_negative, *end_label;
707 NEW_BBLOCK (cfg, is_negative);
708 NEW_BBLOCK (cfg, end_label);
710 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
711 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
712 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
713 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
715 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
716 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
719 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
720 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
721 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
724 MONO_START_BB (cfg, is_negative);
725 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
726 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
728 MONO_START_BB (cfg, end_label);
730 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
733 case OP_LCONV_TO_OVF_I1_UN:
734 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
735 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
737 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
738 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
739 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
740 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
741 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
743 case OP_LCONV_TO_OVF_U1:
744 case OP_LCONV_TO_OVF_U1_UN:
745 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
746 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
748 /* probe value to be within 0 to 255 */
749 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
750 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
751 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
753 case OP_LCONV_TO_OVF_I2: {
754 MonoBasicBlock *is_negative, *end_label;
756 NEW_BBLOCK (cfg, is_negative);
757 NEW_BBLOCK (cfg, end_label);
759 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
760 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
761 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
762 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
764 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
765 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
768 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
769 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
770 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
773 MONO_START_BB (cfg, is_negative);
774 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
775 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
776 MONO_START_BB (cfg, end_label);
778 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
781 case OP_LCONV_TO_OVF_I2_UN:
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
783 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
785 /* Probe value to be within -32768 and 32767 */
786 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
787 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
788 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
789 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
790 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
792 case OP_LCONV_TO_OVF_U2:
793 case OP_LCONV_TO_OVF_U2_UN:
794 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
795 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
797 /* Probe value to be within 0 and 65535 */
798 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
799 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
800 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
802 case OP_LCONV_TO_OVF_I4:
803 case OP_LCONV_TO_OVF_I:
804 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
806 case OP_LCONV_TO_OVF_U4:
807 case OP_LCONV_TO_OVF_U:
808 case OP_LCONV_TO_OVF_U4_UN:
809 case OP_LCONV_TO_OVF_U_UN:
810 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
811 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
812 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
814 case OP_LCONV_TO_OVF_I_UN:
815 case OP_LCONV_TO_OVF_I4_UN:
816 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
817 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
818 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
819 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
820 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
822 case OP_LCONV_TO_OVF_U8:
823 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
824 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
826 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
827 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
829 case OP_LCONV_TO_OVF_I8_UN:
830 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
831 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
833 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
834 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
838 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
839 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
842 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
843 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
847 /* ADC sets the condition code */
848 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
849 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
850 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
853 /* ADC sets the condition code */
854 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
855 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
856 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
859 /* SBB sets the condition code */
860 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
861 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
862 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
865 /* SBB sets the condition code */
866 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
867 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
868 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
871 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
872 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
875 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
876 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
879 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
880 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
883 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
884 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
887 /* Handled in mono_arch_decompose_long_opts () */
888 g_assert_not_reached ();
892 /* FIXME: Add OP_BIGMUL optimization */
896 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
897 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
900 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
901 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
904 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
905 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
908 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
909 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
912 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
913 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
916 if (tree->inst_c1 == 32) {
918 /* The original code had this comment: */
919 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
920 * later apply the speedup to the left shift as well
923 /* FIXME: Move this to the strength reduction pass */
924 /* just move the upper half to the lower and zero the high word */
925 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
926 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
930 if (tree->inst_c1 == 32) {
931 /* just move the lower half to the upper and zero the lower word */
932 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
933 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
938 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
942 switch (next->opcode) {
947 /* Branchless version based on gcc code */
948 d1 = alloc_ireg (cfg);
949 d2 = alloc_ireg (cfg);
950 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
951 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
952 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
953 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
954 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
966 /* Convert into three comparisons + branches */
967 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
968 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
969 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
970 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
971 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
972 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
978 /* Branchless version based on gcc code */
979 d1 = alloc_ireg (cfg);
980 d2 = alloc_ireg (cfg);
981 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
982 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
983 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
985 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
986 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
994 MonoBasicBlock *set_to_0, *set_to_1;
996 NEW_BBLOCK (cfg, set_to_0);
997 NEW_BBLOCK (cfg, set_to_1);
999 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1000 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1001 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1002 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1003 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1004 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1005 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1006 MONO_START_BB (cfg, set_to_1);
1007 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1008 MONO_START_BB (cfg, set_to_0);
1013 g_assert_not_reached ();
1018 /* Not yet used, since lcompare is decomposed before local cprop */
1019 case OP_LCOMPARE_IMM: {
1020 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1021 guint32 low_imm = tree->inst_ls_word;
1022 guint32 high_imm = tree->inst_ms_word;
1023 int low_reg = MONO_LVREG_LS (tree->sreg1);
1024 int high_reg = MONO_LVREG_MS (tree->sreg1);
1028 switch (next->opcode) {
1033 /* Branchless version based on gcc code */
1034 d1 = alloc_ireg (cfg);
1035 d2 = alloc_ireg (cfg);
1036 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1037 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1038 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1039 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1040 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1053 /* Convert into three comparisons + branches */
1054 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1055 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1056 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1057 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1058 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1059 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1065 /* Branchless version based on gcc code */
1066 d1 = alloc_ireg (cfg);
1067 d2 = alloc_ireg (cfg);
1068 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1069 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1070 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1072 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1073 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1081 MonoBasicBlock *set_to_0, *set_to_1;
1083 NEW_BBLOCK (cfg, set_to_0);
1084 NEW_BBLOCK (cfg, set_to_1);
1086 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1087 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1088 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1089 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1090 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1091 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1092 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1093 MONO_START_BB (cfg, set_to_1);
1094 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1095 MONO_START_BB (cfg, set_to_0);
1100 g_assert_not_reached ();
1109 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1112 /* Replace the original instruction with the new code sequence */
1114 /* Ignore the new value of prev */
1116 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1118 /* Process the newly added ops again since they can be long ops too */
1120 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1122 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1124 first_bb->code = first_bb->last_ins = NULL;
1125 first_bb->in_count = first_bb->out_count = 0;
1126 cfg->cbb = first_bb;
1130 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1137 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1138 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1143 * mono_decompose_vtype_opts:
1145 * Decompose valuetype opcodes.
1148 mono_decompose_vtype_opts (MonoCompile *cfg)
1150 MonoBasicBlock *bb, *first_bb;
1153 * Using OP_V opcodes and decomposing them later have two main benefits:
1154 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1156 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1157 * enabling optimizations to work on vtypes too.
1158 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1159 * can be executed anytime. It should be executed as late as possible so vtype
1160 * opcodes can be optimized by the other passes.
1161 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1162 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1164 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1165 * when OP_VMOVE opcodes are decomposed.
1169 * Vregs have no associated type information, so we store the type of the vregs
1174 * Create a dummy bblock and emit code into it so we can use the normal
1175 * code generation macros.
1177 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1178 first_bb = cfg->cbb;
1180 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1182 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1184 MonoInst *prev = NULL;
1185 MonoInst *src_var, *dest_var, *src, *dest;
1189 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1191 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1197 for (ins = bb->code; ins; ins = ins->next) {
1198 switch (ins->opcode) {
1200 g_assert (ins->klass);
1201 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1203 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1204 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1207 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1210 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1213 if (src_var->backend.is_pinvoke)
1214 dest_var->backend.is_pinvoke = 1;
1216 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1217 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1219 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1223 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1226 g_assert (ins->klass);
1228 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1229 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1231 if (cfg->compute_gc_maps) {
1235 * Tell the GC map code that the vtype is considered live after
1236 * the initialization.
1238 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1239 tmp->inst_c1 = ins->dreg;
1240 MONO_ADD_INS (cfg->cbb, tmp);
1243 case OP_DUMMY_VZERO:
1244 if (COMPILE_LLVM (cfg))
1249 case OP_STOREV_MEMBASE: {
1250 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1253 g_assert (ins->klass);
1254 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1257 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1259 dreg = alloc_preg (cfg);
1260 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1261 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1264 case OP_LOADV_MEMBASE: {
1265 g_assert (ins->klass);
1266 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1269 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1273 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1275 dreg = alloc_preg (cfg);
1276 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1277 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1278 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1281 case OP_OUTARG_VT: {
1282 if (COMPILE_LLVM (cfg))
1285 g_assert (ins->klass);
1287 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1289 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1290 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1292 mono_arch_emit_outarg_vt (cfg, ins, src);
1294 /* This might be decomposed into other vtype opcodes */
1298 case OP_OUTARG_VTRETADDR: {
1299 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1301 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1303 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1304 // FIXME: src_var->backend.is_pinvoke ?
1306 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1307 src->dreg = ins->dreg;
1312 case OP_VCALL_MEMBASE: {
1313 MonoCallInst *call = (MonoCallInst*)ins;
1316 if (COMPILE_LLVM (cfg))
1319 if (call->vret_in_reg) {
1320 MonoCallInst *call2;
1322 /* Replace the vcall with a scalar call */
1323 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1324 memcpy (call2, call, sizeof (MonoCallInst));
1325 switch (ins->opcode) {
1327 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1330 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1332 case OP_VCALL_MEMBASE:
1333 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1336 call2->inst.dreg = alloc_preg (cfg);
1337 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1339 /* Compute the vtype location */
1340 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1342 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1343 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1345 /* Save the result */
1346 if (dest_var->backend.is_pinvoke)
1347 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1349 size = mono_type_size (dest_var->inst_vtype, NULL);
1352 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1355 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1359 if (call->vret_in_reg_fp)
1360 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1362 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1368 if (call->vret_in_reg_fp) {
1369 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1372 #if SIZEOF_REGISTER == 4
1374 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1375 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1377 switch (call2->inst.opcode) {
1379 call2->inst.opcode = OP_LCALL;
1382 call2->inst.opcode = OP_LCALL_REG;
1384 case OP_CALL_MEMBASE:
1385 call2->inst.opcode = OP_LCALL_MEMBASE;
1388 call2->inst.dreg = alloc_lreg (cfg);
1389 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1390 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1392 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1396 /* This assumes the vtype is sizeof (gpointer) long */
1397 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1401 switch (ins->opcode) {
1403 ins->opcode = OP_VCALL2;
1406 ins->opcode = OP_VCALL2_REG;
1408 case OP_VCALL_MEMBASE:
1409 ins->opcode = OP_VCALL2_MEMBASE;
1420 g_assert (cfg->cbb == first_bb);
1422 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1423 /* Replace the original instruction with the new code sequence */
1425 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1426 first_bb->code = first_bb->last_ins = NULL;
1427 first_bb->in_count = first_bb->out_count = 0;
1428 cfg->cbb = first_bb;
1435 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1439 inline static MonoInst *
1440 mono_get_domainvar (MonoCompile *cfg)
1442 if (!cfg->domainvar)
1443 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1444 return cfg->domainvar;
1448 * mono_decompose_array_access_opts:
1450 * Decompose array access opcodes.
1453 mono_decompose_array_access_opts (MonoCompile *cfg)
1455 MonoBasicBlock *bb, *first_bb;
1458 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1459 * can be executed anytime. It should be run before decompose_long
1463 * Create a dummy bblock and emit code into it so we can use the normal
1464 * code generation macros.
1466 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1467 first_bb = cfg->cbb;
1469 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1471 MonoInst *prev = NULL;
1473 MonoInst *iargs [3];
1476 if (!bb->has_array_access)
1479 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1481 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1487 for (ins = bb->code; ins; ins = ins->next) {
1488 switch (ins->opcode) {
1490 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1491 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1492 MONO_ADD_INS (cfg->cbb, dest);
1494 case OP_BOUNDS_CHECK:
1495 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1496 if (COMPILE_LLVM (cfg))
1497 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1499 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1502 if (cfg->opt & MONO_OPT_SHARED) {
1503 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1504 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1505 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1506 iargs [2]->dreg = ins->sreg1;
1508 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1509 dest->dreg = ins->dreg;
1511 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1512 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1513 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1515 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1516 NEW_VTABLECONST (cfg, iargs [0], vtable);
1517 MONO_ADD_INS (cfg->cbb, iargs [0]);
1518 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1519 iargs [1]->dreg = ins->sreg1;
1522 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1524 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1525 dest->dreg = ins->dreg;
1529 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1530 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1536 g_assert (cfg->cbb == first_bb);
1538 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1539 /* Replace the original instruction with the new code sequence */
1541 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1542 first_bb->code = first_bb->last_ins = NULL;
1543 first_bb->in_count = first_bb->out_count = 0;
1544 cfg->cbb = first_bb;
1551 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1561 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1564 * mono_decompose_soft_float:
1566 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1567 * similar to long support on 32 bit platforms. 32 bit float values require special
1568 * handling when used as locals, arguments, and in calls.
1569 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1572 mono_decompose_soft_float (MonoCompile *cfg)
1574 MonoBasicBlock *bb, *first_bb;
1577 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1581 * Create a dummy bblock and emit code into it so we can use the normal
1582 * code generation macros.
1584 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1585 first_bb = cfg->cbb;
1587 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1589 MonoInst *prev = NULL;
1592 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1594 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1600 for (ins = bb->code; ins; ins = ins->next) {
1601 const char *spec = INS_INFO (ins->opcode);
1603 /* Most fp operations are handled automatically by opcode emulation */
1605 switch (ins->opcode) {
1608 d.vald = *(double*)ins->inst_p0;
1609 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1614 /* We load the r8 value */
1615 d.vald = *(float*)ins->inst_p0;
1616 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1620 ins->opcode = OP_LMOVE;
1623 ins->opcode = OP_MOVE;
1624 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1627 ins->opcode = OP_MOVE;
1628 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1631 int reg = ins->sreg1;
1633 ins->opcode = OP_SETLRET;
1635 ins->sreg1 = MONO_LVREG_LS (reg);
1636 ins->sreg2 = MONO_LVREG_MS (reg);
1639 case OP_LOADR8_MEMBASE:
1640 ins->opcode = OP_LOADI8_MEMBASE;
1642 case OP_STORER8_MEMBASE_REG:
1643 ins->opcode = OP_STOREI8_MEMBASE_REG;
1645 case OP_STORER4_MEMBASE_REG: {
1646 MonoInst *iargs [2];
1649 /* Arg 1 is the double value */
1650 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1651 iargs [0]->dreg = ins->sreg1;
1653 /* Arg 2 is the address to store to */
1654 addr_reg = mono_alloc_preg (cfg);
1655 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1656 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1660 case OP_LOADR4_MEMBASE: {
1661 MonoInst *iargs [1];
1665 addr_reg = mono_alloc_preg (cfg);
1666 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1667 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1668 conv->dreg = ins->dreg;
1673 case OP_FCALL_MEMBASE: {
1674 MonoCallInst *call = (MonoCallInst*)ins;
1675 if (call->signature->ret->type == MONO_TYPE_R4) {
1676 MonoCallInst *call2;
1677 MonoInst *iargs [1];
1681 /* Convert the call into a call returning an int */
1682 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1683 memcpy (call2, call, sizeof (MonoCallInst));
1684 switch (ins->opcode) {
1686 call2->inst.opcode = OP_CALL;
1689 call2->inst.opcode = OP_CALL_REG;
1691 case OP_FCALL_MEMBASE:
1692 call2->inst.opcode = OP_CALL_MEMBASE;
1695 g_assert_not_reached ();
1697 call2->inst.dreg = mono_alloc_ireg (cfg);
1698 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1700 /* Remap OUTARG_VT instructions referencing this call */
1701 for (l = call->outarg_vts; l; l = l->next)
1702 ((MonoInst*)(l->data))->inst_p0 = call2;
1704 /* FIXME: Optimize this */
1706 /* Emit an r4->r8 conversion */
1707 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1708 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1709 conv->dreg = ins->dreg;
1711 /* The call sequence might include fp ins */
1714 switch (ins->opcode) {
1716 ins->opcode = OP_LCALL;
1719 ins->opcode = OP_LCALL_REG;
1721 case OP_FCALL_MEMBASE:
1722 ins->opcode = OP_LCALL_MEMBASE;
1725 g_assert_not_reached ();
1731 MonoJitICallInfo *info;
1732 MonoInst *iargs [2];
1733 MonoInst *call, *cmp, *br;
1735 /* Convert fcompare+fbcc to icall+icompare+beq */
1738 /* The branch might be optimized away */
1743 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1745 /* The branch might be optimized away */
1750 /* Create dummy MonoInst's for the arguments */
1751 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1752 iargs [0]->dreg = ins->sreg1;
1753 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1754 iargs [1]->dreg = ins->sreg2;
1756 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1758 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1759 cmp->sreg1 = call->dreg;
1761 MONO_ADD_INS (cfg->cbb, cmp);
1763 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1764 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1765 br->inst_true_bb = ins->next->inst_true_bb;
1766 br->inst_false_bb = ins->next->inst_false_bb;
1767 MONO_ADD_INS (cfg->cbb, br);
1769 /* The call sequence might include fp ins */
1772 /* Skip fbcc or fccc */
1773 NULLIFY_INS (ins->next);
1781 MonoJitICallInfo *info;
1782 MonoInst *iargs [2];
1785 /* Convert fccc to icall+icompare+iceq */
1787 info = mono_find_jit_opcode_emulation (ins->opcode);
1790 /* Create dummy MonoInst's for the arguments */
1791 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1792 iargs [0]->dreg = ins->sreg1;
1793 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1794 iargs [1]->dreg = ins->sreg2;
1796 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1798 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1799 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1801 /* The call sequence might include fp ins */
1806 MonoInst *iargs [2];
1807 MonoInst *call, *cmp;
1809 /* Convert to icall+icompare+cond_exc+move */
1811 /* Create dummy MonoInst's for the arguments */
1812 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1813 iargs [0]->dreg = ins->sreg1;
1815 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1817 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1818 cmp->sreg1 = call->dreg;
1820 MONO_ADD_INS (cfg->cbb, cmp);
1822 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1824 /* Do the assignment if the value is finite */
1825 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1831 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1832 mono_print_ins (ins);
1833 g_assert_not_reached ();
1838 g_assert (cfg->cbb == first_bb);
1840 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1841 /* Replace the original instruction with the new code sequence */
1843 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1844 first_bb->code = first_bb->last_ins = NULL;
1845 first_bb->in_count = first_bb->out_count = 0;
1846 cfg->cbb = first_bb;
1853 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1856 mono_decompose_long_opts (cfg);
1862 mono_local_emulate_ops (MonoCompile *cfg)
1865 gboolean inlined_wrapper = FALSE;
1867 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1870 MONO_BB_FOR_EACH_INS (bb, ins) {
1871 int op_noimm = mono_op_imm_to_op (ins->opcode);
1872 MonoJitICallInfo *info;
1875 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1876 * to check whether its non-imm counterpart is emulated and, if so,
1877 * decompose it back to its non-imm counterpart.
1880 info = mono_find_jit_opcode_emulation (op_noimm);
1882 info = mono_find_jit_opcode_emulation (ins->opcode);
1887 MonoBasicBlock *first_bb;
1889 /* Create dummy MonoInst's for the arguments */
1890 g_assert (!info->sig->hasthis);
1891 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1894 mono_decompose_op_imm (cfg, bb, ins);
1896 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1897 if (info->sig->param_count > 0) {
1898 int sregs [MONO_MAX_SRC_REGS];
1900 num_sregs = mono_inst_get_src_registers (ins, sregs);
1901 g_assert (num_sregs == info->sig->param_count);
1902 for (i = 0; i < num_sregs; ++i) {
1903 MONO_INST_NEW (cfg, args [i], OP_ARG);
1904 args [i]->dreg = sregs [i];
1908 /* We emit the call on a separate dummy basic block */
1909 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1910 first_bb = cfg->cbb;
1912 call = mono_emit_jit_icall_by_info (cfg, info, args);
1913 call->dreg = ins->dreg;
1915 /* Replace ins with the emitted code and do the necessary bb linking */
1916 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1917 MonoInst *saved_prev = ins->prev;
1919 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1920 first_bb->code = first_bb->last_ins = NULL;
1921 first_bb->in_count = first_bb->out_count = 0;
1922 cfg->cbb = first_bb;
1924 /* ins is hanging, continue scanning the emitted code */
1927 g_error ("Failed to emit emulation code");
1929 inlined_wrapper = TRUE;
1935 * Avoid rerunning these passes by emitting directly the exception checkpoint
1936 * at IR level, instead of inlining the icall wrapper. FIXME
1938 if (inlined_wrapper) {
1939 if (!COMPILE_LLVM (cfg))
1940 mono_decompose_long_opts (cfg);
1941 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1942 mono_local_cprop (cfg);
1946 #endif /* DISABLE_JIT */