2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include "jit-icalls.h"
15 #include <mono/metadata/gc-internals.h>
16 #include <mono/metadata/abi-details.h>
20 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
21 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
22 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
23 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
26 * Decompose complex long opcodes on 64 bit machines.
27 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
30 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
32 MonoInst *repl = NULL;
36 switch (ins->opcode) {
38 ins->opcode = OP_SEXT_I4;
42 if (SIZEOF_VOID_P == 4)
43 ins->opcode = OP_LMOVE;
45 ins->opcode = OP_MOVE;
48 if (SIZEOF_VOID_P == 4)
50 ins->opcode = OP_SEXT_I4;
52 ins->opcode = OP_MOVE;
55 if (SIZEOF_VOID_P == 4) {
57 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
60 ins->opcode = OP_MOVE;
64 ins->opcode = OP_SEXT_I4;
67 ins->opcode = OP_ZEXT_I4;
70 /* Clean out the upper word */
71 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
77 if (COMPILE_LLVM (cfg))
79 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
83 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
84 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
88 case OP_LADD_OVF_UN: {
91 if (COMPILE_LLVM (cfg))
93 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
97 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
98 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
102 #ifndef __mono_ppc64__
106 if (COMPILE_LLVM (cfg))
108 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
112 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
113 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
117 case OP_LSUB_OVF_UN: {
120 if (COMPILE_LLVM (cfg))
122 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
126 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
127 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
133 case OP_ICONV_TO_OVF_I8:
134 case OP_ICONV_TO_OVF_I:
135 ins->opcode = OP_SEXT_I4;
137 case OP_ICONV_TO_OVF_U8:
138 case OP_ICONV_TO_OVF_U:
139 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
140 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
141 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
144 case OP_ICONV_TO_OVF_I8_UN:
145 case OP_ICONV_TO_OVF_U8_UN:
146 case OP_ICONV_TO_OVF_I_UN:
147 case OP_ICONV_TO_OVF_U_UN:
148 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
149 /* Clean out the upper word */
150 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
153 case OP_LCONV_TO_OVF_I1:
154 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
155 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
156 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
157 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
158 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
161 case OP_LCONV_TO_OVF_I1_UN:
162 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
163 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
164 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
167 case OP_LCONV_TO_OVF_U1:
168 /* probe value to be within 0 to 255 */
169 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
170 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
171 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
174 case OP_LCONV_TO_OVF_U1_UN:
175 /* probe value to be within 0 to 255 */
176 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
177 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
178 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
181 case OP_LCONV_TO_OVF_I2:
182 /* Probe value to be within -32768 and 32767 */
183 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
184 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
185 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
186 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
187 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
190 case OP_LCONV_TO_OVF_I2_UN:
191 /* Probe value to be within 0 and 32767 */
192 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
193 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
194 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
197 case OP_LCONV_TO_OVF_U2:
198 /* Probe value to be within 0 and 65535 */
199 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
200 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
201 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
204 case OP_LCONV_TO_OVF_U2_UN:
205 /* Probe value to be within 0 and 65535 */
206 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
207 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
211 case OP_LCONV_TO_OVF_I4:
212 #if SIZEOF_VOID_P == 4
213 case OP_LCONV_TO_OVF_I:
215 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
216 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
217 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
218 #if SIZEOF_REGISTER == 8
219 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
221 g_assert (COMPILE_LLVM (cfg));
222 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
224 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
225 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
228 case OP_LCONV_TO_OVF_I4_UN:
229 #if SIZEOF_VOID_P == 4
230 case OP_LCONV_TO_OVF_I_UN:
232 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
233 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
234 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
237 case OP_LCONV_TO_OVF_U4:
238 #if SIZEOF_VOID_P == 4
239 case OP_LCONV_TO_OVF_U:
241 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
242 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
243 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
244 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
245 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
248 case OP_LCONV_TO_OVF_U4_UN:
249 #if SIZEOF_VOID_P == 4
250 case OP_LCONV_TO_OVF_U_UN:
252 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
253 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
254 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
257 #if SIZEOF_VOID_P == 8
258 case OP_LCONV_TO_OVF_I:
259 case OP_LCONV_TO_OVF_U_UN:
261 case OP_LCONV_TO_OVF_U8_UN:
262 case OP_LCONV_TO_OVF_I8:
263 ins->opcode = OP_MOVE;
265 #if SIZEOF_VOID_P == 8
266 case OP_LCONV_TO_OVF_I_UN:
268 case OP_LCONV_TO_OVF_I8_UN:
269 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
270 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
271 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
274 case OP_LCONV_TO_OVF_U8:
275 #if SIZEOF_VOID_P == 8
276 case OP_LCONV_TO_OVF_U:
278 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
279 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
280 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
292 * mono_decompose_opcode:
294 * Decompose complex opcodes into ones closer to opcodes supported by
295 * the given architecture.
296 * Returns a MonoInst which represents the result of the decomposition, and can
297 * be pushed on the IL stack. This is needed because the original instruction is
299 * Sets the cfg exception if an opcode is not supported.
302 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
304 MonoInst *repl = NULL;
305 int type = ins->type;
306 int dreg = ins->dreg;
307 gboolean emulate = FALSE;
309 /* FIXME: Instead of = NOP, don't emit the original ins at all */
310 mono_arch_decompose_opts (cfg, ins);
313 * The code below assumes that we are called immediately after emitting
314 * ins. This means we can emit code using the normal code generation
317 switch (ins->opcode) {
318 /* this doesn't make sense on ppc and other architectures */
319 #if !defined(MONO_ARCH_NO_IOV_CHECK)
321 if (COMPILE_LLVM (cfg))
323 ins->opcode = OP_IADDCC;
324 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
327 if (COMPILE_LLVM (cfg))
329 ins->opcode = OP_IADDCC;
330 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
333 if (COMPILE_LLVM (cfg))
335 ins->opcode = OP_ISUBCC;
336 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
339 if (COMPILE_LLVM (cfg))
341 ins->opcode = OP_ISUBCC;
342 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
345 case OP_ICONV_TO_OVF_I1:
346 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
347 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
348 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
349 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
350 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
353 case OP_ICONV_TO_OVF_I1_UN:
354 /* probe values between 0 to 127 */
355 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
356 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
357 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
360 case OP_ICONV_TO_OVF_U1:
361 case OP_ICONV_TO_OVF_U1_UN:
362 /* probe value to be within 0 to 255 */
363 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
364 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
365 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
368 case OP_ICONV_TO_OVF_I2:
369 /* Probe value to be within -32768 and 32767 */
370 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
371 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
372 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
373 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
374 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
377 case OP_ICONV_TO_OVF_I2_UN:
378 /* Convert uint value into short, value within 0 and 32767 */
379 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
380 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
381 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
384 case OP_ICONV_TO_OVF_U2:
385 case OP_ICONV_TO_OVF_U2_UN:
386 /* Probe value to be within 0 and 65535 */
387 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
388 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
389 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
392 case OP_ICONV_TO_OVF_U4:
393 case OP_ICONV_TO_OVF_I4_UN:
394 #if SIZEOF_VOID_P == 4
395 case OP_ICONV_TO_OVF_U:
396 case OP_ICONV_TO_OVF_I_UN:
398 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
399 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
400 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
405 case OP_ICONV_TO_OVF_I4:
406 case OP_ICONV_TO_OVF_U4_UN:
407 #if SIZEOF_VOID_P == 4
408 case OP_ICONV_TO_OVF_I:
409 case OP_ICONV_TO_OVF_U_UN:
411 ins->opcode = OP_MOVE;
414 #if SIZEOF_VOID_P == 8
415 ins->opcode = OP_SEXT_I4;
417 ins->opcode = OP_MOVE;
421 #if SIZEOF_VOID_P == 8
422 ins->opcode = OP_ZEXT_I4;
424 ins->opcode = OP_MOVE;
429 ins->opcode = OP_FMOVE;
432 case OP_FCONV_TO_OVF_I1_UN:
433 case OP_FCONV_TO_OVF_I2_UN:
434 case OP_FCONV_TO_OVF_I4_UN:
435 case OP_FCONV_TO_OVF_I8_UN:
436 case OP_FCONV_TO_OVF_U1_UN:
437 case OP_FCONV_TO_OVF_U2_UN:
438 case OP_FCONV_TO_OVF_U4_UN:
439 case OP_FCONV_TO_OVF_U8_UN:
440 case OP_FCONV_TO_OVF_I_UN:
441 case OP_FCONV_TO_OVF_U_UN:
442 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
449 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
452 if (cfg->backend->need_div_check) {
453 int reg1 = alloc_ireg (cfg);
454 int reg2 = alloc_ireg (cfg);
456 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
457 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
458 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
459 /* b == -1 && a == 0x80000000 */
460 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
461 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
463 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
464 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
465 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
466 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
469 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
474 #if SIZEOF_REGISTER == 8
478 int power = mono_is_power_of_two (ins->inst_imm);
479 if (ins->inst_imm == 1) {
480 ins->opcode = OP_ICONST;
481 MONO_INST_NULLIFY_SREGS (ins);
486 } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
487 gboolean is_long = ins->opcode == OP_LREM_IMM;
488 int compensator_reg = alloc_ireg (cfg);
489 int intermediate_reg;
491 /* Based on gcc code */
493 /* Add compensation for negative numerators */
496 intermediate_reg = compensator_reg;
497 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
499 intermediate_reg = ins->sreg1;
502 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);
503 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
504 /* Compute remainder */
505 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
506 /* Remove compensation */
507 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LSUB : OP_ISUB, ins->dreg, ins->dreg, compensator_reg);
521 #if SIZEOF_REGISTER == 8
522 if (decompose_long_opcode (cfg, ins, &repl))
525 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
529 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
530 cfg->has_emulated_ops = TRUE;
533 if (ins->opcode == OP_NOP) {
538 /* Use the last emitted instruction */
539 ins = cfg->cbb->last_ins;
542 g_assert (ins->dreg == dreg);
550 #if SIZEOF_REGISTER == 4
551 static int lbr_decomp [][2] = {
553 {OP_IBGT, OP_IBGE_UN}, /* BGE */
554 {OP_IBGT, OP_IBGT_UN}, /* BGT */
555 {OP_IBLT, OP_IBLE_UN}, /* BLE */
556 {OP_IBLT, OP_IBLT_UN}, /* BLT */
558 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
559 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
560 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
561 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
564 static int lcset_decomp [][2] = {
566 {OP_IBLT, OP_IBLE_UN}, /* CGT */
567 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
568 {OP_IBGT, OP_IBGE_UN}, /* CLT */
569 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
574 * mono_decompose_long_opts:
576 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
579 mono_decompose_long_opts (MonoCompile *cfg)
581 #if SIZEOF_REGISTER == 4
582 MonoBasicBlock *bb, *first_bb;
585 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
586 * needs to be able to handle long vregs.
590 * Create a dummy bblock and emit code into it so we can use the normal
591 * code generation macros.
593 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
596 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
597 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
598 MonoInst *prev = NULL;
601 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
604 cfg->cbb->code = cfg->cbb->last_ins = NULL;
607 mono_arch_decompose_long_opts (cfg, tree);
609 switch (tree->opcode) {
611 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
612 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
614 case OP_DUMMY_I8CONST:
615 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
616 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
621 case OP_LCONV_TO_OVF_U8_UN:
622 case OP_LCONV_TO_OVF_I8:
623 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
624 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
626 case OP_STOREI8_MEMBASE_REG:
627 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));
628 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));
630 case OP_LOADI8_MEMBASE:
631 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);
632 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);
635 case OP_ICONV_TO_I8: {
636 guint32 tmpreg = alloc_ireg (cfg);
640 * tmp = low > -1 ? 1: 0;
641 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
643 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
644 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
645 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
646 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
650 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
651 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
653 case OP_ICONV_TO_OVF_I8:
654 /* a signed 32 bit num always fits in a signed 64 bit one */
655 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
656 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
658 case OP_ICONV_TO_OVF_U8:
659 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
660 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
661 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
662 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
664 case OP_ICONV_TO_OVF_I8_UN:
665 case OP_ICONV_TO_OVF_U8_UN:
666 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
667 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
668 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
671 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
674 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
677 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
680 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
686 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
688 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
690 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
693 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
695 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
698 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
699 case OP_LCONV_TO_R_UN:
700 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
703 case OP_LCONV_TO_OVF_I1: {
704 MonoBasicBlock *is_negative, *end_label;
706 NEW_BBLOCK (cfg, is_negative);
707 NEW_BBLOCK (cfg, end_label);
709 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
710 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
711 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
712 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
714 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
715 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
718 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
719 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
720 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
723 MONO_START_BB (cfg, is_negative);
724 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
725 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
727 MONO_START_BB (cfg, end_label);
729 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
732 case OP_LCONV_TO_OVF_I1_UN:
733 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
734 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
736 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
737 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
738 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
739 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
740 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
742 case OP_LCONV_TO_OVF_U1:
743 case OP_LCONV_TO_OVF_U1_UN:
744 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
745 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
747 /* probe value to be within 0 to 255 */
748 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
749 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
750 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
752 case OP_LCONV_TO_OVF_I2: {
753 MonoBasicBlock *is_negative, *end_label;
755 NEW_BBLOCK (cfg, is_negative);
756 NEW_BBLOCK (cfg, end_label);
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
759 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
760 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
761 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
763 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
764 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
767 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
768 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
769 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
772 MONO_START_BB (cfg, is_negative);
773 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
774 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
775 MONO_START_BB (cfg, end_label);
777 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
780 case OP_LCONV_TO_OVF_I2_UN:
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
782 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
784 /* Probe value to be within -32768 and 32767 */
785 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
786 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
787 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
788 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
789 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
791 case OP_LCONV_TO_OVF_U2:
792 case OP_LCONV_TO_OVF_U2_UN:
793 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
794 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
796 /* Probe value to be within 0 and 65535 */
797 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
798 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
799 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
801 case OP_LCONV_TO_OVF_I4:
802 case OP_LCONV_TO_OVF_I:
803 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
805 case OP_LCONV_TO_OVF_U4:
806 case OP_LCONV_TO_OVF_U:
807 case OP_LCONV_TO_OVF_U4_UN:
808 case OP_LCONV_TO_OVF_U_UN:
809 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
810 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
811 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
813 case OP_LCONV_TO_OVF_I_UN:
814 case OP_LCONV_TO_OVF_I4_UN:
815 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
816 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
817 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
818 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
819 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
821 case OP_LCONV_TO_OVF_U8:
822 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
823 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
825 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
826 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
828 case OP_LCONV_TO_OVF_I8_UN:
829 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
830 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
832 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
833 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
837 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
838 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
841 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
842 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
846 /* ADC sets the condition code */
847 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
848 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
849 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
852 /* ADC sets the condition code */
853 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
854 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
855 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
858 /* SBB sets the condition code */
859 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
860 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
861 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
864 /* SBB sets the condition code */
865 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
866 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
867 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
870 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
871 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
874 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
875 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
878 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
879 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
882 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
883 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
886 /* Handled in mono_arch_decompose_long_opts () */
887 g_assert_not_reached ();
891 /* FIXME: Add OP_BIGMUL optimization */
895 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
896 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
899 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
900 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
903 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
904 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
907 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
908 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
911 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
912 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
915 if (tree->inst_c1 == 32) {
917 /* The original code had this comment: */
918 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
919 * later apply the speedup to the left shift as well
922 /* FIXME: Move this to the strength reduction pass */
923 /* just move the upper half to the lower and zero the high word */
924 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
925 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
929 if (tree->inst_c1 == 32) {
930 /* just move the lower half to the upper and zero the lower word */
931 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
932 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
937 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
941 switch (next->opcode) {
946 /* Branchless version based on gcc code */
947 d1 = alloc_ireg (cfg);
948 d2 = alloc_ireg (cfg);
949 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
950 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
951 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
952 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
953 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
965 /* Convert into three comparisons + branches */
966 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
967 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
968 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
969 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
970 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
971 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
977 /* Branchless version based on gcc code */
978 d1 = alloc_ireg (cfg);
979 d2 = alloc_ireg (cfg);
980 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
981 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
982 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
984 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
985 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
993 MonoBasicBlock *set_to_0, *set_to_1;
995 NEW_BBLOCK (cfg, set_to_0);
996 NEW_BBLOCK (cfg, set_to_1);
998 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
999 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1000 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1001 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1002 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1003 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1004 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1005 MONO_START_BB (cfg, set_to_1);
1006 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1007 MONO_START_BB (cfg, set_to_0);
1012 g_assert_not_reached ();
1017 /* Not yet used, since lcompare is decomposed before local cprop */
1018 case OP_LCOMPARE_IMM: {
1019 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1020 guint32 low_imm = tree->inst_ls_word;
1021 guint32 high_imm = tree->inst_ms_word;
1022 int low_reg = MONO_LVREG_LS (tree->sreg1);
1023 int high_reg = MONO_LVREG_MS (tree->sreg1);
1027 switch (next->opcode) {
1032 /* Branchless version based on gcc code */
1033 d1 = alloc_ireg (cfg);
1034 d2 = alloc_ireg (cfg);
1035 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1036 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1037 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1038 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1039 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1052 /* Convert into three comparisons + branches */
1053 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1054 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1055 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1056 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1057 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1058 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1064 /* Branchless version based on gcc code */
1065 d1 = alloc_ireg (cfg);
1066 d2 = alloc_ireg (cfg);
1067 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1068 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1069 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1071 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1072 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1080 MonoBasicBlock *set_to_0, *set_to_1;
1082 NEW_BBLOCK (cfg, set_to_0);
1083 NEW_BBLOCK (cfg, set_to_1);
1085 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1086 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1087 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1088 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1089 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1090 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1091 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1092 MONO_START_BB (cfg, set_to_1);
1093 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1094 MONO_START_BB (cfg, set_to_0);
1099 g_assert_not_reached ();
1108 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1111 /* Replace the original instruction with the new code sequence */
1113 /* Ignore the new value of prev */
1115 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1117 /* Process the newly added ops again since they can be long ops too */
1119 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1121 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1123 first_bb->code = first_bb->last_ins = NULL;
1124 first_bb->in_count = first_bb->out_count = 0;
1125 cfg->cbb = first_bb;
1129 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1136 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1137 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1142 * mono_decompose_vtype_opts:
1144 * Decompose valuetype opcodes.
1147 mono_decompose_vtype_opts (MonoCompile *cfg)
1149 MonoBasicBlock *bb, *first_bb;
1152 * Using OP_V opcodes and decomposing them later have two main benefits:
1153 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1155 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1156 * enabling optimizations to work on vtypes too.
1157 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1158 * can be executed anytime. It should be executed as late as possible so vtype
1159 * opcodes can be optimized by the other passes.
1160 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1161 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1163 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1164 * when OP_VMOVE opcodes are decomposed.
1168 * Vregs have no associated type information, so we store the type of the vregs
1173 * Create a dummy bblock and emit code into it so we can use the normal
1174 * code generation macros.
1176 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1177 first_bb = cfg->cbb;
1179 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1181 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1183 MonoInst *prev = NULL;
1184 MonoInst *src_var, *dest_var, *src, *dest;
1188 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1190 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1196 for (ins = bb->code; ins; ins = ins->next) {
1197 switch (ins->opcode) {
1199 g_assert (ins->klass);
1200 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1202 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1203 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1206 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1209 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1212 if (src_var->backend.is_pinvoke)
1213 dest_var->backend.is_pinvoke = 1;
1215 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1216 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1218 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1222 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1225 g_assert (ins->klass);
1227 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1228 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1230 if (cfg->compute_gc_maps) {
1234 * Tell the GC map code that the vtype is considered live after
1235 * the initialization.
1237 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1238 tmp->inst_c1 = ins->dreg;
1239 MONO_ADD_INS (cfg->cbb, tmp);
1242 case OP_DUMMY_VZERO:
1243 if (COMPILE_LLVM (cfg))
1248 case OP_STOREV_MEMBASE: {
1249 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1252 g_assert (ins->klass);
1253 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1256 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1258 dreg = alloc_preg (cfg);
1259 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1260 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1263 case OP_LOADV_MEMBASE: {
1264 g_assert (ins->klass);
1265 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1268 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1272 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1274 dreg = alloc_preg (cfg);
1275 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1276 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1277 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1280 case OP_OUTARG_VT: {
1281 if (COMPILE_LLVM (cfg))
1284 g_assert (ins->klass);
1286 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1288 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1289 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1291 mono_arch_emit_outarg_vt (cfg, ins, src);
1293 /* This might be decomposed into other vtype opcodes */
1297 case OP_OUTARG_VTRETADDR: {
1298 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1300 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1302 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1303 // FIXME: src_var->backend.is_pinvoke ?
1305 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1306 src->dreg = ins->dreg;
1311 case OP_VCALL_MEMBASE: {
1312 MonoCallInst *call = (MonoCallInst*)ins;
1315 if (COMPILE_LLVM (cfg))
1318 if (call->vret_in_reg) {
1319 MonoCallInst *call2;
1321 /* Replace the vcall with a scalar call */
1322 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1323 memcpy (call2, call, sizeof (MonoCallInst));
1324 switch (ins->opcode) {
1326 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1329 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1331 case OP_VCALL_MEMBASE:
1332 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1335 call2->inst.dreg = alloc_preg (cfg);
1336 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1338 /* Compute the vtype location */
1339 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1341 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1342 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1344 /* Save the result */
1345 if (dest_var->backend.is_pinvoke)
1346 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1348 size = mono_type_size (dest_var->inst_vtype, NULL);
1351 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1354 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1358 if (call->vret_in_reg_fp)
1359 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1361 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1367 if (call->vret_in_reg_fp) {
1368 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1371 #if SIZEOF_REGISTER == 4
1373 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1374 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1376 switch (call2->inst.opcode) {
1378 call2->inst.opcode = OP_LCALL;
1381 call2->inst.opcode = OP_LCALL_REG;
1383 case OP_CALL_MEMBASE:
1384 call2->inst.opcode = OP_LCALL_MEMBASE;
1387 call2->inst.dreg = alloc_lreg (cfg);
1388 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1389 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1391 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1395 /* This assumes the vtype is sizeof (gpointer) long */
1396 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1400 switch (ins->opcode) {
1402 ins->opcode = OP_VCALL2;
1405 ins->opcode = OP_VCALL2_REG;
1407 case OP_VCALL_MEMBASE:
1408 ins->opcode = OP_VCALL2_MEMBASE;
1419 g_assert (cfg->cbb == first_bb);
1421 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1422 /* Replace the original instruction with the new code sequence */
1424 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1425 first_bb->code = first_bb->last_ins = NULL;
1426 first_bb->in_count = first_bb->out_count = 0;
1427 cfg->cbb = first_bb;
1434 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1438 inline static MonoInst *
1439 mono_get_domainvar (MonoCompile *cfg)
1441 if (!cfg->domainvar)
1442 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1443 return cfg->domainvar;
1447 * mono_decompose_array_access_opts:
1449 * Decompose array access opcodes.
1452 mono_decompose_array_access_opts (MonoCompile *cfg)
1454 MonoBasicBlock *bb, *first_bb;
1457 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1458 * can be executed anytime. It should be run before decompose_long
1462 * Create a dummy bblock and emit code into it so we can use the normal
1463 * code generation macros.
1465 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1466 first_bb = cfg->cbb;
1468 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1470 MonoInst *prev = NULL;
1472 MonoInst *iargs [3];
1475 if (!bb->has_array_access)
1478 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1480 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1486 for (ins = bb->code; ins; ins = ins->next) {
1487 switch (ins->opcode) {
1489 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1490 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1491 MONO_ADD_INS (cfg->cbb, dest);
1493 case OP_BOUNDS_CHECK:
1494 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1495 if (COMPILE_LLVM (cfg))
1496 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1498 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1501 if (cfg->opt & MONO_OPT_SHARED) {
1502 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1503 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1504 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1505 iargs [2]->dreg = ins->sreg1;
1507 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1508 dest->dreg = ins->dreg;
1510 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1511 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1512 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1514 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1515 NEW_VTABLECONST (cfg, iargs [0], vtable);
1516 MONO_ADD_INS (cfg->cbb, iargs [0]);
1517 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1518 iargs [1]->dreg = ins->sreg1;
1521 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1523 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1524 dest->dreg = ins->dreg;
1528 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1529 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1535 g_assert (cfg->cbb == first_bb);
1537 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1538 /* Replace the original instruction with the new code sequence */
1540 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1541 first_bb->code = first_bb->last_ins = NULL;
1542 first_bb->in_count = first_bb->out_count = 0;
1543 cfg->cbb = first_bb;
1550 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1560 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1563 * mono_decompose_soft_float:
1565 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1566 * similar to long support on 32 bit platforms. 32 bit float values require special
1567 * handling when used as locals, arguments, and in calls.
1568 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1571 mono_decompose_soft_float (MonoCompile *cfg)
1573 MonoBasicBlock *bb, *first_bb;
1576 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1580 * Create a dummy bblock and emit code into it so we can use the normal
1581 * code generation macros.
1583 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1584 first_bb = cfg->cbb;
1586 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1588 MonoInst *prev = NULL;
1591 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1593 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1599 for (ins = bb->code; ins; ins = ins->next) {
1600 const char *spec = INS_INFO (ins->opcode);
1602 /* Most fp operations are handled automatically by opcode emulation */
1604 switch (ins->opcode) {
1607 d.vald = *(double*)ins->inst_p0;
1608 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1613 /* We load the r8 value */
1614 d.vald = *(float*)ins->inst_p0;
1615 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1619 ins->opcode = OP_LMOVE;
1622 ins->opcode = OP_MOVE;
1623 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1626 ins->opcode = OP_MOVE;
1627 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1630 int reg = ins->sreg1;
1632 ins->opcode = OP_SETLRET;
1634 ins->sreg1 = MONO_LVREG_LS (reg);
1635 ins->sreg2 = MONO_LVREG_MS (reg);
1638 case OP_LOADR8_MEMBASE:
1639 ins->opcode = OP_LOADI8_MEMBASE;
1641 case OP_STORER8_MEMBASE_REG:
1642 ins->opcode = OP_STOREI8_MEMBASE_REG;
1644 case OP_STORER4_MEMBASE_REG: {
1645 MonoInst *iargs [2];
1648 /* Arg 1 is the double value */
1649 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1650 iargs [0]->dreg = ins->sreg1;
1652 /* Arg 2 is the address to store to */
1653 addr_reg = mono_alloc_preg (cfg);
1654 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1655 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1659 case OP_LOADR4_MEMBASE: {
1660 MonoInst *iargs [1];
1664 addr_reg = mono_alloc_preg (cfg);
1665 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1666 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1667 conv->dreg = ins->dreg;
1672 case OP_FCALL_MEMBASE: {
1673 MonoCallInst *call = (MonoCallInst*)ins;
1674 if (call->signature->ret->type == MONO_TYPE_R4) {
1675 MonoCallInst *call2;
1676 MonoInst *iargs [1];
1680 /* Convert the call into a call returning an int */
1681 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1682 memcpy (call2, call, sizeof (MonoCallInst));
1683 switch (ins->opcode) {
1685 call2->inst.opcode = OP_CALL;
1688 call2->inst.opcode = OP_CALL_REG;
1690 case OP_FCALL_MEMBASE:
1691 call2->inst.opcode = OP_CALL_MEMBASE;
1694 g_assert_not_reached ();
1696 call2->inst.dreg = mono_alloc_ireg (cfg);
1697 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1699 /* Remap OUTARG_VT instructions referencing this call */
1700 for (l = call->outarg_vts; l; l = l->next)
1701 ((MonoInst*)(l->data))->inst_p0 = call2;
1703 /* FIXME: Optimize this */
1705 /* Emit an r4->r8 conversion */
1706 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1707 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1708 conv->dreg = ins->dreg;
1710 /* The call sequence might include fp ins */
1713 switch (ins->opcode) {
1715 ins->opcode = OP_LCALL;
1718 ins->opcode = OP_LCALL_REG;
1720 case OP_FCALL_MEMBASE:
1721 ins->opcode = OP_LCALL_MEMBASE;
1724 g_assert_not_reached ();
1730 MonoJitICallInfo *info;
1731 MonoInst *iargs [2];
1732 MonoInst *call, *cmp, *br;
1734 /* Convert fcompare+fbcc to icall+icompare+beq */
1737 /* The branch might be optimized away */
1742 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1744 /* The branch might be optimized away */
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_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1758 cmp->sreg1 = call->dreg;
1760 MONO_ADD_INS (cfg->cbb, cmp);
1762 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1763 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1764 br->inst_true_bb = ins->next->inst_true_bb;
1765 br->inst_false_bb = ins->next->inst_false_bb;
1766 MONO_ADD_INS (cfg->cbb, br);
1768 /* The call sequence might include fp ins */
1771 /* Skip fbcc or fccc */
1772 NULLIFY_INS (ins->next);
1780 MonoJitICallInfo *info;
1781 MonoInst *iargs [2];
1784 /* Convert fccc to icall+icompare+iceq */
1786 info = mono_find_jit_opcode_emulation (ins->opcode);
1789 /* Create dummy MonoInst's for the arguments */
1790 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1791 iargs [0]->dreg = ins->sreg1;
1792 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1793 iargs [1]->dreg = ins->sreg2;
1795 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1797 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1798 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1800 /* The call sequence might include fp ins */
1805 MonoInst *iargs [2];
1806 MonoInst *call, *cmp;
1808 /* Convert to icall+icompare+cond_exc+move */
1810 /* Create dummy MonoInst's for the arguments */
1811 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1812 iargs [0]->dreg = ins->sreg1;
1814 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1816 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1817 cmp->sreg1 = call->dreg;
1819 MONO_ADD_INS (cfg->cbb, cmp);
1821 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1823 /* Do the assignment if the value is finite */
1824 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1830 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1831 mono_print_ins (ins);
1832 g_assert_not_reached ();
1837 g_assert (cfg->cbb == first_bb);
1839 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1840 /* Replace the original instruction with the new code sequence */
1842 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1843 first_bb->code = first_bb->last_ins = NULL;
1844 first_bb->in_count = first_bb->out_count = 0;
1845 cfg->cbb = first_bb;
1852 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1855 mono_decompose_long_opts (cfg);
1861 mono_local_emulate_ops (MonoCompile *cfg)
1864 gboolean inlined_wrapper = FALSE;
1866 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1869 MONO_BB_FOR_EACH_INS (bb, ins) {
1870 int op_noimm = mono_op_imm_to_op (ins->opcode);
1871 MonoJitICallInfo *info;
1874 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1875 * to check whether its non-imm counterpart is emulated and, if so,
1876 * decompose it back to its non-imm counterpart.
1879 info = mono_find_jit_opcode_emulation (op_noimm);
1881 info = mono_find_jit_opcode_emulation (ins->opcode);
1886 MonoBasicBlock *first_bb;
1888 /* Create dummy MonoInst's for the arguments */
1889 g_assert (!info->sig->hasthis);
1890 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1893 mono_decompose_op_imm (cfg, bb, ins);
1895 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1896 if (info->sig->param_count > 0) {
1897 int sregs [MONO_MAX_SRC_REGS];
1899 num_sregs = mono_inst_get_src_registers (ins, sregs);
1900 g_assert (num_sregs == info->sig->param_count);
1901 for (i = 0; i < num_sregs; ++i) {
1902 MONO_INST_NEW (cfg, args [i], OP_ARG);
1903 args [i]->dreg = sregs [i];
1907 /* We emit the call on a separate dummy basic block */
1908 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1909 first_bb = cfg->cbb;
1911 call = mono_emit_jit_icall_by_info (cfg, info, args);
1912 call->dreg = ins->dreg;
1914 /* Replace ins with the emitted code and do the necessary bb linking */
1915 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1916 MonoInst *saved_prev = ins->prev;
1918 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1919 first_bb->code = first_bb->last_ins = NULL;
1920 first_bb->in_count = first_bb->out_count = 0;
1921 cfg->cbb = first_bb;
1923 /* ins is hanging, continue scanning the emitted code */
1926 g_error ("Failed to emit emulation code");
1928 inlined_wrapper = TRUE;
1934 * Avoid rerunning these passes by emitting directly the exception checkpoint
1935 * at IR level, instead of inlining the icall wrapper. FIXME
1937 if (inlined_wrapper) {
1938 if (!COMPILE_LLVM (cfg))
1939 mono_decompose_long_opts (cfg);
1940 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1941 mono_local_cprop (cfg);
1945 #endif /* DISABLE_JIT */