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 = 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.
617 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
620 * Create a dummy bblock and emit code into it so we can use the normal
621 * code generation macros.
623 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
626 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
627 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
628 MonoInst *prev = NULL;
631 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
634 cfg->cbb->code = cfg->cbb->last_ins = NULL;
637 mono_arch_decompose_long_opts (cfg, tree);
639 switch (tree->opcode) {
641 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
642 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
644 case OP_DUMMY_I8CONST:
645 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 1, OP_DUMMY_ICONST);
646 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 2, OP_DUMMY_ICONST);
651 case OP_LCONV_TO_OVF_U8_UN:
652 case OP_LCONV_TO_OVF_I8:
653 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
654 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
656 case OP_STOREI8_MEMBASE_REG:
657 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
658 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
660 case OP_LOADI8_MEMBASE:
661 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
662 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
665 case OP_ICONV_TO_I8: {
666 guint32 tmpreg = alloc_ireg (cfg);
670 * tmp = low > -1 ? 1: 0;
671 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
673 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
674 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
675 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
676 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
680 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
681 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
683 case OP_ICONV_TO_OVF_I8:
684 /* a signed 32 bit num always fits in a signed 64 bit one */
685 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
686 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
688 case OP_ICONV_TO_OVF_U8:
689 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
690 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
691 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
692 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
694 case OP_ICONV_TO_OVF_I8_UN:
695 case OP_ICONV_TO_OVF_U8_UN:
696 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
697 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
698 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
701 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
704 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
707 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
710 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
716 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
719 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
722 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
724 case OP_LCONV_TO_R_UN:
725 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
727 case OP_LCONV_TO_OVF_I1: {
728 MonoBasicBlock *is_negative, *end_label;
730 NEW_BBLOCK (cfg, is_negative);
731 NEW_BBLOCK (cfg, end_label);
733 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
734 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
735 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
736 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
738 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
739 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
742 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
743 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
744 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
747 MONO_START_BB (cfg, is_negative);
748 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
749 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
751 MONO_START_BB (cfg, end_label);
753 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
756 case OP_LCONV_TO_OVF_I1_UN:
757 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
758 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
760 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
761 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
762 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
763 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
764 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
766 case OP_LCONV_TO_OVF_U1:
767 case OP_LCONV_TO_OVF_U1_UN:
768 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
769 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
771 /* probe value to be within 0 to 255 */
772 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
773 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
774 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
776 case OP_LCONV_TO_OVF_I2: {
777 MonoBasicBlock *is_negative, *end_label;
779 NEW_BBLOCK (cfg, is_negative);
780 NEW_BBLOCK (cfg, end_label);
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
783 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
784 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
785 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
787 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
788 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
791 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
792 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
793 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
796 MONO_START_BB (cfg, is_negative);
797 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
798 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
799 MONO_START_BB (cfg, end_label);
801 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
804 case OP_LCONV_TO_OVF_I2_UN:
805 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
806 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
808 /* Probe value to be within -32768 and 32767 */
809 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
810 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
811 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
812 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
813 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
815 case OP_LCONV_TO_OVF_U2:
816 case OP_LCONV_TO_OVF_U2_UN:
817 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
818 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
820 /* Probe value to be within 0 and 65535 */
821 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
822 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
823 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
825 case OP_LCONV_TO_OVF_I4:
826 case OP_LCONV_TO_OVF_I:
827 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
829 case OP_LCONV_TO_OVF_U4:
830 case OP_LCONV_TO_OVF_U:
831 case OP_LCONV_TO_OVF_U4_UN:
832 case OP_LCONV_TO_OVF_U_UN:
833 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
834 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
835 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
837 case OP_LCONV_TO_OVF_I_UN:
838 case OP_LCONV_TO_OVF_I4_UN:
839 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
840 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
841 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
842 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
843 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
845 case OP_LCONV_TO_OVF_U8:
846 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
847 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
849 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
850 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
852 case OP_LCONV_TO_OVF_I8_UN:
853 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
854 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
856 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
857 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
861 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
862 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
865 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
866 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
870 /* ADC sets the condition code */
871 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
872 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
873 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
876 /* ADC sets the condition code */
877 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
878 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
879 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
882 /* SBB sets the condition code */
883 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
884 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
885 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
888 /* SBB sets the condition code */
889 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
890 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
891 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
894 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
895 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
898 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
899 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
902 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
903 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
906 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
907 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
910 /* Handled in mono_arch_decompose_long_opts () */
911 g_assert_not_reached ();
915 /* FIXME: Add OP_BIGMUL optimization */
919 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
920 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
923 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
932 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
935 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
936 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
939 if (tree->inst_c1 == 32) {
941 /* The original code had this comment: */
942 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
943 * later apply the speedup to the left shift as well
946 /* FIXME: Move this to the strength reduction pass */
947 /* just move the upper half to the lower and zero the high word */
948 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
949 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
953 if (tree->inst_c1 == 32) {
954 /* just move the lower half to the upper and zero the lower word */
955 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
956 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
961 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
965 switch (next->opcode) {
970 /* Branchless version based on gcc code */
971 d1 = alloc_ireg (cfg);
972 d2 = alloc_ireg (cfg);
973 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
974 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
975 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
976 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
977 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
989 /* Convert into three comparisons + branches */
990 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
991 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
992 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
993 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
994 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
995 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1001 /* Branchless version based on gcc code */
1002 d1 = alloc_ireg (cfg);
1003 d2 = alloc_ireg (cfg);
1004 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
1005 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
1006 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1008 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1009 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1017 MonoBasicBlock *set_to_0, *set_to_1;
1019 NEW_BBLOCK (cfg, set_to_0);
1020 NEW_BBLOCK (cfg, set_to_1);
1022 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1023 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1024 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1025 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1026 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1027 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
1028 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1029 MONO_START_BB (cfg, set_to_1);
1030 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1031 MONO_START_BB (cfg, set_to_0);
1036 g_assert_not_reached ();
1041 /* Not yet used, since lcompare is decomposed before local cprop */
1042 case OP_LCOMPARE_IMM: {
1043 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1044 guint32 low_imm = tree->inst_ls_word;
1045 guint32 high_imm = tree->inst_ms_word;
1046 int low_reg = tree->sreg1 + 1;
1047 int high_reg = tree->sreg1 + 2;
1051 switch (next->opcode) {
1056 /* Branchless version based on gcc code */
1057 d1 = alloc_ireg (cfg);
1058 d2 = alloc_ireg (cfg);
1059 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1060 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1061 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1062 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1063 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1076 /* Convert into three comparisons + branches */
1077 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1078 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1079 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1080 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1081 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1082 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1088 /* Branchless version based on gcc code */
1089 d1 = alloc_ireg (cfg);
1090 d2 = alloc_ireg (cfg);
1091 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1092 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1093 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1095 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1096 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1104 MonoBasicBlock *set_to_0, *set_to_1;
1106 NEW_BBLOCK (cfg, set_to_0);
1107 NEW_BBLOCK (cfg, set_to_1);
1109 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1110 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1111 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1112 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1113 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1114 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1115 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1116 MONO_START_BB (cfg, set_to_1);
1117 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1118 MONO_START_BB (cfg, set_to_0);
1123 g_assert_not_reached ();
1132 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1135 /* Replace the original instruction with the new code sequence */
1137 /* Ignore the new value of prev */
1139 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1141 /* Process the newly added ops again since they can be long ops too */
1143 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1145 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1147 first_bb->code = first_bb->last_ins = NULL;
1148 first_bb->in_count = first_bb->out_count = 0;
1149 cfg->cbb = first_bb;
1153 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1160 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1161 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1166 * mono_decompose_vtype_opts:
1168 * Decompose valuetype opcodes.
1171 mono_decompose_vtype_opts (MonoCompile *cfg)
1173 MonoBasicBlock *bb, *first_bb;
1176 * Using OP_V opcodes and decomposing them later have two main benefits:
1177 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1179 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1180 * enabling optimizations to work on vtypes too.
1181 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1182 * can be executed anytime. It should be executed as late as possible so vtype
1183 * opcodes can be optimized by the other passes.
1184 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1185 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1187 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1188 * when OP_VMOVE opcodes are decomposed.
1192 * Vregs have no associated type information, so we store the type of the vregs
1197 * Create a dummy bblock and emit code into it so we can use the normal
1198 * code generation macros.
1200 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1201 first_bb = cfg->cbb;
1203 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1205 MonoInst *prev = NULL;
1206 MonoInst *src_var, *dest_var, *src, *dest;
1210 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1212 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1218 for (ins = bb->code; ins; ins = ins->next) {
1219 switch (ins->opcode) {
1221 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1222 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1224 g_assert (ins->klass);
1227 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1230 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1233 if (src_var->backend.is_pinvoke)
1234 dest_var->backend.is_pinvoke = 1;
1236 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1237 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1239 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1243 g_assert (ins->klass);
1245 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1246 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1248 if (cfg->compute_gc_maps) {
1252 * Tell the GC map code that the vtype is considered live after
1253 * the initialization.
1255 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1256 tmp->inst_c1 = ins->dreg;
1257 MONO_ADD_INS (cfg->cbb, tmp);
1260 case OP_DUMMY_VZERO:
1263 case OP_STOREV_MEMBASE: {
1264 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1267 g_assert (ins->klass);
1268 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1271 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1273 dreg = alloc_preg (cfg);
1274 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1275 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1278 case OP_LOADV_MEMBASE: {
1279 g_assert (ins->klass);
1281 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1285 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1287 dreg = alloc_preg (cfg);
1288 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1289 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1290 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1293 case OP_OUTARG_VT: {
1294 g_assert (ins->klass);
1296 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1298 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1299 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1301 mono_arch_emit_outarg_vt (cfg, ins, src);
1303 /* This might be decomposed into other vtype opcodes */
1307 case OP_OUTARG_VTRETADDR: {
1308 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1310 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1312 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1313 // FIXME: src_var->backend.is_pinvoke ?
1315 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1316 src->dreg = ins->dreg;
1321 case OP_VCALL_MEMBASE: {
1322 MonoCallInst *call = (MonoCallInst*)ins;
1325 if (call->vret_in_reg) {
1326 MonoCallInst *call2;
1328 /* Replace the vcall with a scalar call */
1329 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1330 memcpy (call2, call, sizeof (MonoCallInst));
1331 switch (ins->opcode) {
1333 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1336 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1338 case OP_VCALL_MEMBASE:
1339 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1342 call2->inst.dreg = alloc_preg (cfg);
1343 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1345 /* Compute the vtype location */
1346 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1348 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1349 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1351 /* Save the result */
1352 if (dest_var->backend.is_pinvoke)
1353 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1355 size = mono_type_size (dest_var->inst_vtype, NULL);
1358 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1361 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1365 if (call->vret_in_reg_fp)
1366 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1368 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1374 if (call->vret_in_reg_fp) {
1375 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1378 #if SIZEOF_REGISTER == 4
1380 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1381 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1383 switch (call2->inst.opcode) {
1385 call2->inst.opcode = OP_LCALL;
1388 call2->inst.opcode = OP_LCALL_REG;
1390 case OP_CALL_MEMBASE:
1391 call2->inst.opcode = OP_LCALL_MEMBASE;
1394 call2->inst.dreg = alloc_lreg (cfg);
1395 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1396 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1398 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1402 /* This assumes the vtype is sizeof (gpointer) long */
1403 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1407 switch (ins->opcode) {
1409 ins->opcode = OP_VCALL2;
1412 ins->opcode = OP_VCALL2_REG;
1414 case OP_VCALL_MEMBASE:
1415 ins->opcode = OP_VCALL2_MEMBASE;
1426 g_assert (cfg->cbb == first_bb);
1428 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1429 /* Replace the original instruction with the new code sequence */
1431 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1432 first_bb->code = first_bb->last_ins = NULL;
1433 first_bb->in_count = first_bb->out_count = 0;
1434 cfg->cbb = first_bb;
1441 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1446 mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
1448 MonoBasicBlock *bb, *first_bb;
1450 /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
1452 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1453 first_bb = cfg->cbb;
1455 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1457 MonoInst *prev = NULL;
1458 MonoInst *src_var, *src, *dest;
1462 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
1464 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1470 for (ins = bb->code; ins; ins = ins->next) {
1471 switch (ins->opcode) {
1472 case OP_STOREV_MEMBASE: {
1473 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1476 g_assert (ins->klass);
1477 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1480 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1482 dreg = alloc_preg (cfg);
1483 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1484 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1491 g_assert (cfg->cbb == first_bb);
1493 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1494 /* Replace the original instruction with the new code sequence */
1496 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1497 first_bb->code = first_bb->last_ins = NULL;
1498 first_bb->in_count = first_bb->out_count = 0;
1499 cfg->cbb = first_bb;
1506 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
1510 inline static MonoInst *
1511 mono_get_domainvar (MonoCompile *cfg)
1513 if (!cfg->domainvar)
1514 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1515 return cfg->domainvar;
1519 * mono_decompose_array_access_opts:
1521 * Decompose array access opcodes.
1524 mono_decompose_array_access_opts (MonoCompile *cfg)
1526 MonoBasicBlock *bb, *first_bb;
1529 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1530 * can be executed anytime. It should be run before decompose_long
1534 * Create a dummy bblock and emit code into it so we can use the normal
1535 * code generation macros.
1537 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1538 first_bb = cfg->cbb;
1540 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1542 MonoInst *prev = NULL;
1544 MonoInst *iargs [3];
1547 if (!bb->has_array_access)
1550 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1552 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1558 for (ins = bb->code; ins; ins = ins->next) {
1559 switch (ins->opcode) {
1561 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1562 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1563 MONO_ADD_INS (cfg->cbb, dest);
1565 case OP_BOUNDS_CHECK:
1566 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1567 if (COMPILE_LLVM (cfg))
1568 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1570 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1573 if (cfg->opt & MONO_OPT_SHARED) {
1574 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1575 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1576 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1577 iargs [2]->dreg = ins->sreg1;
1579 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1580 dest->dreg = ins->dreg;
1582 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1583 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1584 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1586 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1587 NEW_VTABLECONST (cfg, iargs [0], vtable);
1588 MONO_ADD_INS (cfg->cbb, iargs [0]);
1589 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1590 iargs [1]->dreg = ins->sreg1;
1593 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1595 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1596 dest->dreg = ins->dreg;
1600 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1601 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1607 g_assert (cfg->cbb == first_bb);
1609 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1610 /* Replace the original instruction with the new code sequence */
1612 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1613 first_bb->code = first_bb->last_ins = NULL;
1614 first_bb->in_count = first_bb->out_count = 0;
1615 cfg->cbb = first_bb;
1622 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1632 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1635 * mono_decompose_soft_float:
1637 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1638 * similar to long support on 32 bit platforms. 32 bit float values require special
1639 * handling when used as locals, arguments, and in calls.
1640 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1643 mono_decompose_soft_float (MonoCompile *cfg)
1645 MonoBasicBlock *bb, *first_bb;
1648 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1652 * Create a dummy bblock and emit code into it so we can use the normal
1653 * code generation macros.
1655 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1656 first_bb = cfg->cbb;
1658 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1660 MonoInst *prev = NULL;
1663 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1665 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1671 for (ins = bb->code; ins; ins = ins->next) {
1672 const char *spec = INS_INFO (ins->opcode);
1674 /* Most fp operations are handled automatically by opcode emulation */
1676 switch (ins->opcode) {
1679 d.vald = *(double*)ins->inst_p0;
1680 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1685 /* We load the r8 value */
1686 d.vald = *(float*)ins->inst_p0;
1687 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1691 ins->opcode = OP_LMOVE;
1694 ins->opcode = OP_MOVE;
1695 ins->sreg1 = ins->sreg1 + 1;
1698 ins->opcode = OP_MOVE;
1699 ins->sreg1 = ins->sreg1 + 2;
1702 int reg = ins->sreg1;
1704 ins->opcode = OP_SETLRET;
1706 ins->sreg1 = reg + 1;
1707 ins->sreg2 = reg + 2;
1710 case OP_LOADR8_MEMBASE:
1711 ins->opcode = OP_LOADI8_MEMBASE;
1713 case OP_STORER8_MEMBASE_REG:
1714 ins->opcode = OP_STOREI8_MEMBASE_REG;
1716 case OP_STORER4_MEMBASE_REG: {
1717 MonoInst *iargs [2];
1720 /* Arg 1 is the double value */
1721 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1722 iargs [0]->dreg = ins->sreg1;
1724 /* Arg 2 is the address to store to */
1725 addr_reg = mono_alloc_preg (cfg);
1726 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1727 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1731 case OP_LOADR4_MEMBASE: {
1732 MonoInst *iargs [1];
1736 addr_reg = mono_alloc_preg (cfg);
1737 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1738 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1739 conv->dreg = ins->dreg;
1744 case OP_FCALL_MEMBASE: {
1745 MonoCallInst *call = (MonoCallInst*)ins;
1746 if (call->signature->ret->type == MONO_TYPE_R4) {
1747 MonoCallInst *call2;
1748 MonoInst *iargs [1];
1752 /* Convert the call into a call returning an int */
1753 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1754 memcpy (call2, call, sizeof (MonoCallInst));
1755 switch (ins->opcode) {
1757 call2->inst.opcode = OP_CALL;
1760 call2->inst.opcode = OP_CALL_REG;
1762 case OP_FCALL_MEMBASE:
1763 call2->inst.opcode = OP_CALL_MEMBASE;
1766 g_assert_not_reached ();
1768 call2->inst.dreg = mono_alloc_ireg (cfg);
1769 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1771 /* Remap OUTARG_VT instructions referencing this call */
1772 for (l = call->outarg_vts; l; l = l->next)
1773 ((MonoInst*)(l->data))->inst_p0 = call2;
1775 /* FIXME: Optimize this */
1777 /* Emit an r4->r8 conversion */
1778 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1779 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1780 conv->dreg = ins->dreg;
1782 /* The call sequence might include fp ins */
1785 switch (ins->opcode) {
1787 ins->opcode = OP_LCALL;
1790 ins->opcode = OP_LCALL_REG;
1792 case OP_FCALL_MEMBASE:
1793 ins->opcode = OP_LCALL_MEMBASE;
1796 g_assert_not_reached ();
1802 MonoJitICallInfo *info;
1803 MonoInst *iargs [2];
1804 MonoInst *call, *cmp, *br;
1806 /* Convert fcompare+fbcc to icall+icompare+beq */
1809 /* The branch might be optimized away */
1814 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1816 /* The branch might be optimized away */
1821 /* Create dummy MonoInst's for the arguments */
1822 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1823 iargs [0]->dreg = ins->sreg1;
1824 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1825 iargs [1]->dreg = ins->sreg2;
1827 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1829 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1830 cmp->sreg1 = call->dreg;
1832 MONO_ADD_INS (cfg->cbb, cmp);
1834 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1835 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1836 br->inst_true_bb = ins->next->inst_true_bb;
1837 br->inst_false_bb = ins->next->inst_false_bb;
1838 MONO_ADD_INS (cfg->cbb, br);
1840 /* The call sequence might include fp ins */
1843 /* Skip fbcc or fccc */
1844 NULLIFY_INS (ins->next);
1852 MonoJitICallInfo *info;
1853 MonoInst *iargs [2];
1856 /* Convert fccc to icall+icompare+iceq */
1858 info = mono_find_jit_opcode_emulation (ins->opcode);
1861 /* Create dummy MonoInst's for the arguments */
1862 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1863 iargs [0]->dreg = ins->sreg1;
1864 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1865 iargs [1]->dreg = ins->sreg2;
1867 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1869 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1870 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1872 /* The call sequence might include fp ins */
1877 MonoInst *iargs [2];
1878 MonoInst *call, *cmp;
1880 /* Convert to icall+icompare+cond_exc+move */
1882 /* Create dummy MonoInst's for the arguments */
1883 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1884 iargs [0]->dreg = ins->sreg1;
1886 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1888 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1889 cmp->sreg1 = call->dreg;
1891 MONO_ADD_INS (cfg->cbb, cmp);
1893 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1895 /* Do the assignment if the value is finite */
1896 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1902 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1903 mono_print_ins (ins);
1904 g_assert_not_reached ();
1909 g_assert (cfg->cbb == first_bb);
1911 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1912 /* Replace the original instruction with the new code sequence */
1914 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1915 first_bb->code = first_bb->last_ins = NULL;
1916 first_bb->in_count = first_bb->out_count = 0;
1917 cfg->cbb = first_bb;
1924 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1927 mono_decompose_long_opts (cfg);
1932 #endif /* DISABLE_JIT */