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);
473 ins->opcode = OP_NOP;
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);
489 } else if ((ins->inst_imm > 0) && (ins->inst_imm < (1LL << 32)) && (power != -1)) {
490 gboolean is_long = ins->opcode == OP_LREM_IMM;
491 int compensator_reg = alloc_ireg (cfg);
492 int intermediate_reg;
494 /* Based on gcc code */
496 /* Add compensation for negative numerators */
499 intermediate_reg = compensator_reg;
500 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_IMM : OP_SHR_IMM, intermediate_reg, ins->sreg1, is_long ? 63 : 31);
502 intermediate_reg = ins->sreg1;
505 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LSHR_UN_IMM : OP_SHR_UN_IMM, compensator_reg, intermediate_reg, (is_long ? 64 : 32) - power);
506 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LADD : OP_IADD, ins->dreg, ins->sreg1, compensator_reg);
507 /* Compute remainder */
508 MONO_EMIT_NEW_BIALU_IMM (cfg, is_long ? OP_LAND_IMM : OP_AND_IMM, ins->dreg, ins->dreg, (1 << power) - 1);
509 /* Remove compensation */
510 MONO_EMIT_NEW_BIALU (cfg, is_long ? OP_LSUB : OP_ISUB, ins->dreg, ins->dreg, compensator_reg);
523 MonoJitICallInfo *info = NULL;
525 #if SIZEOF_REGISTER == 8
526 if (decompose_long_opcode (cfg, ins, &repl))
529 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
534 info = mono_find_jit_opcode_emulation (ins->opcode);
539 /* Create dummy MonoInst's for the arguments */
540 g_assert (!info->sig->hasthis);
541 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
543 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
544 if (info->sig->param_count > 0) {
545 int sregs [MONO_MAX_SRC_REGS];
547 num_sregs = mono_inst_get_src_registers (ins, sregs);
548 g_assert (num_sregs == info->sig->param_count);
549 for (i = 0; i < num_sregs; ++i) {
550 MONO_INST_NEW (cfg, args [i], OP_ARG);
551 args [i]->dreg = sregs [i];
555 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
556 call->dreg = ins->dreg;
562 if (ins->opcode == OP_NOP) {
567 /* Use the last emitted instruction */
568 ins = cfg->cbb->last_ins;
571 g_assert (ins->dreg == dreg);
579 #if SIZEOF_REGISTER == 4
580 static int lbr_decomp [][2] = {
582 {OP_IBGT, OP_IBGE_UN}, /* BGE */
583 {OP_IBGT, OP_IBGT_UN}, /* BGT */
584 {OP_IBLT, OP_IBLE_UN}, /* BLE */
585 {OP_IBLT, OP_IBLT_UN}, /* BLT */
587 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
588 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
589 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
590 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
593 static int lcset_decomp [][2] = {
595 {OP_IBLT, OP_IBLE_UN}, /* CGT */
596 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
597 {OP_IBGT, OP_IBGE_UN}, /* CLT */
598 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
603 * mono_decompose_long_opts:
605 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
608 mono_decompose_long_opts (MonoCompile *cfg)
610 #if SIZEOF_REGISTER == 4
611 MonoBasicBlock *bb, *first_bb;
614 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
615 * needs to be able to handle long vregs.
618 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
621 * Create a dummy bblock and emit code into it so we can use the normal
622 * code generation macros.
624 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
627 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
628 MonoInst *tree = bb->code;
629 MonoInst *prev = NULL;
632 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
636 cfg->cbb->code = cfg->cbb->last_ins = NULL;
640 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
641 mono_arch_decompose_long_opts (cfg, tree);
644 switch (tree->opcode) {
646 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
647 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
649 case OP_DUMMY_I8CONST:
650 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 1, OP_DUMMY_ICONST);
651 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 2, OP_DUMMY_ICONST);
656 case OP_LCONV_TO_OVF_U8_UN:
657 case OP_LCONV_TO_OVF_I8:
658 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
659 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
661 case OP_STOREI8_MEMBASE_REG:
662 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
663 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
665 case OP_LOADI8_MEMBASE:
666 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
667 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
670 case OP_ICONV_TO_I8: {
671 guint32 tmpreg = alloc_ireg (cfg);
675 * tmp = low > -1 ? 1: 0;
676 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
678 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
679 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
680 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
681 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
685 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
686 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
688 case OP_ICONV_TO_OVF_I8:
689 /* a signed 32 bit num always fits in a signed 64 bit one */
690 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
691 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
693 case OP_ICONV_TO_OVF_U8:
694 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
695 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
696 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
697 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
699 case OP_ICONV_TO_OVF_I8_UN:
700 case OP_ICONV_TO_OVF_U8_UN:
701 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
702 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
703 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
706 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
709 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
712 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
715 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
721 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
724 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
727 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
729 case OP_LCONV_TO_R_UN:
730 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
732 case OP_LCONV_TO_OVF_I1: {
733 MonoBasicBlock *is_negative, *end_label;
735 NEW_BBLOCK (cfg, is_negative);
736 NEW_BBLOCK (cfg, end_label);
738 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
739 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
740 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
741 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
743 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
744 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
747 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
748 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
749 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
752 MONO_START_BB (cfg, is_negative);
753 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
754 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
756 MONO_START_BB (cfg, end_label);
758 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
761 case OP_LCONV_TO_OVF_I1_UN:
762 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
763 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
765 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
766 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
767 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
768 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
769 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
771 case OP_LCONV_TO_OVF_U1:
772 case OP_LCONV_TO_OVF_U1_UN:
773 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
774 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
776 /* probe value to be within 0 to 255 */
777 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
778 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
779 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
781 case OP_LCONV_TO_OVF_I2: {
782 MonoBasicBlock *is_negative, *end_label;
784 NEW_BBLOCK (cfg, is_negative);
785 NEW_BBLOCK (cfg, end_label);
787 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
788 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
789 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
790 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
792 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
793 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
796 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
797 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
798 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
801 MONO_START_BB (cfg, is_negative);
802 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
803 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
804 MONO_START_BB (cfg, end_label);
806 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
809 case OP_LCONV_TO_OVF_I2_UN:
810 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
811 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
813 /* Probe value to be within -32768 and 32767 */
814 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
815 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
816 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
817 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
818 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
820 case OP_LCONV_TO_OVF_U2:
821 case OP_LCONV_TO_OVF_U2_UN:
822 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
823 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
825 /* Probe value to be within 0 and 65535 */
826 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
827 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
828 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
830 case OP_LCONV_TO_OVF_I4:
831 case OP_LCONV_TO_OVF_I:
832 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
834 case OP_LCONV_TO_OVF_U4:
835 case OP_LCONV_TO_OVF_U:
836 case OP_LCONV_TO_OVF_U4_UN:
837 case OP_LCONV_TO_OVF_U_UN:
838 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
839 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
840 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
842 case OP_LCONV_TO_OVF_I_UN:
843 case OP_LCONV_TO_OVF_I4_UN:
844 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
845 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
846 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
847 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
848 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
850 case OP_LCONV_TO_OVF_U8:
851 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
852 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
854 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
855 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
857 case OP_LCONV_TO_OVF_I8_UN:
858 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
859 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
861 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
862 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
866 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
867 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
870 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
871 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
875 /* ADC sets the condition code */
876 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
877 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
878 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
881 /* ADC sets the condition code */
882 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
883 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
884 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
887 /* SBB sets the condition code */
888 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
889 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
890 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
893 /* SBB sets the condition code */
894 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
895 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
896 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
899 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
900 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
903 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
904 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
907 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
908 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
911 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
912 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
915 /* Handled in mono_arch_decompose_long_opts () */
916 g_assert_not_reached ();
920 /* FIXME: Add OP_BIGMUL optimization */
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
932 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
936 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
937 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
940 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
944 if (tree->inst_c1 == 32) {
946 /* The original code had this comment: */
947 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
948 * later apply the speedup to the left shift as well
951 /* FIXME: Move this to the strength reduction pass */
952 /* just move the upper half to the lower and zero the high word */
953 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
954 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
958 if (tree->inst_c1 == 32) {
959 /* just move the lower half to the upper and zero the lower word */
960 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
961 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
966 MonoInst *next = tree->next;
970 switch (next->opcode) {
975 /* Branchless version based on gcc code */
976 d1 = alloc_ireg (cfg);
977 d2 = alloc_ireg (cfg);
978 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
979 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
980 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
981 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
982 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
983 next->opcode = OP_NOP;
994 /* Convert into three comparisons + branches */
995 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
996 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
997 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
998 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
999 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
1000 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1001 next->opcode = OP_NOP;
1006 /* Branchless version based on gcc code */
1007 d1 = alloc_ireg (cfg);
1008 d2 = alloc_ireg (cfg);
1009 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
1010 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
1011 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1013 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1014 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1015 next->opcode = OP_NOP;
1022 MonoBasicBlock *set_to_0, *set_to_1;
1024 NEW_BBLOCK (cfg, set_to_0);
1025 NEW_BBLOCK (cfg, set_to_1);
1027 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1028 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1029 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1030 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1031 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1032 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
1033 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1034 MONO_START_BB (cfg, set_to_1);
1035 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1036 MONO_START_BB (cfg, set_to_0);
1037 next->opcode = OP_NOP;
1041 g_assert_not_reached ();
1046 /* Not yet used, since lcompare is decomposed before local cprop */
1047 case OP_LCOMPARE_IMM: {
1048 MonoInst *next = tree->next;
1049 guint32 low_imm = tree->inst_ls_word;
1050 guint32 high_imm = tree->inst_ms_word;
1051 int low_reg = tree->sreg1 + 1;
1052 int high_reg = tree->sreg1 + 2;
1056 switch (next->opcode) {
1061 /* Branchless version based on gcc code */
1062 d1 = alloc_ireg (cfg);
1063 d2 = alloc_ireg (cfg);
1064 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1065 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1066 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1067 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1068 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1069 next->opcode = OP_NOP;
1081 /* Convert into three comparisons + branches */
1082 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1083 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1084 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1085 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1086 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1087 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1088 next->opcode = OP_NOP;
1093 /* Branchless version based on gcc code */
1094 d1 = alloc_ireg (cfg);
1095 d2 = alloc_ireg (cfg);
1096 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1097 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1098 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1100 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1101 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1102 next->opcode = OP_NOP;
1109 MonoBasicBlock *set_to_0, *set_to_1;
1111 NEW_BBLOCK (cfg, set_to_0);
1112 NEW_BBLOCK (cfg, set_to_1);
1114 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1115 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1116 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1117 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1118 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1119 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1120 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1121 MONO_START_BB (cfg, set_to_1);
1122 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1123 MONO_START_BB (cfg, set_to_0);
1124 next->opcode = OP_NOP;
1128 g_assert_not_reached ();
1137 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1140 /* Replace the original instruction with the new code sequence */
1142 /* Ignore the new value of prev */
1144 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1146 /* Process the newly added ops again since they can be long ops too */
1152 first_bb->code = first_bb->last_ins = NULL;
1153 first_bb->in_count = first_bb->out_count = 0;
1154 cfg->cbb = first_bb;
1165 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1166 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1171 * mono_decompose_vtype_opts:
1173 * Decompose valuetype opcodes.
1176 mono_decompose_vtype_opts (MonoCompile *cfg)
1178 MonoBasicBlock *bb, *first_bb;
1181 * Using OP_V opcodes and decomposing them later have two main benefits:
1182 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1184 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1185 * enabling optimizations to work on vtypes too.
1186 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1187 * can be executed anytime. It should be executed as late as possible so vtype
1188 * opcodes can be optimized by the other passes.
1189 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1190 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1192 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1193 * when OP_VMOVE opcodes are decomposed.
1197 * Vregs have no associated type information, so we store the type of the vregs
1202 * Create a dummy bblock and emit code into it so we can use the normal
1203 * code generation macros.
1205 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1206 first_bb = cfg->cbb;
1208 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1210 MonoInst *prev = NULL;
1211 MonoInst *src_var, *dest_var, *src, *dest;
1215 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1217 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1223 for (ins = bb->code; ins; ins = ins->next) {
1224 switch (ins->opcode) {
1226 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1227 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1229 g_assert (ins->klass);
1232 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1235 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1238 if (src_var->backend.is_pinvoke)
1239 dest_var->backend.is_pinvoke = 1;
1241 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1242 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1244 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1248 g_assert (ins->klass);
1250 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1251 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1253 if (cfg->compute_gc_maps) {
1257 * Tell the GC map code that the vtype is considered live after
1258 * the initialization.
1260 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1261 tmp->inst_c1 = ins->dreg;
1262 MONO_ADD_INS (cfg->cbb, tmp);
1265 case OP_DUMMY_VZERO:
1268 case OP_STOREV_MEMBASE: {
1269 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1272 g_assert (ins->klass);
1273 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1276 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1278 dreg = alloc_preg (cfg);
1279 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1280 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1283 case OP_LOADV_MEMBASE: {
1284 g_assert (ins->klass);
1286 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1290 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1292 dreg = alloc_preg (cfg);
1293 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1294 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1295 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1298 case OP_OUTARG_VT: {
1299 g_assert (ins->klass);
1301 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1303 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1304 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1306 mono_arch_emit_outarg_vt (cfg, ins, src);
1308 /* This might be decomposed into other vtype opcodes */
1312 case OP_OUTARG_VTRETADDR: {
1313 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1315 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1317 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1318 // FIXME: src_var->backend.is_pinvoke ?
1320 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1321 src->dreg = ins->dreg;
1326 case OP_VCALL_MEMBASE: {
1327 MonoCallInst *call = (MonoCallInst*)ins;
1330 if (call->vret_in_reg) {
1331 MonoCallInst *call2;
1333 /* Replace the vcall with a scalar call */
1334 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1335 memcpy (call2, call, sizeof (MonoCallInst));
1336 switch (ins->opcode) {
1338 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1341 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1343 case OP_VCALL_MEMBASE:
1344 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1347 call2->inst.dreg = alloc_preg (cfg);
1348 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1350 /* Compute the vtype location */
1351 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1353 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1354 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1356 /* Save the result */
1357 if (dest_var->backend.is_pinvoke)
1358 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1360 size = mono_type_size (dest_var->inst_vtype, NULL);
1363 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1366 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1370 if (call->vret_in_reg_fp)
1371 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1373 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1379 if (call->vret_in_reg_fp) {
1380 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1383 #if SIZEOF_REGISTER == 4
1385 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1386 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1388 switch (call2->inst.opcode) {
1390 call2->inst.opcode = OP_LCALL;
1393 call2->inst.opcode = OP_LCALL_REG;
1395 case OP_CALL_MEMBASE:
1396 call2->inst.opcode = OP_LCALL_MEMBASE;
1399 call2->inst.dreg = alloc_lreg (cfg);
1400 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1401 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1403 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1407 /* This assumes the vtype is sizeof (gpointer) long */
1408 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1412 switch (ins->opcode) {
1414 ins->opcode = OP_VCALL2;
1417 ins->opcode = OP_VCALL2_REG;
1419 case OP_VCALL_MEMBASE:
1420 ins->opcode = OP_VCALL2_MEMBASE;
1431 g_assert (cfg->cbb == first_bb);
1433 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1434 /* Replace the original instruction with the new code sequence */
1436 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1437 first_bb->code = first_bb->last_ins = NULL;
1438 first_bb->in_count = first_bb->out_count = 0;
1439 cfg->cbb = first_bb;
1446 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1451 mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
1453 MonoBasicBlock *bb, *first_bb;
1455 /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
1457 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1458 first_bb = cfg->cbb;
1460 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1462 MonoInst *prev = NULL;
1463 MonoInst *src_var, *src, *dest;
1467 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
1469 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1475 for (ins = bb->code; ins; ins = ins->next) {
1476 switch (ins->opcode) {
1477 case OP_STOREV_MEMBASE: {
1478 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1481 g_assert (ins->klass);
1482 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1485 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1487 dreg = alloc_preg (cfg);
1488 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1489 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1496 g_assert (cfg->cbb == first_bb);
1498 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1499 /* Replace the original instruction with the new code sequence */
1501 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1502 first_bb->code = first_bb->last_ins = NULL;
1503 first_bb->in_count = first_bb->out_count = 0;
1504 cfg->cbb = first_bb;
1511 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
1515 inline static MonoInst *
1516 mono_get_domainvar (MonoCompile *cfg)
1518 if (!cfg->domainvar)
1519 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1520 return cfg->domainvar;
1524 * mono_decompose_array_access_opts:
1526 * Decompose array access opcodes.
1529 mono_decompose_array_access_opts (MonoCompile *cfg)
1531 MonoBasicBlock *bb, *first_bb;
1534 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1535 * can be executed anytime. It should be run before decompose_long
1539 * Create a dummy bblock and emit code into it so we can use the normal
1540 * code generation macros.
1542 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1543 first_bb = cfg->cbb;
1545 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1547 MonoInst *prev = NULL;
1549 MonoInst *iargs [3];
1552 if (!bb->has_array_access)
1555 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1557 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1563 for (ins = bb->code; ins; ins = ins->next) {
1564 switch (ins->opcode) {
1566 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1567 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1568 MONO_ADD_INS (cfg->cbb, dest);
1570 case OP_BOUNDS_CHECK:
1571 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1572 if (COMPILE_LLVM (cfg))
1573 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1575 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1578 if (cfg->opt & MONO_OPT_SHARED) {
1579 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1580 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1581 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1582 iargs [2]->dreg = ins->sreg1;
1584 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1585 dest->dreg = ins->dreg;
1587 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1588 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1589 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1591 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1592 NEW_VTABLECONST (cfg, iargs [0], vtable);
1593 MONO_ADD_INS (cfg->cbb, iargs [0]);
1594 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1595 iargs [1]->dreg = ins->sreg1;
1598 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1600 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1601 dest->dreg = ins->dreg;
1605 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1606 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1612 g_assert (cfg->cbb == first_bb);
1614 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1615 /* Replace the original instruction with the new code sequence */
1617 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1618 first_bb->code = first_bb->last_ins = NULL;
1619 first_bb->in_count = first_bb->out_count = 0;
1620 cfg->cbb = first_bb;
1627 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1637 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1640 * mono_decompose_soft_float:
1642 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1643 * similar to long support on 32 bit platforms. 32 bit float values require special
1644 * handling when used as locals, arguments, and in calls.
1645 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1648 mono_decompose_soft_float (MonoCompile *cfg)
1650 MonoBasicBlock *bb, *first_bb;
1653 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1657 * Create a dummy bblock and emit code into it so we can use the normal
1658 * code generation macros.
1660 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1661 first_bb = cfg->cbb;
1663 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1665 MonoInst *prev = NULL;
1668 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1670 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1676 for (ins = bb->code; ins; ins = ins->next) {
1677 const char *spec = INS_INFO (ins->opcode);
1679 /* Most fp operations are handled automatically by opcode emulation */
1681 switch (ins->opcode) {
1684 d.vald = *(double*)ins->inst_p0;
1685 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1690 /* We load the r8 value */
1691 d.vald = *(float*)ins->inst_p0;
1692 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1696 ins->opcode = OP_LMOVE;
1699 ins->opcode = OP_MOVE;
1700 ins->sreg1 = ins->sreg1 + 1;
1703 ins->opcode = OP_MOVE;
1704 ins->sreg1 = ins->sreg1 + 2;
1707 int reg = ins->sreg1;
1709 ins->opcode = OP_SETLRET;
1711 ins->sreg1 = reg + 1;
1712 ins->sreg2 = reg + 2;
1715 case OP_LOADR8_MEMBASE:
1716 ins->opcode = OP_LOADI8_MEMBASE;
1718 case OP_STORER8_MEMBASE_REG:
1719 ins->opcode = OP_STOREI8_MEMBASE_REG;
1721 case OP_STORER4_MEMBASE_REG: {
1722 MonoInst *iargs [2];
1725 /* Arg 1 is the double value */
1726 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1727 iargs [0]->dreg = ins->sreg1;
1729 /* Arg 2 is the address to store to */
1730 addr_reg = mono_alloc_preg (cfg);
1731 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1732 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1736 case OP_LOADR4_MEMBASE: {
1737 MonoInst *iargs [1];
1741 addr_reg = mono_alloc_preg (cfg);
1742 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1743 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1744 conv->dreg = ins->dreg;
1749 case OP_FCALL_MEMBASE: {
1750 MonoCallInst *call = (MonoCallInst*)ins;
1751 if (call->signature->ret->type == MONO_TYPE_R4) {
1752 MonoCallInst *call2;
1753 MonoInst *iargs [1];
1757 /* Convert the call into a call returning an int */
1758 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1759 memcpy (call2, call, sizeof (MonoCallInst));
1760 switch (ins->opcode) {
1762 call2->inst.opcode = OP_CALL;
1765 call2->inst.opcode = OP_CALL_REG;
1767 case OP_FCALL_MEMBASE:
1768 call2->inst.opcode = OP_CALL_MEMBASE;
1771 g_assert_not_reached ();
1773 call2->inst.dreg = mono_alloc_ireg (cfg);
1774 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1776 /* Remap OUTARG_VT instructions referencing this call */
1777 for (l = call->outarg_vts; l; l = l->next)
1778 ((MonoInst*)(l->data))->inst_p0 = call2;
1780 /* FIXME: Optimize this */
1782 /* Emit an r4->r8 conversion */
1783 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1784 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1785 conv->dreg = ins->dreg;
1787 /* The call sequence might include fp ins */
1790 switch (ins->opcode) {
1792 ins->opcode = OP_LCALL;
1795 ins->opcode = OP_LCALL_REG;
1797 case OP_FCALL_MEMBASE:
1798 ins->opcode = OP_LCALL_MEMBASE;
1801 g_assert_not_reached ();
1807 MonoJitICallInfo *info;
1808 MonoInst *iargs [2];
1809 MonoInst *call, *cmp, *br;
1811 /* Convert fcompare+fbcc to icall+icompare+beq */
1814 /* The branch might be optimized away */
1819 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1821 /* The branch might be optimized away */
1826 /* Create dummy MonoInst's for the arguments */
1827 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1828 iargs [0]->dreg = ins->sreg1;
1829 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1830 iargs [1]->dreg = ins->sreg2;
1832 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1834 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1835 cmp->sreg1 = call->dreg;
1837 MONO_ADD_INS (cfg->cbb, cmp);
1839 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1840 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1841 br->inst_true_bb = ins->next->inst_true_bb;
1842 br->inst_false_bb = ins->next->inst_false_bb;
1843 MONO_ADD_INS (cfg->cbb, br);
1845 /* The call sequence might include fp ins */
1848 /* Skip fbcc or fccc */
1849 NULLIFY_INS (ins->next);
1857 MonoJitICallInfo *info;
1858 MonoInst *iargs [2];
1861 /* Convert fccc to icall+icompare+iceq */
1863 info = mono_find_jit_opcode_emulation (ins->opcode);
1866 /* Create dummy MonoInst's for the arguments */
1867 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1868 iargs [0]->dreg = ins->sreg1;
1869 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1870 iargs [1]->dreg = ins->sreg2;
1872 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1874 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1875 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1877 /* The call sequence might include fp ins */
1882 MonoInst *iargs [2];
1883 MonoInst *call, *cmp;
1885 /* Convert to icall+icompare+cond_exc+move */
1887 /* Create dummy MonoInst's for the arguments */
1888 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1889 iargs [0]->dreg = ins->sreg1;
1891 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1893 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1894 cmp->sreg1 = call->dreg;
1896 MONO_ADD_INS (cfg->cbb, cmp);
1898 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1900 /* Do the assignment if the value is finite */
1901 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1907 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1908 mono_print_ins (ins);
1909 g_assert_not_reached ();
1914 g_assert (cfg->cbb == first_bb);
1916 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1917 /* Replace the original instruction with the new code sequence */
1919 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1920 first_bb->code = first_bb->last_ins = NULL;
1921 first_bb->in_count = first_bb->out_count = 0;
1922 cfg->cbb = first_bb;
1929 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1932 mono_decompose_long_opts (cfg);
1937 #endif /* DISABLE_JIT */