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-internal.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 (MONO_IS_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 (MONO_IS_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 (MONO_IS_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 (MONO_IS_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.");
446 #if defined(MONO_ARCH_EMULATE_DIV)
451 if (!mono_arch_opcode_needs_emulation (cfg, ins->opcode)) {
452 #ifdef MONO_ARCH_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);
477 #if SIZEOF_REGISTER == 8
481 int power = mono_is_power_of_two (ins->inst_imm);
482 if (ins->inst_imm == 1) {
483 ins->opcode = OP_ICONST;
484 MONO_INST_NULLIFY_SREGS (ins);
489 } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
490 gboolean is_long = ins->opcode == OP_LREM_IMM;
491 int compensator_reg = alloc_ireg (cfg);
492 int intermediate_reg;
494 /* Based on gcc code */
496 /* Add compensation for negative numerators */
499 intermediate_reg = compensator_reg;
500 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
502 intermediate_reg = ins->sreg1;
505 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);
506 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
507 /* Compute remainder */
508 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
509 /* Remove compensation */
510 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LSUB : OP_ISUB, ins->dreg, ins->dreg, compensator_reg);
524 MonoJitICallInfo *info = NULL;
526 #if SIZEOF_REGISTER == 8
527 if (decompose_long_opcode (cfg, ins, &repl))
530 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
535 info = mono_find_jit_opcode_emulation (ins->opcode);
540 /* Create dummy MonoInst's for the arguments */
541 g_assert (!info->sig->hasthis);
542 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
544 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
545 if (info->sig->param_count > 0) {
546 int sregs [MONO_MAX_SRC_REGS];
548 num_sregs = mono_inst_get_src_registers (ins, sregs);
549 g_assert (num_sregs == info->sig->param_count);
550 for (i = 0; i < num_sregs; ++i) {
551 MONO_INST_NEW (cfg, args [i], OP_ARG);
552 args [i]->dreg = sregs [i];
556 call = mono_emit_jit_icall_by_info (cfg, info, args);
557 call->dreg = ins->dreg;
563 if (ins->opcode == OP_NOP) {
568 /* Use the last emitted instruction */
569 ins = cfg->cbb->last_ins;
572 g_assert (ins->dreg == dreg);
580 #if SIZEOF_REGISTER == 4
581 static int lbr_decomp [][2] = {
583 {OP_IBGT, OP_IBGE_UN}, /* BGE */
584 {OP_IBGT, OP_IBGT_UN}, /* BGT */
585 {OP_IBLT, OP_IBLE_UN}, /* BLE */
586 {OP_IBLT, OP_IBLT_UN}, /* BLT */
588 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
589 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
590 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
591 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
594 static int lcset_decomp [][2] = {
596 {OP_IBLT, OP_IBLE_UN}, /* CGT */
597 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
598 {OP_IBGT, OP_IBGE_UN}, /* CLT */
599 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
604 * mono_decompose_long_opts:
606 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
609 mono_decompose_long_opts (MonoCompile *cfg)
611 #if SIZEOF_REGISTER == 4
612 MonoBasicBlock *bb, *first_bb;
615 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
616 * needs to be able to handle long vregs.
619 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
622 * Create a dummy bblock and emit code into it so we can use the normal
623 * code generation macros.
625 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
628 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
629 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
630 MonoInst *prev = NULL;
633 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
636 cfg->cbb->code = cfg->cbb->last_ins = NULL;
639 mono_arch_decompose_long_opts (cfg, tree);
641 switch (tree->opcode) {
643 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
644 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
646 case OP_DUMMY_I8CONST:
647 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 1, OP_DUMMY_ICONST);
648 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 2, OP_DUMMY_ICONST);
653 case OP_LCONV_TO_OVF_U8_UN:
654 case OP_LCONV_TO_OVF_I8:
655 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
656 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
658 case OP_STOREI8_MEMBASE_REG:
659 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
660 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
662 case OP_LOADI8_MEMBASE:
663 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
664 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
667 case OP_ICONV_TO_I8: {
668 guint32 tmpreg = alloc_ireg (cfg);
672 * tmp = low > -1 ? 1: 0;
673 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
675 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
676 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
677 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
678 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
682 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
683 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
685 case OP_ICONV_TO_OVF_I8:
686 /* a signed 32 bit num always fits in a signed 64 bit one */
687 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
688 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
690 case OP_ICONV_TO_OVF_U8:
691 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
692 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
693 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
694 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
696 case OP_ICONV_TO_OVF_I8_UN:
697 case OP_ICONV_TO_OVF_U8_UN:
698 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
699 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
700 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
703 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
706 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
709 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
712 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
718 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
721 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
724 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
726 case OP_LCONV_TO_R_UN:
727 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
729 case OP_LCONV_TO_OVF_I1: {
730 MonoBasicBlock *is_negative, *end_label;
732 NEW_BBLOCK (cfg, is_negative);
733 NEW_BBLOCK (cfg, end_label);
735 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
736 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
737 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
738 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
740 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
741 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
744 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
745 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
746 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
749 MONO_START_BB (cfg, is_negative);
750 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
751 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
753 MONO_START_BB (cfg, end_label);
755 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
758 case OP_LCONV_TO_OVF_I1_UN:
759 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
760 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
762 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
763 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
764 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
765 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
766 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
768 case OP_LCONV_TO_OVF_U1:
769 case OP_LCONV_TO_OVF_U1_UN:
770 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
771 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
773 /* probe value to be within 0 to 255 */
774 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
775 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
776 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
778 case OP_LCONV_TO_OVF_I2: {
779 MonoBasicBlock *is_negative, *end_label;
781 NEW_BBLOCK (cfg, is_negative);
782 NEW_BBLOCK (cfg, end_label);
784 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
785 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
786 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
787 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
789 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
790 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
793 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
794 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
795 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
798 MONO_START_BB (cfg, is_negative);
799 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
800 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
801 MONO_START_BB (cfg, end_label);
803 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
806 case OP_LCONV_TO_OVF_I2_UN:
807 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
808 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
810 /* Probe value to be within -32768 and 32767 */
811 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
812 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
813 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
814 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
815 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
817 case OP_LCONV_TO_OVF_U2:
818 case OP_LCONV_TO_OVF_U2_UN:
819 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
820 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
822 /* Probe value to be within 0 and 65535 */
823 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
824 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
825 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
827 case OP_LCONV_TO_OVF_I4:
828 case OP_LCONV_TO_OVF_I:
829 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
831 case OP_LCONV_TO_OVF_U4:
832 case OP_LCONV_TO_OVF_U:
833 case OP_LCONV_TO_OVF_U4_UN:
834 case OP_LCONV_TO_OVF_U_UN:
835 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
836 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
837 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
839 case OP_LCONV_TO_OVF_I_UN:
840 case OP_LCONV_TO_OVF_I4_UN:
841 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
842 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
843 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
844 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
845 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
847 case OP_LCONV_TO_OVF_U8:
848 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
849 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
851 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
852 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
854 case OP_LCONV_TO_OVF_I8_UN:
855 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
856 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
858 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
859 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
863 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
864 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
867 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
868 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
872 /* ADC sets the condition code */
873 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
874 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
875 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
878 /* ADC sets the condition code */
879 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
880 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
881 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
884 /* SBB sets the condition code */
885 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
886 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
887 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
890 /* SBB sets the condition code */
891 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
892 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
893 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
896 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
897 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
900 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
901 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
904 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
905 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
908 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
909 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
912 /* Handled in mono_arch_decompose_long_opts () */
913 g_assert_not_reached ();
917 /* FIXME: Add OP_BIGMUL optimization */
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
922 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
930 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
934 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
937 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
938 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
941 if (tree->inst_c1 == 32) {
943 /* The original code had this comment: */
944 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
945 * later apply the speedup to the left shift as well
948 /* FIXME: Move this to the strength reduction pass */
949 /* just move the upper half to the lower and zero the high word */
950 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
951 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
955 if (tree->inst_c1 == 32) {
956 /* just move the lower half to the upper and zero the lower word */
957 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
958 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
963 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
967 switch (next->opcode) {
972 /* Branchless version based on gcc code */
973 d1 = alloc_ireg (cfg);
974 d2 = alloc_ireg (cfg);
975 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
976 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
977 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
978 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
979 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
991 /* Convert into three comparisons + branches */
992 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
993 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
994 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
995 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
996 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
997 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1003 /* Branchless version based on gcc code */
1004 d1 = alloc_ireg (cfg);
1005 d2 = alloc_ireg (cfg);
1006 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
1007 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
1008 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1010 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1011 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1019 MonoBasicBlock *set_to_0, *set_to_1;
1021 NEW_BBLOCK (cfg, set_to_0);
1022 NEW_BBLOCK (cfg, set_to_1);
1024 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1025 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1026 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1027 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1028 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1029 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
1030 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1031 MONO_START_BB (cfg, set_to_1);
1032 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1033 MONO_START_BB (cfg, set_to_0);
1038 g_assert_not_reached ();
1043 /* Not yet used, since lcompare is decomposed before local cprop */
1044 case OP_LCOMPARE_IMM: {
1045 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1046 guint32 low_imm = tree->inst_ls_word;
1047 guint32 high_imm = tree->inst_ms_word;
1048 int low_reg = tree->sreg1 + 1;
1049 int high_reg = tree->sreg1 + 2;
1053 switch (next->opcode) {
1058 /* Branchless version based on gcc code */
1059 d1 = alloc_ireg (cfg);
1060 d2 = alloc_ireg (cfg);
1061 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1062 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1063 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1064 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1065 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1078 /* Convert into three comparisons + branches */
1079 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1080 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1081 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1082 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1083 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1084 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1090 /* Branchless version based on gcc code */
1091 d1 = alloc_ireg (cfg);
1092 d2 = alloc_ireg (cfg);
1093 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1094 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1095 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1097 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1098 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1106 MonoBasicBlock *set_to_0, *set_to_1;
1108 NEW_BBLOCK (cfg, set_to_0);
1109 NEW_BBLOCK (cfg, set_to_1);
1111 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1112 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1113 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1114 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1115 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1116 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1117 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1118 MONO_START_BB (cfg, set_to_1);
1119 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1120 MONO_START_BB (cfg, set_to_0);
1125 g_assert_not_reached ();
1134 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1137 /* Replace the original instruction with the new code sequence */
1139 /* Ignore the new value of prev */
1141 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1143 /* Process the newly added ops again since they can be long ops too */
1145 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1147 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1149 first_bb->code = first_bb->last_ins = NULL;
1150 first_bb->in_count = first_bb->out_count = 0;
1151 cfg->cbb = first_bb;
1155 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1162 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1163 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1168 * mono_decompose_vtype_opts:
1170 * Decompose valuetype opcodes.
1173 mono_decompose_vtype_opts (MonoCompile *cfg)
1175 MonoBasicBlock *bb, *first_bb;
1178 * Using OP_V opcodes and decomposing them later have two main benefits:
1179 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1181 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1182 * enabling optimizations to work on vtypes too.
1183 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1184 * can be executed anytime. It should be executed as late as possible so vtype
1185 * opcodes can be optimized by the other passes.
1186 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1187 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1189 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1190 * when OP_VMOVE opcodes are decomposed.
1194 * Vregs have no associated type information, so we store the type of the vregs
1199 * Create a dummy bblock and emit code into it so we can use the normal
1200 * code generation macros.
1202 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1203 first_bb = cfg->cbb;
1205 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1207 MonoInst *prev = NULL;
1208 MonoInst *src_var, *dest_var, *src, *dest;
1212 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1214 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1220 for (ins = bb->code; ins; ins = ins->next) {
1221 switch (ins->opcode) {
1223 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1224 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1226 g_assert (ins->klass);
1229 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1232 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1235 if (src_var->backend.is_pinvoke)
1236 dest_var->backend.is_pinvoke = 1;
1238 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1239 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1241 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1245 g_assert (ins->klass);
1247 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1248 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1250 if (cfg->compute_gc_maps) {
1254 * Tell the GC map code that the vtype is considered live after
1255 * the initialization.
1257 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1258 tmp->inst_c1 = ins->dreg;
1259 MONO_ADD_INS (cfg->cbb, tmp);
1262 case OP_DUMMY_VZERO:
1265 case OP_STOREV_MEMBASE: {
1266 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1269 g_assert (ins->klass);
1270 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1273 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1275 dreg = alloc_preg (cfg);
1276 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1277 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1280 case OP_LOADV_MEMBASE: {
1281 g_assert (ins->klass);
1283 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1287 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1289 dreg = alloc_preg (cfg);
1290 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1291 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1292 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1295 case OP_OUTARG_VT: {
1296 g_assert (ins->klass);
1298 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1300 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1301 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1303 mono_arch_emit_outarg_vt (cfg, ins, src);
1305 /* This might be decomposed into other vtype opcodes */
1309 case OP_OUTARG_VTRETADDR: {
1310 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1312 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1314 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1315 // FIXME: src_var->backend.is_pinvoke ?
1317 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1318 src->dreg = ins->dreg;
1323 case OP_VCALL_MEMBASE: {
1324 MonoCallInst *call = (MonoCallInst*)ins;
1327 if (call->vret_in_reg) {
1328 MonoCallInst *call2;
1330 /* Replace the vcall with a scalar call */
1331 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1332 memcpy (call2, call, sizeof (MonoCallInst));
1333 switch (ins->opcode) {
1335 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1338 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1340 case OP_VCALL_MEMBASE:
1341 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1344 call2->inst.dreg = alloc_preg (cfg);
1345 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1347 /* Compute the vtype location */
1348 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1350 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1351 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1353 /* Save the result */
1354 if (dest_var->backend.is_pinvoke)
1355 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1357 size = mono_type_size (dest_var->inst_vtype, NULL);
1360 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1363 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1367 if (call->vret_in_reg_fp)
1368 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1370 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1376 if (call->vret_in_reg_fp) {
1377 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1380 #if SIZEOF_REGISTER == 4
1382 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1383 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1385 switch (call2->inst.opcode) {
1387 call2->inst.opcode = OP_LCALL;
1390 call2->inst.opcode = OP_LCALL_REG;
1392 case OP_CALL_MEMBASE:
1393 call2->inst.opcode = OP_LCALL_MEMBASE;
1396 call2->inst.dreg = alloc_lreg (cfg);
1397 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1398 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1400 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1404 /* This assumes the vtype is sizeof (gpointer) long */
1405 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1409 switch (ins->opcode) {
1411 ins->opcode = OP_VCALL2;
1414 ins->opcode = OP_VCALL2_REG;
1416 case OP_VCALL_MEMBASE:
1417 ins->opcode = OP_VCALL2_MEMBASE;
1428 g_assert (cfg->cbb == first_bb);
1430 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1431 /* Replace the original instruction with the new code sequence */
1433 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1434 first_bb->code = first_bb->last_ins = NULL;
1435 first_bb->in_count = first_bb->out_count = 0;
1436 cfg->cbb = first_bb;
1443 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1448 mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
1450 MonoBasicBlock *bb, *first_bb;
1452 /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
1454 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1455 first_bb = cfg->cbb;
1457 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1459 MonoInst *prev = NULL;
1460 MonoInst *src_var, *src, *dest;
1464 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
1466 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1472 for (ins = bb->code; ins; ins = ins->next) {
1473 switch (ins->opcode) {
1474 case OP_STOREV_MEMBASE: {
1475 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1478 g_assert (ins->klass);
1479 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1482 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1484 dreg = alloc_preg (cfg);
1485 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1486 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1493 g_assert (cfg->cbb == first_bb);
1495 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1496 /* Replace the original instruction with the new code sequence */
1498 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1499 first_bb->code = first_bb->last_ins = NULL;
1500 first_bb->in_count = first_bb->out_count = 0;
1501 cfg->cbb = first_bb;
1508 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
1512 inline static MonoInst *
1513 mono_get_domainvar (MonoCompile *cfg)
1515 if (!cfg->domainvar)
1516 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1517 return cfg->domainvar;
1521 * mono_decompose_array_access_opts:
1523 * Decompose array access opcodes.
1526 mono_decompose_array_access_opts (MonoCompile *cfg)
1528 MonoBasicBlock *bb, *first_bb;
1531 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1532 * can be executed anytime. It should be run before decompose_long
1536 * Create a dummy bblock and emit code into it so we can use the normal
1537 * code generation macros.
1539 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1540 first_bb = cfg->cbb;
1542 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1544 MonoInst *prev = NULL;
1546 MonoInst *iargs [3];
1549 if (!bb->has_array_access)
1552 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1554 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1560 for (ins = bb->code; ins; ins = ins->next) {
1561 switch (ins->opcode) {
1563 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1564 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1565 MONO_ADD_INS (cfg->cbb, dest);
1567 case OP_BOUNDS_CHECK:
1568 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1569 if (COMPILE_LLVM (cfg))
1570 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1572 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1575 if (cfg->opt & MONO_OPT_SHARED) {
1576 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1577 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1578 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1579 iargs [2]->dreg = ins->sreg1;
1581 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1582 dest->dreg = ins->dreg;
1584 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1585 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1586 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1588 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1589 NEW_VTABLECONST (cfg, iargs [0], vtable);
1590 MONO_ADD_INS (cfg->cbb, iargs [0]);
1591 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1592 iargs [1]->dreg = ins->sreg1;
1595 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1597 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1598 dest->dreg = ins->dreg;
1602 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1603 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1609 g_assert (cfg->cbb == first_bb);
1611 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1612 /* Replace the original instruction with the new code sequence */
1614 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1615 first_bb->code = first_bb->last_ins = NULL;
1616 first_bb->in_count = first_bb->out_count = 0;
1617 cfg->cbb = first_bb;
1624 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1634 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1637 * mono_decompose_soft_float:
1639 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1640 * similar to long support on 32 bit platforms. 32 bit float values require special
1641 * handling when used as locals, arguments, and in calls.
1642 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1645 mono_decompose_soft_float (MonoCompile *cfg)
1647 MonoBasicBlock *bb, *first_bb;
1650 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1654 * Create a dummy bblock and emit code into it so we can use the normal
1655 * code generation macros.
1657 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1658 first_bb = cfg->cbb;
1660 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1662 MonoInst *prev = NULL;
1665 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1667 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1673 for (ins = bb->code; ins; ins = ins->next) {
1674 const char *spec = INS_INFO (ins->opcode);
1676 /* Most fp operations are handled automatically by opcode emulation */
1678 switch (ins->opcode) {
1681 d.vald = *(double*)ins->inst_p0;
1682 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1687 /* We load the r8 value */
1688 d.vald = *(float*)ins->inst_p0;
1689 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1693 ins->opcode = OP_LMOVE;
1696 ins->opcode = OP_MOVE;
1697 ins->sreg1 = ins->sreg1 + 1;
1700 ins->opcode = OP_MOVE;
1701 ins->sreg1 = ins->sreg1 + 2;
1704 int reg = ins->sreg1;
1706 ins->opcode = OP_SETLRET;
1708 ins->sreg1 = reg + 1;
1709 ins->sreg2 = reg + 2;
1712 case OP_LOADR8_MEMBASE:
1713 ins->opcode = OP_LOADI8_MEMBASE;
1715 case OP_STORER8_MEMBASE_REG:
1716 ins->opcode = OP_STOREI8_MEMBASE_REG;
1718 case OP_STORER4_MEMBASE_REG: {
1719 MonoInst *iargs [2];
1722 /* Arg 1 is the double value */
1723 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1724 iargs [0]->dreg = ins->sreg1;
1726 /* Arg 2 is the address to store to */
1727 addr_reg = mono_alloc_preg (cfg);
1728 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1729 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1733 case OP_LOADR4_MEMBASE: {
1734 MonoInst *iargs [1];
1738 addr_reg = mono_alloc_preg (cfg);
1739 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1740 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1741 conv->dreg = ins->dreg;
1746 case OP_FCALL_MEMBASE: {
1747 MonoCallInst *call = (MonoCallInst*)ins;
1748 if (call->signature->ret->type == MONO_TYPE_R4) {
1749 MonoCallInst *call2;
1750 MonoInst *iargs [1];
1754 /* Convert the call into a call returning an int */
1755 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1756 memcpy (call2, call, sizeof (MonoCallInst));
1757 switch (ins->opcode) {
1759 call2->inst.opcode = OP_CALL;
1762 call2->inst.opcode = OP_CALL_REG;
1764 case OP_FCALL_MEMBASE:
1765 call2->inst.opcode = OP_CALL_MEMBASE;
1768 g_assert_not_reached ();
1770 call2->inst.dreg = mono_alloc_ireg (cfg);
1771 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1773 /* Remap OUTARG_VT instructions referencing this call */
1774 for (l = call->outarg_vts; l; l = l->next)
1775 ((MonoInst*)(l->data))->inst_p0 = call2;
1777 /* FIXME: Optimize this */
1779 /* Emit an r4->r8 conversion */
1780 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1781 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1782 conv->dreg = ins->dreg;
1784 /* The call sequence might include fp ins */
1787 switch (ins->opcode) {
1789 ins->opcode = OP_LCALL;
1792 ins->opcode = OP_LCALL_REG;
1794 case OP_FCALL_MEMBASE:
1795 ins->opcode = OP_LCALL_MEMBASE;
1798 g_assert_not_reached ();
1804 MonoJitICallInfo *info;
1805 MonoInst *iargs [2];
1806 MonoInst *call, *cmp, *br;
1808 /* Convert fcompare+fbcc to icall+icompare+beq */
1811 /* The branch might be optimized away */
1816 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1818 /* The branch might be optimized away */
1823 /* Create dummy MonoInst's for the arguments */
1824 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1825 iargs [0]->dreg = ins->sreg1;
1826 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1827 iargs [1]->dreg = ins->sreg2;
1829 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1831 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1832 cmp->sreg1 = call->dreg;
1834 MONO_ADD_INS (cfg->cbb, cmp);
1836 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1837 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1838 br->inst_true_bb = ins->next->inst_true_bb;
1839 br->inst_false_bb = ins->next->inst_false_bb;
1840 MONO_ADD_INS (cfg->cbb, br);
1842 /* The call sequence might include fp ins */
1845 /* Skip fbcc or fccc */
1846 NULLIFY_INS (ins->next);
1854 MonoJitICallInfo *info;
1855 MonoInst *iargs [2];
1858 /* Convert fccc to icall+icompare+iceq */
1860 info = mono_find_jit_opcode_emulation (ins->opcode);
1863 /* Create dummy MonoInst's for the arguments */
1864 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1865 iargs [0]->dreg = ins->sreg1;
1866 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1867 iargs [1]->dreg = ins->sreg2;
1869 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1871 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1872 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1874 /* The call sequence might include fp ins */
1879 MonoInst *iargs [2];
1880 MonoInst *call, *cmp;
1882 /* Convert to icall+icompare+cond_exc+move */
1884 /* Create dummy MonoInst's for the arguments */
1885 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1886 iargs [0]->dreg = ins->sreg1;
1888 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1890 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1891 cmp->sreg1 = call->dreg;
1893 MONO_ADD_INS (cfg->cbb, cmp);
1895 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1897 /* Do the assignment if the value is finite */
1898 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1904 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1905 mono_print_ins (ins);
1906 g_assert_not_reached ();
1911 g_assert (cfg->cbb == first_bb);
1913 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1914 /* Replace the original instruction with the new code sequence */
1916 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1917 first_bb->code = first_bb->last_ins = NULL;
1918 first_bb->in_count = first_bb->out_count = 0;
1919 cfg->cbb = first_bb;
1926 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1929 mono_decompose_long_opts (cfg);
1934 #endif /* DISABLE_JIT */