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 MonoJitICallInfo *info = NULL;
524 #if SIZEOF_REGISTER == 8
525 if (decompose_long_opcode (cfg, ins, &repl))
528 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
533 info = mono_find_jit_opcode_emulation (ins->opcode);
538 /* Create dummy MonoInst's for the arguments */
539 g_assert (!info->sig->hasthis);
540 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
542 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
543 if (info->sig->param_count > 0) {
544 int sregs [MONO_MAX_SRC_REGS];
546 num_sregs = mono_inst_get_src_registers (ins, sregs);
547 g_assert (num_sregs == info->sig->param_count);
548 for (i = 0; i < num_sregs; ++i) {
549 MONO_INST_NEW (cfg, args [i], OP_ARG);
550 args [i]->dreg = sregs [i];
554 call = mono_emit_jit_icall_by_info (cfg, info, args);
555 call->dreg = ins->dreg;
561 if (ins->opcode == OP_NOP) {
566 /* Use the last emitted instruction */
567 ins = cfg->cbb->last_ins;
570 g_assert (ins->dreg == dreg);
578 #if SIZEOF_REGISTER == 4
579 static int lbr_decomp [][2] = {
581 {OP_IBGT, OP_IBGE_UN}, /* BGE */
582 {OP_IBGT, OP_IBGT_UN}, /* BGT */
583 {OP_IBLT, OP_IBLE_UN}, /* BLE */
584 {OP_IBLT, OP_IBLT_UN}, /* BLT */
586 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
587 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
588 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
589 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
592 static int lcset_decomp [][2] = {
594 {OP_IBLT, OP_IBLE_UN}, /* CGT */
595 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
596 {OP_IBGT, OP_IBGE_UN}, /* CLT */
597 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
602 * mono_decompose_long_opts:
604 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
607 mono_decompose_long_opts (MonoCompile *cfg)
609 #if SIZEOF_REGISTER == 4
610 MonoBasicBlock *bb, *first_bb;
613 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
614 * needs to be able to handle long vregs.
618 * Create a dummy bblock and emit code into it so we can use the normal
619 * code generation macros.
621 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
624 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
625 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
626 MonoInst *prev = NULL;
629 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
632 cfg->cbb->code = cfg->cbb->last_ins = NULL;
635 mono_arch_decompose_long_opts (cfg, tree);
637 switch (tree->opcode) {
639 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
640 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
642 case OP_DUMMY_I8CONST:
643 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
644 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
649 case OP_LCONV_TO_OVF_U8_UN:
650 case OP_LCONV_TO_OVF_I8:
651 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
652 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
654 case OP_STOREI8_MEMBASE_REG:
655 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));
656 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));
658 case OP_LOADI8_MEMBASE:
659 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);
660 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);
663 case OP_ICONV_TO_I8: {
664 guint32 tmpreg = alloc_ireg (cfg);
668 * tmp = low > -1 ? 1: 0;
669 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
671 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
672 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
673 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
674 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
678 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
679 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
681 case OP_ICONV_TO_OVF_I8:
682 /* a signed 32 bit num always fits in a signed 64 bit one */
683 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
684 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
686 case OP_ICONV_TO_OVF_U8:
687 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
688 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
689 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
690 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
692 case OP_ICONV_TO_OVF_I8_UN:
693 case OP_ICONV_TO_OVF_U8_UN:
694 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
695 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
696 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
699 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
702 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
705 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
708 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
714 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
716 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
718 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
721 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
723 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
726 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
727 case OP_LCONV_TO_R_UN:
728 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
731 case OP_LCONV_TO_OVF_I1: {
732 MonoBasicBlock *is_negative, *end_label;
734 NEW_BBLOCK (cfg, is_negative);
735 NEW_BBLOCK (cfg, end_label);
737 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
738 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
739 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
740 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
742 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
743 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
746 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
747 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
748 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
751 MONO_START_BB (cfg, is_negative);
752 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
753 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
755 MONO_START_BB (cfg, end_label);
757 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
760 case OP_LCONV_TO_OVF_I1_UN:
761 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
762 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
764 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
765 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
766 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
767 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
768 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
770 case OP_LCONV_TO_OVF_U1:
771 case OP_LCONV_TO_OVF_U1_UN:
772 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
773 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
775 /* probe value to be within 0 to 255 */
776 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
777 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
778 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
780 case OP_LCONV_TO_OVF_I2: {
781 MonoBasicBlock *is_negative, *end_label;
783 NEW_BBLOCK (cfg, is_negative);
784 NEW_BBLOCK (cfg, end_label);
786 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
787 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
788 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
789 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
791 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
792 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
795 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
796 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
797 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
800 MONO_START_BB (cfg, is_negative);
801 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
802 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
803 MONO_START_BB (cfg, end_label);
805 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
808 case OP_LCONV_TO_OVF_I2_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");
812 /* Probe value to be within -32768 and 32767 */
813 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
814 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
815 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
816 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
817 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
819 case OP_LCONV_TO_OVF_U2:
820 case OP_LCONV_TO_OVF_U2_UN:
821 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
822 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
824 /* Probe value to be within 0 and 65535 */
825 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
826 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
827 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
829 case OP_LCONV_TO_OVF_I4:
830 case OP_LCONV_TO_OVF_I:
831 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
833 case OP_LCONV_TO_OVF_U4:
834 case OP_LCONV_TO_OVF_U:
835 case OP_LCONV_TO_OVF_U4_UN:
836 case OP_LCONV_TO_OVF_U_UN:
837 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
838 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
839 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
841 case OP_LCONV_TO_OVF_I_UN:
842 case OP_LCONV_TO_OVF_I4_UN:
843 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
844 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
845 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
846 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
847 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
849 case OP_LCONV_TO_OVF_U8:
850 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
851 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
853 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
854 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
856 case OP_LCONV_TO_OVF_I8_UN:
857 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
858 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
860 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
861 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
865 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
866 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
869 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
870 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
874 /* ADC sets the condition code */
875 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
876 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
877 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
880 /* ADC sets the condition code */
881 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
882 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
883 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
886 /* SBB sets the condition code */
887 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
888 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
889 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
892 /* SBB sets the condition code */
893 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
894 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
895 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
898 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
899 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
902 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
903 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
906 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
907 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
910 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
911 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
914 /* Handled in mono_arch_decompose_long_opts () */
915 g_assert_not_reached ();
919 /* FIXME: Add OP_BIGMUL optimization */
923 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
932 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
935 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
936 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
939 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
940 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
943 if (tree->inst_c1 == 32) {
945 /* The original code had this comment: */
946 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
947 * later apply the speedup to the left shift as well
950 /* FIXME: Move this to the strength reduction pass */
951 /* just move the upper half to the lower and zero the high word */
952 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
953 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
957 if (tree->inst_c1 == 32) {
958 /* just move the lower half to the upper and zero the lower word */
959 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
960 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
965 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
969 switch (next->opcode) {
974 /* Branchless version based on gcc code */
975 d1 = alloc_ireg (cfg);
976 d2 = alloc_ireg (cfg);
977 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
978 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
979 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
980 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
981 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
993 /* Convert into three comparisons + branches */
994 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
995 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
996 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
997 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
998 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
999 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1005 /* Branchless version based on gcc code */
1006 d1 = alloc_ireg (cfg);
1007 d2 = alloc_ireg (cfg);
1008 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1009 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1010 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1012 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1013 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1021 MonoBasicBlock *set_to_0, *set_to_1;
1023 NEW_BBLOCK (cfg, set_to_0);
1024 NEW_BBLOCK (cfg, set_to_1);
1026 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1027 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1028 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1029 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1030 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1031 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1032 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1033 MONO_START_BB (cfg, set_to_1);
1034 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1035 MONO_START_BB (cfg, set_to_0);
1040 g_assert_not_reached ();
1045 /* Not yet used, since lcompare is decomposed before local cprop */
1046 case OP_LCOMPARE_IMM: {
1047 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1048 guint32 low_imm = tree->inst_ls_word;
1049 guint32 high_imm = tree->inst_ms_word;
1050 int low_reg = MONO_LVREG_LS (tree->sreg1);
1051 int high_reg = MONO_LVREG_MS (tree->sreg1);
1055 switch (next->opcode) {
1060 /* Branchless version based on gcc code */
1061 d1 = alloc_ireg (cfg);
1062 d2 = alloc_ireg (cfg);
1063 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1064 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1065 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1066 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1067 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1080 /* Convert into three comparisons + branches */
1081 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1082 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1083 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1084 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1085 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1086 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1092 /* Branchless version based on gcc code */
1093 d1 = alloc_ireg (cfg);
1094 d2 = alloc_ireg (cfg);
1095 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1096 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1097 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1099 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1100 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1108 MonoBasicBlock *set_to_0, *set_to_1;
1110 NEW_BBLOCK (cfg, set_to_0);
1111 NEW_BBLOCK (cfg, set_to_1);
1113 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1114 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1115 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1116 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1117 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1118 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1119 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1120 MONO_START_BB (cfg, set_to_1);
1121 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1122 MONO_START_BB (cfg, set_to_0);
1127 g_assert_not_reached ();
1136 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1139 /* Replace the original instruction with the new code sequence */
1141 /* Ignore the new value of prev */
1143 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1145 /* Process the newly added ops again since they can be long ops too */
1147 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1149 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1151 first_bb->code = first_bb->last_ins = NULL;
1152 first_bb->in_count = first_bb->out_count = 0;
1153 cfg->cbb = first_bb;
1157 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1164 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1165 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1170 * mono_decompose_vtype_opts:
1172 * Decompose valuetype opcodes.
1175 mono_decompose_vtype_opts (MonoCompile *cfg)
1177 MonoBasicBlock *bb, *first_bb;
1180 * Using OP_V opcodes and decomposing them later have two main benefits:
1181 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1183 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1184 * enabling optimizations to work on vtypes too.
1185 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1186 * can be executed anytime. It should be executed as late as possible so vtype
1187 * opcodes can be optimized by the other passes.
1188 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1189 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1191 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1192 * when OP_VMOVE opcodes are decomposed.
1196 * Vregs have no associated type information, so we store the type of the vregs
1201 * Create a dummy bblock and emit code into it so we can use the normal
1202 * code generation macros.
1204 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1205 first_bb = cfg->cbb;
1207 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1209 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1211 MonoInst *prev = NULL;
1212 MonoInst *src_var, *dest_var, *src, *dest;
1216 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1218 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1224 for (ins = bb->code; ins; ins = ins->next) {
1225 switch (ins->opcode) {
1227 g_assert (ins->klass);
1228 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1230 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1231 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1234 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1237 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1240 if (src_var->backend.is_pinvoke)
1241 dest_var->backend.is_pinvoke = 1;
1243 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1244 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1246 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1250 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1253 g_assert (ins->klass);
1255 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1256 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1258 if (cfg->compute_gc_maps) {
1262 * Tell the GC map code that the vtype is considered live after
1263 * the initialization.
1265 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1266 tmp->inst_c1 = ins->dreg;
1267 MONO_ADD_INS (cfg->cbb, tmp);
1270 case OP_DUMMY_VZERO:
1271 if (COMPILE_LLVM (cfg))
1276 case OP_STOREV_MEMBASE: {
1277 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1280 g_assert (ins->klass);
1281 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1284 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1286 dreg = alloc_preg (cfg);
1287 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1288 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1291 case OP_LOADV_MEMBASE: {
1292 g_assert (ins->klass);
1293 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1296 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1300 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1302 dreg = alloc_preg (cfg);
1303 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1304 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1305 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1308 case OP_OUTARG_VT: {
1309 if (COMPILE_LLVM (cfg))
1312 g_assert (ins->klass);
1314 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1316 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1317 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1319 mono_arch_emit_outarg_vt (cfg, ins, src);
1321 /* This might be decomposed into other vtype opcodes */
1325 case OP_OUTARG_VTRETADDR: {
1326 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1328 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1330 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1331 // FIXME: src_var->backend.is_pinvoke ?
1333 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1334 src->dreg = ins->dreg;
1339 case OP_VCALL_MEMBASE: {
1340 MonoCallInst *call = (MonoCallInst*)ins;
1343 if (COMPILE_LLVM (cfg))
1346 if (call->vret_in_reg) {
1347 MonoCallInst *call2;
1349 /* Replace the vcall with a scalar call */
1350 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1351 memcpy (call2, call, sizeof (MonoCallInst));
1352 switch (ins->opcode) {
1354 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1357 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1359 case OP_VCALL_MEMBASE:
1360 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1363 call2->inst.dreg = alloc_preg (cfg);
1364 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1366 /* Compute the vtype location */
1367 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1369 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1370 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1372 /* Save the result */
1373 if (dest_var->backend.is_pinvoke)
1374 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1376 size = mono_type_size (dest_var->inst_vtype, NULL);
1379 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1382 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1386 if (call->vret_in_reg_fp)
1387 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1389 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1395 if (call->vret_in_reg_fp) {
1396 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1399 #if SIZEOF_REGISTER == 4
1401 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1402 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1404 switch (call2->inst.opcode) {
1406 call2->inst.opcode = OP_LCALL;
1409 call2->inst.opcode = OP_LCALL_REG;
1411 case OP_CALL_MEMBASE:
1412 call2->inst.opcode = OP_LCALL_MEMBASE;
1415 call2->inst.dreg = alloc_lreg (cfg);
1416 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1417 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1419 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1423 /* This assumes the vtype is sizeof (gpointer) long */
1424 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1428 switch (ins->opcode) {
1430 ins->opcode = OP_VCALL2;
1433 ins->opcode = OP_VCALL2_REG;
1435 case OP_VCALL_MEMBASE:
1436 ins->opcode = OP_VCALL2_MEMBASE;
1447 g_assert (cfg->cbb == first_bb);
1449 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1450 /* Replace the original instruction with the new code sequence */
1452 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1453 first_bb->code = first_bb->last_ins = NULL;
1454 first_bb->in_count = first_bb->out_count = 0;
1455 cfg->cbb = first_bb;
1462 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1466 inline static MonoInst *
1467 mono_get_domainvar (MonoCompile *cfg)
1469 if (!cfg->domainvar)
1470 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1471 return cfg->domainvar;
1475 * mono_decompose_array_access_opts:
1477 * Decompose array access opcodes.
1480 mono_decompose_array_access_opts (MonoCompile *cfg)
1482 MonoBasicBlock *bb, *first_bb;
1485 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1486 * can be executed anytime. It should be run before decompose_long
1490 * Create a dummy bblock and emit code into it so we can use the normal
1491 * code generation macros.
1493 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1494 first_bb = cfg->cbb;
1496 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1498 MonoInst *prev = NULL;
1500 MonoInst *iargs [3];
1503 if (!bb->has_array_access)
1506 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1508 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1514 for (ins = bb->code; ins; ins = ins->next) {
1515 switch (ins->opcode) {
1517 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1518 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1519 MONO_ADD_INS (cfg->cbb, dest);
1521 case OP_BOUNDS_CHECK:
1522 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1523 if (COMPILE_LLVM (cfg))
1524 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1526 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1529 if (cfg->opt & MONO_OPT_SHARED) {
1530 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1531 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1532 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1533 iargs [2]->dreg = ins->sreg1;
1535 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1536 dest->dreg = ins->dreg;
1538 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1539 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1540 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1542 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1543 NEW_VTABLECONST (cfg, iargs [0], vtable);
1544 MONO_ADD_INS (cfg->cbb, iargs [0]);
1545 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1546 iargs [1]->dreg = ins->sreg1;
1549 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1551 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1552 dest->dreg = ins->dreg;
1556 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1557 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1563 g_assert (cfg->cbb == first_bb);
1565 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1566 /* Replace the original instruction with the new code sequence */
1568 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1569 first_bb->code = first_bb->last_ins = NULL;
1570 first_bb->in_count = first_bb->out_count = 0;
1571 cfg->cbb = first_bb;
1578 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1588 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1591 * mono_decompose_soft_float:
1593 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1594 * similar to long support on 32 bit platforms. 32 bit float values require special
1595 * handling when used as locals, arguments, and in calls.
1596 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1599 mono_decompose_soft_float (MonoCompile *cfg)
1601 MonoBasicBlock *bb, *first_bb;
1604 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1608 * Create a dummy bblock and emit code into it so we can use the normal
1609 * code generation macros.
1611 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1612 first_bb = cfg->cbb;
1614 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1616 MonoInst *prev = NULL;
1619 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1621 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1627 for (ins = bb->code; ins; ins = ins->next) {
1628 const char *spec = INS_INFO (ins->opcode);
1630 /* Most fp operations are handled automatically by opcode emulation */
1632 switch (ins->opcode) {
1635 d.vald = *(double*)ins->inst_p0;
1636 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1641 /* We load the r8 value */
1642 d.vald = *(float*)ins->inst_p0;
1643 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1647 ins->opcode = OP_LMOVE;
1650 ins->opcode = OP_MOVE;
1651 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1654 ins->opcode = OP_MOVE;
1655 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1658 int reg = ins->sreg1;
1660 ins->opcode = OP_SETLRET;
1662 ins->sreg1 = MONO_LVREG_LS (reg);
1663 ins->sreg2 = MONO_LVREG_MS (reg);
1666 case OP_LOADR8_MEMBASE:
1667 ins->opcode = OP_LOADI8_MEMBASE;
1669 case OP_STORER8_MEMBASE_REG:
1670 ins->opcode = OP_STOREI8_MEMBASE_REG;
1672 case OP_STORER4_MEMBASE_REG: {
1673 MonoInst *iargs [2];
1676 /* Arg 1 is the double value */
1677 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1678 iargs [0]->dreg = ins->sreg1;
1680 /* Arg 2 is the address to store to */
1681 addr_reg = mono_alloc_preg (cfg);
1682 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1683 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1687 case OP_LOADR4_MEMBASE: {
1688 MonoInst *iargs [1];
1692 addr_reg = mono_alloc_preg (cfg);
1693 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1694 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1695 conv->dreg = ins->dreg;
1700 case OP_FCALL_MEMBASE: {
1701 MonoCallInst *call = (MonoCallInst*)ins;
1702 if (call->signature->ret->type == MONO_TYPE_R4) {
1703 MonoCallInst *call2;
1704 MonoInst *iargs [1];
1708 /* Convert the call into a call returning an int */
1709 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1710 memcpy (call2, call, sizeof (MonoCallInst));
1711 switch (ins->opcode) {
1713 call2->inst.opcode = OP_CALL;
1716 call2->inst.opcode = OP_CALL_REG;
1718 case OP_FCALL_MEMBASE:
1719 call2->inst.opcode = OP_CALL_MEMBASE;
1722 g_assert_not_reached ();
1724 call2->inst.dreg = mono_alloc_ireg (cfg);
1725 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1727 /* Remap OUTARG_VT instructions referencing this call */
1728 for (l = call->outarg_vts; l; l = l->next)
1729 ((MonoInst*)(l->data))->inst_p0 = call2;
1731 /* FIXME: Optimize this */
1733 /* Emit an r4->r8 conversion */
1734 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1735 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1736 conv->dreg = ins->dreg;
1738 /* The call sequence might include fp ins */
1741 switch (ins->opcode) {
1743 ins->opcode = OP_LCALL;
1746 ins->opcode = OP_LCALL_REG;
1748 case OP_FCALL_MEMBASE:
1749 ins->opcode = OP_LCALL_MEMBASE;
1752 g_assert_not_reached ();
1758 MonoJitICallInfo *info;
1759 MonoInst *iargs [2];
1760 MonoInst *call, *cmp, *br;
1762 /* Convert fcompare+fbcc to icall+icompare+beq */
1765 /* The branch might be optimized away */
1770 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1772 /* The branch might be optimized away */
1777 /* Create dummy MonoInst's for the arguments */
1778 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1779 iargs [0]->dreg = ins->sreg1;
1780 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1781 iargs [1]->dreg = ins->sreg2;
1783 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1785 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1786 cmp->sreg1 = call->dreg;
1788 MONO_ADD_INS (cfg->cbb, cmp);
1790 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1791 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1792 br->inst_true_bb = ins->next->inst_true_bb;
1793 br->inst_false_bb = ins->next->inst_false_bb;
1794 MONO_ADD_INS (cfg->cbb, br);
1796 /* The call sequence might include fp ins */
1799 /* Skip fbcc or fccc */
1800 NULLIFY_INS (ins->next);
1808 MonoJitICallInfo *info;
1809 MonoInst *iargs [2];
1812 /* Convert fccc to icall+icompare+iceq */
1814 info = mono_find_jit_opcode_emulation (ins->opcode);
1817 /* Create dummy MonoInst's for the arguments */
1818 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1819 iargs [0]->dreg = ins->sreg1;
1820 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1821 iargs [1]->dreg = ins->sreg2;
1823 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1825 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1826 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1828 /* The call sequence might include fp ins */
1833 MonoInst *iargs [2];
1834 MonoInst *call, *cmp;
1836 /* Convert to icall+icompare+cond_exc+move */
1838 /* Create dummy MonoInst's for the arguments */
1839 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1840 iargs [0]->dreg = ins->sreg1;
1842 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1844 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1845 cmp->sreg1 = call->dreg;
1847 MONO_ADD_INS (cfg->cbb, cmp);
1849 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1851 /* Do the assignment if the value is finite */
1852 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1858 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1859 mono_print_ins (ins);
1860 g_assert_not_reached ();
1865 g_assert (cfg->cbb == first_bb);
1867 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1868 /* Replace the original instruction with the new code sequence */
1870 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1871 first_bb->code = first_bb->last_ins = NULL;
1872 first_bb->in_count = first_bb->out_count = 0;
1873 cfg->cbb = first_bb;
1880 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1883 mono_decompose_long_opts (cfg);
1888 #endif /* DISABLE_JIT */