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 */
311 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
312 mono_arch_decompose_opts (cfg, ins);
316 * The code below assumes that we are called immediately after emitting
317 * ins. This means we can emit code using the normal code generation
320 switch (ins->opcode) {
321 /* this doesn't make sense on ppc and other architectures */
322 #if !defined(MONO_ARCH_NO_IOV_CHECK)
324 if (COMPILE_LLVM (cfg))
326 ins->opcode = OP_IADDCC;
327 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
330 if (COMPILE_LLVM (cfg))
332 ins->opcode = OP_IADDCC;
333 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
336 if (COMPILE_LLVM (cfg))
338 ins->opcode = OP_ISUBCC;
339 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
342 if (COMPILE_LLVM (cfg))
344 ins->opcode = OP_ISUBCC;
345 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
348 case OP_ICONV_TO_OVF_I1:
349 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
350 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
351 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
352 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
353 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
356 case OP_ICONV_TO_OVF_I1_UN:
357 /* probe values between 0 to 127 */
358 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
359 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
360 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
363 case OP_ICONV_TO_OVF_U1:
364 case OP_ICONV_TO_OVF_U1_UN:
365 /* probe value to be within 0 to 255 */
366 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
367 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
368 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
371 case OP_ICONV_TO_OVF_I2:
372 /* Probe value to be within -32768 and 32767 */
373 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
374 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
375 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
376 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
377 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
380 case OP_ICONV_TO_OVF_I2_UN:
381 /* Convert uint value into short, value within 0 and 32767 */
382 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
383 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
384 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
387 case OP_ICONV_TO_OVF_U2:
388 case OP_ICONV_TO_OVF_U2_UN:
389 /* Probe value to be within 0 and 65535 */
390 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
391 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
392 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
395 case OP_ICONV_TO_OVF_U4:
396 case OP_ICONV_TO_OVF_I4_UN:
397 #if SIZEOF_VOID_P == 4
398 case OP_ICONV_TO_OVF_U:
399 case OP_ICONV_TO_OVF_I_UN:
401 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
402 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
403 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
408 case OP_ICONV_TO_OVF_I4:
409 case OP_ICONV_TO_OVF_U4_UN:
410 #if SIZEOF_VOID_P == 4
411 case OP_ICONV_TO_OVF_I:
412 case OP_ICONV_TO_OVF_U_UN:
414 ins->opcode = OP_MOVE;
417 #if SIZEOF_VOID_P == 8
418 ins->opcode = OP_SEXT_I4;
420 ins->opcode = OP_MOVE;
424 #if SIZEOF_VOID_P == 8
425 ins->opcode = OP_ZEXT_I4;
427 ins->opcode = OP_MOVE;
432 ins->opcode = OP_FMOVE;
435 case OP_FCONV_TO_OVF_I1_UN:
436 case OP_FCONV_TO_OVF_I2_UN:
437 case OP_FCONV_TO_OVF_I4_UN:
438 case OP_FCONV_TO_OVF_I8_UN:
439 case OP_FCONV_TO_OVF_U1_UN:
440 case OP_FCONV_TO_OVF_U2_UN:
441 case OP_FCONV_TO_OVF_U4_UN:
442 case OP_FCONV_TO_OVF_U8_UN:
443 case OP_FCONV_TO_OVF_I_UN:
444 case OP_FCONV_TO_OVF_U_UN:
445 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
446 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
449 #if defined(MONO_ARCH_EMULATE_DIV) && defined(MONO_ARCH_HAVE_OPCODE_NEEDS_EMULATION)
454 if (!mono_arch_opcode_needs_emulation (cfg, ins->opcode)) {
455 #ifdef MONO_ARCH_NEED_DIV_CHECK
456 int reg1 = alloc_ireg (cfg);
457 int reg2 = alloc_ireg (cfg);
459 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
460 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
461 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
462 /* b == -1 && a == 0x80000000 */
463 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
464 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
465 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
466 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
467 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
468 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
469 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
472 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
480 #if SIZEOF_REGISTER == 8
484 int power = mono_is_power_of_two (ins->inst_imm);
485 if (ins->inst_imm == 1) {
486 ins->opcode = OP_ICONST;
487 MONO_INST_NULLIFY_SREGS (ins);
492 } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
493 gboolean is_long = ins->opcode == OP_LREM_IMM;
494 int compensator_reg = alloc_ireg (cfg);
495 int intermediate_reg;
497 /* Based on gcc code */
499 /* Add compensation for negative numerators */
502 intermediate_reg = compensator_reg;
503 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_ISHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
505 intermediate_reg = ins->sreg1;
508 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);
509 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
510 /* Compute remainder */
511 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
512 /* Remove compensation */
513 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LSUB : OP_ISUB, ins->dreg, ins->dreg, compensator_reg);
527 MonoJitICallInfo *info = NULL;
529 #if SIZEOF_REGISTER == 8
530 if (decompose_long_opcode (cfg, ins, &repl))
533 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
538 info = mono_find_jit_opcode_emulation (ins->opcode);
543 /* Create dummy MonoInst's for the arguments */
544 g_assert (!info->sig->hasthis);
545 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
547 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
548 if (info->sig->param_count > 0) {
549 int sregs [MONO_MAX_SRC_REGS];
551 num_sregs = mono_inst_get_src_registers (ins, sregs);
552 g_assert (num_sregs == info->sig->param_count);
553 for (i = 0; i < num_sregs; ++i) {
554 MONO_INST_NEW (cfg, args [i], OP_ARG);
555 args [i]->dreg = sregs [i];
559 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
560 call->dreg = ins->dreg;
566 if (ins->opcode == OP_NOP) {
571 /* Use the last emitted instruction */
572 ins = cfg->cbb->last_ins;
575 g_assert (ins->dreg == dreg);
583 #if SIZEOF_REGISTER == 4
584 static int lbr_decomp [][2] = {
586 {OP_IBGT, OP_IBGE_UN}, /* BGE */
587 {OP_IBGT, OP_IBGT_UN}, /* BGT */
588 {OP_IBLT, OP_IBLE_UN}, /* BLE */
589 {OP_IBLT, OP_IBLT_UN}, /* BLT */
591 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
592 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
593 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
594 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
597 static int lcset_decomp [][2] = {
599 {OP_IBLT, OP_IBLE_UN}, /* CGT */
600 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
601 {OP_IBGT, OP_IBGE_UN}, /* CLT */
602 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
607 * mono_decompose_long_opts:
609 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
612 mono_decompose_long_opts (MonoCompile *cfg)
614 #if SIZEOF_REGISTER == 4
615 MonoBasicBlock *bb, *first_bb;
618 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
619 * needs to be able to handle long vregs.
622 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
625 * Create a dummy bblock and emit code into it so we can use the normal
626 * code generation macros.
628 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
631 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
632 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
633 MonoInst *prev = NULL;
636 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
639 cfg->cbb->code = cfg->cbb->last_ins = NULL;
643 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
644 mono_arch_decompose_long_opts (cfg, tree);
647 switch (tree->opcode) {
649 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
650 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
652 case OP_DUMMY_I8CONST:
653 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 1, OP_DUMMY_ICONST);
654 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 2, OP_DUMMY_ICONST);
659 case OP_LCONV_TO_OVF_U8_UN:
660 case OP_LCONV_TO_OVF_I8:
661 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
662 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
664 case OP_STOREI8_MEMBASE_REG:
665 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
666 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
668 case OP_LOADI8_MEMBASE:
669 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
670 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
673 case OP_ICONV_TO_I8: {
674 guint32 tmpreg = alloc_ireg (cfg);
678 * tmp = low > -1 ? 1: 0;
679 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
681 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
682 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
683 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
684 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
688 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
689 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
691 case OP_ICONV_TO_OVF_I8:
692 /* a signed 32 bit num always fits in a signed 64 bit one */
693 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
694 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
696 case OP_ICONV_TO_OVF_U8:
697 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
698 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
699 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
700 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
702 case OP_ICONV_TO_OVF_I8_UN:
703 case OP_ICONV_TO_OVF_U8_UN:
704 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
705 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
706 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
709 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
712 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
715 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
718 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
724 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
727 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
730 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
732 case OP_LCONV_TO_R_UN:
733 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
735 case OP_LCONV_TO_OVF_I1: {
736 MonoBasicBlock *is_negative, *end_label;
738 NEW_BBLOCK (cfg, is_negative);
739 NEW_BBLOCK (cfg, end_label);
741 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
742 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
743 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
744 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
746 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
747 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
750 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
751 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
752 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
755 MONO_START_BB (cfg, is_negative);
756 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
757 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
759 MONO_START_BB (cfg, end_label);
761 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
764 case OP_LCONV_TO_OVF_I1_UN:
765 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
766 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
768 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
769 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
770 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
771 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
772 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
774 case OP_LCONV_TO_OVF_U1:
775 case OP_LCONV_TO_OVF_U1_UN:
776 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
777 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
779 /* probe value to be within 0 to 255 */
780 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
781 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
784 case OP_LCONV_TO_OVF_I2: {
785 MonoBasicBlock *is_negative, *end_label;
787 NEW_BBLOCK (cfg, is_negative);
788 NEW_BBLOCK (cfg, end_label);
790 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
791 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
792 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
793 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
795 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
796 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
799 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
800 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
801 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
804 MONO_START_BB (cfg, is_negative);
805 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
806 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
807 MONO_START_BB (cfg, end_label);
809 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
812 case OP_LCONV_TO_OVF_I2_UN:
813 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
814 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
816 /* Probe value to be within -32768 and 32767 */
817 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
818 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
819 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
820 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
821 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
823 case OP_LCONV_TO_OVF_U2:
824 case OP_LCONV_TO_OVF_U2_UN:
825 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
826 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
828 /* Probe value to be within 0 and 65535 */
829 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
830 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
831 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
833 case OP_LCONV_TO_OVF_I4:
834 case OP_LCONV_TO_OVF_I:
835 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
837 case OP_LCONV_TO_OVF_U4:
838 case OP_LCONV_TO_OVF_U:
839 case OP_LCONV_TO_OVF_U4_UN:
840 case OP_LCONV_TO_OVF_U_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_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
845 case OP_LCONV_TO_OVF_I_UN:
846 case OP_LCONV_TO_OVF_I4_UN:
847 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
848 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
849 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
850 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
851 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
853 case OP_LCONV_TO_OVF_U8:
854 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
855 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
857 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
858 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
860 case OP_LCONV_TO_OVF_I8_UN:
861 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
862 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
864 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
865 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
869 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
870 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
873 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
874 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
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, OV, "OverflowException");
884 /* ADC sets the condition code */
885 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
886 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
887 MONO_EMIT_NEW_COND_EXC (cfg, C, "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, OV, "OverflowException");
896 /* SBB sets the condition code */
897 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
898 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
899 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
902 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
903 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
906 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
907 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
910 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
911 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
914 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
915 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
918 /* Handled in mono_arch_decompose_long_opts () */
919 g_assert_not_reached ();
923 /* FIXME: Add OP_BIGMUL optimization */
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
932 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
935 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
936 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
939 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
940 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
943 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
944 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
947 if (tree->inst_c1 == 32) {
949 /* The original code had this comment: */
950 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
951 * later apply the speedup to the left shift as well
954 /* FIXME: Move this to the strength reduction pass */
955 /* just move the upper half to the lower and zero the high word */
956 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
957 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
961 if (tree->inst_c1 == 32) {
962 /* just move the lower half to the upper and zero the lower word */
963 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
964 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
969 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
973 switch (next->opcode) {
978 /* Branchless version based on gcc code */
979 d1 = alloc_ireg (cfg);
980 d2 = alloc_ireg (cfg);
981 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
982 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
983 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
984 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
985 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
997 /* Convert into three comparisons + branches */
998 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
999 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1000 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1001 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1002 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
1003 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1009 /* Branchless version based on gcc code */
1010 d1 = alloc_ireg (cfg);
1011 d2 = alloc_ireg (cfg);
1012 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
1013 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
1014 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1016 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1017 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1025 MonoBasicBlock *set_to_0, *set_to_1;
1027 NEW_BBLOCK (cfg, set_to_0);
1028 NEW_BBLOCK (cfg, set_to_1);
1030 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1031 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1032 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1033 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1034 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1035 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
1036 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1037 MONO_START_BB (cfg, set_to_1);
1038 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1039 MONO_START_BB (cfg, set_to_0);
1044 g_assert_not_reached ();
1049 /* Not yet used, since lcompare is decomposed before local cprop */
1050 case OP_LCOMPARE_IMM: {
1051 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1052 guint32 low_imm = tree->inst_ls_word;
1053 guint32 high_imm = tree->inst_ms_word;
1054 int low_reg = tree->sreg1 + 1;
1055 int high_reg = tree->sreg1 + 2;
1059 switch (next->opcode) {
1064 /* Branchless version based on gcc code */
1065 d1 = alloc_ireg (cfg);
1066 d2 = alloc_ireg (cfg);
1067 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1068 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1069 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1070 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1071 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1084 /* Convert into three comparisons + branches */
1085 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1086 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1087 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1088 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1089 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1090 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1096 /* Branchless version based on gcc code */
1097 d1 = alloc_ireg (cfg);
1098 d2 = alloc_ireg (cfg);
1099 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1100 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1101 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1103 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1104 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1112 MonoBasicBlock *set_to_0, *set_to_1;
1114 NEW_BBLOCK (cfg, set_to_0);
1115 NEW_BBLOCK (cfg, set_to_1);
1117 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1118 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1119 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1120 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1121 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1122 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1123 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1124 MONO_START_BB (cfg, set_to_1);
1125 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1126 MONO_START_BB (cfg, set_to_0);
1131 g_assert_not_reached ();
1140 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1143 /* Replace the original instruction with the new code sequence */
1145 /* Ignore the new value of prev */
1147 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1149 /* Process the newly added ops again since they can be long ops too */
1151 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1153 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1155 first_bb->code = first_bb->last_ins = NULL;
1156 first_bb->in_count = first_bb->out_count = 0;
1157 cfg->cbb = first_bb;
1161 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1168 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1169 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1174 * mono_decompose_vtype_opts:
1176 * Decompose valuetype opcodes.
1179 mono_decompose_vtype_opts (MonoCompile *cfg)
1181 MonoBasicBlock *bb, *first_bb;
1184 * Using OP_V opcodes and decomposing them later have two main benefits:
1185 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1187 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1188 * enabling optimizations to work on vtypes too.
1189 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1190 * can be executed anytime. It should be executed as late as possible so vtype
1191 * opcodes can be optimized by the other passes.
1192 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1193 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1195 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1196 * when OP_VMOVE opcodes are decomposed.
1200 * Vregs have no associated type information, so we store the type of the vregs
1205 * Create a dummy bblock and emit code into it so we can use the normal
1206 * code generation macros.
1208 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1209 first_bb = cfg->cbb;
1211 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1213 MonoInst *prev = NULL;
1214 MonoInst *src_var, *dest_var, *src, *dest;
1218 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1220 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1226 for (ins = bb->code; ins; ins = ins->next) {
1227 switch (ins->opcode) {
1229 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1230 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1232 g_assert (ins->klass);
1235 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1238 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1241 if (src_var->backend.is_pinvoke)
1242 dest_var->backend.is_pinvoke = 1;
1244 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1245 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1247 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1251 g_assert (ins->klass);
1253 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1254 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1256 if (cfg->compute_gc_maps) {
1260 * Tell the GC map code that the vtype is considered live after
1261 * the initialization.
1263 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1264 tmp->inst_c1 = ins->dreg;
1265 MONO_ADD_INS (cfg->cbb, tmp);
1268 case OP_DUMMY_VZERO:
1271 case OP_STOREV_MEMBASE: {
1272 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1275 g_assert (ins->klass);
1276 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1279 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1281 dreg = alloc_preg (cfg);
1282 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1283 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1286 case OP_LOADV_MEMBASE: {
1287 g_assert (ins->klass);
1289 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1293 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1295 dreg = alloc_preg (cfg);
1296 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1297 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1298 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1301 case OP_OUTARG_VT: {
1302 g_assert (ins->klass);
1304 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1306 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1307 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1309 mono_arch_emit_outarg_vt (cfg, ins, src);
1311 /* This might be decomposed into other vtype opcodes */
1315 case OP_OUTARG_VTRETADDR: {
1316 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1318 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1320 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1321 // FIXME: src_var->backend.is_pinvoke ?
1323 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1324 src->dreg = ins->dreg;
1329 case OP_VCALL_MEMBASE: {
1330 MonoCallInst *call = (MonoCallInst*)ins;
1333 if (call->vret_in_reg) {
1334 MonoCallInst *call2;
1336 /* Replace the vcall with a scalar call */
1337 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1338 memcpy (call2, call, sizeof (MonoCallInst));
1339 switch (ins->opcode) {
1341 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1344 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1346 case OP_VCALL_MEMBASE:
1347 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1350 call2->inst.dreg = alloc_preg (cfg);
1351 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1353 /* Compute the vtype location */
1354 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1356 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1357 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1359 /* Save the result */
1360 if (dest_var->backend.is_pinvoke)
1361 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1363 size = mono_type_size (dest_var->inst_vtype, NULL);
1366 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1369 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1373 if (call->vret_in_reg_fp)
1374 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1376 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1382 if (call->vret_in_reg_fp) {
1383 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1386 #if SIZEOF_REGISTER == 4
1388 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1389 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1391 switch (call2->inst.opcode) {
1393 call2->inst.opcode = OP_LCALL;
1396 call2->inst.opcode = OP_LCALL_REG;
1398 case OP_CALL_MEMBASE:
1399 call2->inst.opcode = OP_LCALL_MEMBASE;
1402 call2->inst.dreg = alloc_lreg (cfg);
1403 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1404 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1406 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1410 /* This assumes the vtype is sizeof (gpointer) long */
1411 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1415 switch (ins->opcode) {
1417 ins->opcode = OP_VCALL2;
1420 ins->opcode = OP_VCALL2_REG;
1422 case OP_VCALL_MEMBASE:
1423 ins->opcode = OP_VCALL2_MEMBASE;
1434 g_assert (cfg->cbb == first_bb);
1436 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1437 /* Replace the original instruction with the new code sequence */
1439 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1440 first_bb->code = first_bb->last_ins = NULL;
1441 first_bb->in_count = first_bb->out_count = 0;
1442 cfg->cbb = first_bb;
1449 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1454 mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
1456 MonoBasicBlock *bb, *first_bb;
1458 /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
1460 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1461 first_bb = cfg->cbb;
1463 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1465 MonoInst *prev = NULL;
1466 MonoInst *src_var, *src, *dest;
1470 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
1472 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1478 for (ins = bb->code; ins; ins = ins->next) {
1479 switch (ins->opcode) {
1480 case OP_STOREV_MEMBASE: {
1481 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1484 g_assert (ins->klass);
1485 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1488 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1490 dreg = alloc_preg (cfg);
1491 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1492 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1499 g_assert (cfg->cbb == first_bb);
1501 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1502 /* Replace the original instruction with the new code sequence */
1504 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1505 first_bb->code = first_bb->last_ins = NULL;
1506 first_bb->in_count = first_bb->out_count = 0;
1507 cfg->cbb = first_bb;
1514 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
1518 inline static MonoInst *
1519 mono_get_domainvar (MonoCompile *cfg)
1521 if (!cfg->domainvar)
1522 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1523 return cfg->domainvar;
1527 * mono_decompose_array_access_opts:
1529 * Decompose array access opcodes.
1532 mono_decompose_array_access_opts (MonoCompile *cfg)
1534 MonoBasicBlock *bb, *first_bb;
1537 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1538 * can be executed anytime. It should be run before decompose_long
1542 * Create a dummy bblock and emit code into it so we can use the normal
1543 * code generation macros.
1545 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1546 first_bb = cfg->cbb;
1548 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1550 MonoInst *prev = NULL;
1552 MonoInst *iargs [3];
1555 if (!bb->has_array_access)
1558 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1560 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1566 for (ins = bb->code; ins; ins = ins->next) {
1567 switch (ins->opcode) {
1569 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1570 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1571 MONO_ADD_INS (cfg->cbb, dest);
1573 case OP_BOUNDS_CHECK:
1574 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1575 if (COMPILE_LLVM (cfg))
1576 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1578 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1581 if (cfg->opt & MONO_OPT_SHARED) {
1582 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1583 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1584 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1585 iargs [2]->dreg = ins->sreg1;
1587 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1588 dest->dreg = ins->dreg;
1590 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1591 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1592 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1594 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1595 NEW_VTABLECONST (cfg, iargs [0], vtable);
1596 MONO_ADD_INS (cfg->cbb, iargs [0]);
1597 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1598 iargs [1]->dreg = ins->sreg1;
1601 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1603 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1604 dest->dreg = ins->dreg;
1608 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1609 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1615 g_assert (cfg->cbb == first_bb);
1617 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1618 /* Replace the original instruction with the new code sequence */
1620 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1621 first_bb->code = first_bb->last_ins = NULL;
1622 first_bb->in_count = first_bb->out_count = 0;
1623 cfg->cbb = first_bb;
1630 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1640 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1643 * mono_decompose_soft_float:
1645 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1646 * similar to long support on 32 bit platforms. 32 bit float values require special
1647 * handling when used as locals, arguments, and in calls.
1648 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1651 mono_decompose_soft_float (MonoCompile *cfg)
1653 MonoBasicBlock *bb, *first_bb;
1656 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1660 * Create a dummy bblock and emit code into it so we can use the normal
1661 * code generation macros.
1663 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1664 first_bb = cfg->cbb;
1666 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1668 MonoInst *prev = NULL;
1671 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1673 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1679 for (ins = bb->code; ins; ins = ins->next) {
1680 const char *spec = INS_INFO (ins->opcode);
1682 /* Most fp operations are handled automatically by opcode emulation */
1684 switch (ins->opcode) {
1687 d.vald = *(double*)ins->inst_p0;
1688 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1693 /* We load the r8 value */
1694 d.vald = *(float*)ins->inst_p0;
1695 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1699 ins->opcode = OP_LMOVE;
1702 ins->opcode = OP_MOVE;
1703 ins->sreg1 = ins->sreg1 + 1;
1706 ins->opcode = OP_MOVE;
1707 ins->sreg1 = ins->sreg1 + 2;
1710 int reg = ins->sreg1;
1712 ins->opcode = OP_SETLRET;
1714 ins->sreg1 = reg + 1;
1715 ins->sreg2 = reg + 2;
1718 case OP_LOADR8_MEMBASE:
1719 ins->opcode = OP_LOADI8_MEMBASE;
1721 case OP_STORER8_MEMBASE_REG:
1722 ins->opcode = OP_STOREI8_MEMBASE_REG;
1724 case OP_STORER4_MEMBASE_REG: {
1725 MonoInst *iargs [2];
1728 /* Arg 1 is the double value */
1729 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1730 iargs [0]->dreg = ins->sreg1;
1732 /* Arg 2 is the address to store to */
1733 addr_reg = mono_alloc_preg (cfg);
1734 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1735 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1739 case OP_LOADR4_MEMBASE: {
1740 MonoInst *iargs [1];
1744 addr_reg = mono_alloc_preg (cfg);
1745 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1746 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1747 conv->dreg = ins->dreg;
1752 case OP_FCALL_MEMBASE: {
1753 MonoCallInst *call = (MonoCallInst*)ins;
1754 if (call->signature->ret->type == MONO_TYPE_R4) {
1755 MonoCallInst *call2;
1756 MonoInst *iargs [1];
1760 /* Convert the call into a call returning an int */
1761 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1762 memcpy (call2, call, sizeof (MonoCallInst));
1763 switch (ins->opcode) {
1765 call2->inst.opcode = OP_CALL;
1768 call2->inst.opcode = OP_CALL_REG;
1770 case OP_FCALL_MEMBASE:
1771 call2->inst.opcode = OP_CALL_MEMBASE;
1774 g_assert_not_reached ();
1776 call2->inst.dreg = mono_alloc_ireg (cfg);
1777 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1779 /* Remap OUTARG_VT instructions referencing this call */
1780 for (l = call->outarg_vts; l; l = l->next)
1781 ((MonoInst*)(l->data))->inst_p0 = call2;
1783 /* FIXME: Optimize this */
1785 /* Emit an r4->r8 conversion */
1786 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1787 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1788 conv->dreg = ins->dreg;
1790 /* The call sequence might include fp ins */
1793 switch (ins->opcode) {
1795 ins->opcode = OP_LCALL;
1798 ins->opcode = OP_LCALL_REG;
1800 case OP_FCALL_MEMBASE:
1801 ins->opcode = OP_LCALL_MEMBASE;
1804 g_assert_not_reached ();
1810 MonoJitICallInfo *info;
1811 MonoInst *iargs [2];
1812 MonoInst *call, *cmp, *br;
1814 /* Convert fcompare+fbcc to icall+icompare+beq */
1817 /* The branch might be optimized away */
1822 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1824 /* The branch might be optimized away */
1829 /* Create dummy MonoInst's for the arguments */
1830 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1831 iargs [0]->dreg = ins->sreg1;
1832 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1833 iargs [1]->dreg = ins->sreg2;
1835 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1837 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1838 cmp->sreg1 = call->dreg;
1840 MONO_ADD_INS (cfg->cbb, cmp);
1842 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1843 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1844 br->inst_true_bb = ins->next->inst_true_bb;
1845 br->inst_false_bb = ins->next->inst_false_bb;
1846 MONO_ADD_INS (cfg->cbb, br);
1848 /* The call sequence might include fp ins */
1851 /* Skip fbcc or fccc */
1852 NULLIFY_INS (ins->next);
1860 MonoJitICallInfo *info;
1861 MonoInst *iargs [2];
1864 /* Convert fccc to icall+icompare+iceq */
1866 info = mono_find_jit_opcode_emulation (ins->opcode);
1869 /* Create dummy MonoInst's for the arguments */
1870 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1871 iargs [0]->dreg = ins->sreg1;
1872 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1873 iargs [1]->dreg = ins->sreg2;
1875 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1877 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1878 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1880 /* The call sequence might include fp ins */
1885 MonoInst *iargs [2];
1886 MonoInst *call, *cmp;
1888 /* Convert to icall+icompare+cond_exc+move */
1890 /* Create dummy MonoInst's for the arguments */
1891 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1892 iargs [0]->dreg = ins->sreg1;
1894 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1896 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1897 cmp->sreg1 = call->dreg;
1899 MONO_ADD_INS (cfg->cbb, cmp);
1901 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1903 /* Do the assignment if the value is finite */
1904 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1910 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1911 mono_print_ins (ins);
1912 g_assert_not_reached ();
1917 g_assert (cfg->cbb == first_bb);
1919 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1920 /* Replace the original instruction with the new code sequence */
1922 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1923 first_bb->code = first_bb->last_ins = NULL;
1924 first_bb->in_count = first_bb->out_count = 0;
1925 cfg->cbb = first_bb;
1932 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1935 mono_decompose_long_opts (cfg);
1940 #endif /* DISABLE_JIT */