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 = bb->code;
633 MonoInst *prev = NULL;
636 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
640 cfg->cbb->code = cfg->cbb->last_ins = NULL;
644 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
645 mono_arch_decompose_long_opts (cfg, tree);
648 switch (tree->opcode) {
650 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
651 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
653 case OP_DUMMY_I8CONST:
654 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 1, OP_DUMMY_ICONST);
655 MONO_EMIT_NEW_DUMMY_INIT (cfg, tree->dreg + 2, OP_DUMMY_ICONST);
660 case OP_LCONV_TO_OVF_U8_UN:
661 case OP_LCONV_TO_OVF_I8:
662 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
663 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
665 case OP_STOREI8_MEMBASE_REG:
666 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
667 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
669 case OP_LOADI8_MEMBASE:
670 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
671 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
674 case OP_ICONV_TO_I8: {
675 guint32 tmpreg = alloc_ireg (cfg);
679 * tmp = low > -1 ? 1: 0;
680 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
682 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
683 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
684 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
685 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
689 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
690 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
692 case OP_ICONV_TO_OVF_I8:
693 /* a signed 32 bit num always fits in a signed 64 bit one */
694 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
695 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
697 case OP_ICONV_TO_OVF_U8:
698 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
699 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
700 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
701 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
703 case OP_ICONV_TO_OVF_I8_UN:
704 case OP_ICONV_TO_OVF_U8_UN:
705 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
706 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
707 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
710 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
713 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
716 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
719 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
725 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
728 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
731 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
733 case OP_LCONV_TO_R_UN:
734 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
736 case OP_LCONV_TO_OVF_I1: {
737 MonoBasicBlock *is_negative, *end_label;
739 NEW_BBLOCK (cfg, is_negative);
740 NEW_BBLOCK (cfg, end_label);
742 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
743 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
744 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
745 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
747 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
748 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
751 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
752 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
753 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
756 MONO_START_BB (cfg, is_negative);
757 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
758 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
760 MONO_START_BB (cfg, end_label);
762 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
765 case OP_LCONV_TO_OVF_I1_UN:
766 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
767 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
769 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
770 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
771 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
772 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
773 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
775 case OP_LCONV_TO_OVF_U1:
776 case OP_LCONV_TO_OVF_U1_UN:
777 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
778 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
780 /* probe value to be within 0 to 255 */
781 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
782 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
783 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
785 case OP_LCONV_TO_OVF_I2: {
786 MonoBasicBlock *is_negative, *end_label;
788 NEW_BBLOCK (cfg, is_negative);
789 NEW_BBLOCK (cfg, end_label);
791 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
792 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
793 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
794 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
796 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
797 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
800 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
801 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
802 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
805 MONO_START_BB (cfg, is_negative);
806 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
807 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
808 MONO_START_BB (cfg, end_label);
810 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
813 case OP_LCONV_TO_OVF_I2_UN:
814 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
815 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
817 /* Probe value to be within -32768 and 32767 */
818 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
819 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
820 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
821 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
822 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
824 case OP_LCONV_TO_OVF_U2:
825 case OP_LCONV_TO_OVF_U2_UN:
826 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
827 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
829 /* Probe value to be within 0 and 65535 */
830 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
831 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
832 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
834 case OP_LCONV_TO_OVF_I4:
835 case OP_LCONV_TO_OVF_I:
836 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
838 case OP_LCONV_TO_OVF_U4:
839 case OP_LCONV_TO_OVF_U:
840 case OP_LCONV_TO_OVF_U4_UN:
841 case OP_LCONV_TO_OVF_U_UN:
842 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
843 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
844 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
846 case OP_LCONV_TO_OVF_I_UN:
847 case OP_LCONV_TO_OVF_I4_UN:
848 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
849 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
850 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
851 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
852 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
854 case OP_LCONV_TO_OVF_U8:
855 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
856 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
858 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
859 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
861 case OP_LCONV_TO_OVF_I8_UN:
862 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
863 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
865 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
866 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
870 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
871 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
874 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
875 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
879 /* ADC sets the condition code */
880 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
881 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
882 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
885 /* ADC sets the condition code */
886 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
887 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
888 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
891 /* SBB sets the condition code */
892 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
893 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
894 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
897 /* SBB sets the condition code */
898 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
899 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
900 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
903 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
904 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
907 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
908 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
911 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
912 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
915 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
916 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
919 /* Handled in mono_arch_decompose_long_opts () */
920 g_assert_not_reached ();
924 /* FIXME: Add OP_BIGMUL optimization */
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
932 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
936 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
937 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
940 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
944 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
945 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
948 if (tree->inst_c1 == 32) {
950 /* The original code had this comment: */
951 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
952 * later apply the speedup to the left shift as well
955 /* FIXME: Move this to the strength reduction pass */
956 /* just move the upper half to the lower and zero the high word */
957 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
958 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
962 if (tree->inst_c1 == 32) {
963 /* just move the lower half to the upper and zero the lower word */
964 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
965 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
970 MonoInst *next = tree->next;
974 switch (next->opcode) {
979 /* Branchless version based on gcc code */
980 d1 = alloc_ireg (cfg);
981 d2 = alloc_ireg (cfg);
982 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
983 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
984 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
985 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
986 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
998 /* Convert into three comparisons + branches */
999 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1000 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1001 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1002 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1003 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
1004 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1010 /* Branchless version based on gcc code */
1011 d1 = alloc_ireg (cfg);
1012 d2 = alloc_ireg (cfg);
1013 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
1014 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
1015 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1017 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1018 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1026 MonoBasicBlock *set_to_0, *set_to_1;
1028 NEW_BBLOCK (cfg, set_to_0);
1029 NEW_BBLOCK (cfg, set_to_1);
1031 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1032 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1033 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1034 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
1035 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1036 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
1037 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1038 MONO_START_BB (cfg, set_to_1);
1039 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1040 MONO_START_BB (cfg, set_to_0);
1045 g_assert_not_reached ();
1050 /* Not yet used, since lcompare is decomposed before local cprop */
1051 case OP_LCOMPARE_IMM: {
1052 MonoInst *next = tree->next;
1053 guint32 low_imm = tree->inst_ls_word;
1054 guint32 high_imm = tree->inst_ms_word;
1055 int low_reg = tree->sreg1 + 1;
1056 int high_reg = tree->sreg1 + 2;
1060 switch (next->opcode) {
1065 /* Branchless version based on gcc code */
1066 d1 = alloc_ireg (cfg);
1067 d2 = alloc_ireg (cfg);
1068 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1069 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1070 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1071 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1072 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1085 /* Convert into three comparisons + branches */
1086 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1087 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1088 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1089 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1090 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1091 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1097 /* Branchless version based on gcc code */
1098 d1 = alloc_ireg (cfg);
1099 d2 = alloc_ireg (cfg);
1100 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1101 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1102 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1104 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1105 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1113 MonoBasicBlock *set_to_0, *set_to_1;
1115 NEW_BBLOCK (cfg, set_to_0);
1116 NEW_BBLOCK (cfg, set_to_1);
1118 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1119 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1120 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1121 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1122 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1123 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1124 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1125 MONO_START_BB (cfg, set_to_1);
1126 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1127 MONO_START_BB (cfg, set_to_0);
1132 g_assert_not_reached ();
1141 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1144 /* Replace the original instruction with the new code sequence */
1146 /* Ignore the new value of prev */
1148 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1150 /* Process the newly added ops again since they can be long ops too */
1156 first_bb->code = first_bb->last_ins = NULL;
1157 first_bb->in_count = first_bb->out_count = 0;
1158 cfg->cbb = first_bb;
1169 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1170 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1175 * mono_decompose_vtype_opts:
1177 * Decompose valuetype opcodes.
1180 mono_decompose_vtype_opts (MonoCompile *cfg)
1182 MonoBasicBlock *bb, *first_bb;
1185 * Using OP_V opcodes and decomposing them later have two main benefits:
1186 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1188 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1189 * enabling optimizations to work on vtypes too.
1190 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1191 * can be executed anytime. It should be executed as late as possible so vtype
1192 * opcodes can be optimized by the other passes.
1193 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1194 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1196 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1197 * when OP_VMOVE opcodes are decomposed.
1201 * Vregs have no associated type information, so we store the type of the vregs
1206 * Create a dummy bblock and emit code into it so we can use the normal
1207 * code generation macros.
1209 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1210 first_bb = cfg->cbb;
1212 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1214 MonoInst *prev = NULL;
1215 MonoInst *src_var, *dest_var, *src, *dest;
1219 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1221 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1227 for (ins = bb->code; ins; ins = ins->next) {
1229 #ifdef MONO_ARCH_HAVE_DECOMPOSE_VTYPE_OPTS
1230 // Try the architecture specific vtype decomposition first. If that handles the
1231 // decomposition for this instruction, then nothing more needs to be done here.
1232 if (!mono_arch_decompose_vtype_opts (cfg, ins, bb))
1235 switch (ins->opcode) {
1237 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1238 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1240 g_assert (ins->klass);
1243 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1246 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1249 if (src_var->backend.is_pinvoke)
1250 dest_var->backend.is_pinvoke = 1;
1252 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1253 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1255 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1259 g_assert (ins->klass);
1261 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1262 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1264 if (cfg->compute_gc_maps) {
1268 * Tell the GC map code that the vtype is considered live after
1269 * the initialization.
1271 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1272 tmp->inst_c1 = ins->dreg;
1273 MONO_ADD_INS (cfg->cbb, tmp);
1276 case OP_DUMMY_VZERO:
1279 case OP_STOREV_MEMBASE: {
1280 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1283 g_assert (ins->klass);
1284 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1287 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1289 dreg = alloc_preg (cfg);
1290 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1291 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1294 case OP_LOADV_MEMBASE: {
1295 g_assert (ins->klass);
1297 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1301 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1303 dreg = alloc_preg (cfg);
1304 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1305 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1306 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1309 case OP_OUTARG_VT: {
1310 g_assert (ins->klass);
1312 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1314 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1315 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1317 mono_arch_emit_outarg_vt (cfg, ins, src);
1319 /* This might be decomposed into other vtype opcodes */
1323 case OP_OUTARG_VTRETADDR: {
1324 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1326 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1328 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1329 // FIXME: src_var->backend.is_pinvoke ?
1331 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1332 src->dreg = ins->dreg;
1337 case OP_VCALL_MEMBASE: {
1338 MonoCallInst *call = (MonoCallInst*)ins;
1341 if (call->vret_in_reg) {
1342 MonoCallInst *call2;
1344 /* Replace the vcall with a scalar call */
1345 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1346 memcpy (call2, call, sizeof (MonoCallInst));
1347 switch (ins->opcode) {
1349 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1352 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1354 case OP_VCALL_MEMBASE:
1355 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1358 call2->inst.dreg = alloc_preg (cfg);
1359 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1361 /* Compute the vtype location */
1362 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1364 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1365 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1367 /* Save the result */
1368 if (dest_var->backend.is_pinvoke)
1369 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1371 size = mono_type_size (dest_var->inst_vtype, NULL);
1374 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1377 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1381 if (call->vret_in_reg_fp)
1382 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1384 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1390 if (call->vret_in_reg_fp) {
1391 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1394 #if SIZEOF_REGISTER == 4
1396 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1397 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1399 switch (call2->inst.opcode) {
1401 call2->inst.opcode = OP_LCALL;
1404 call2->inst.opcode = OP_LCALL_REG;
1406 case OP_CALL_MEMBASE:
1407 call2->inst.opcode = OP_LCALL_MEMBASE;
1410 call2->inst.dreg = alloc_lreg (cfg);
1411 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1412 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1414 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1418 /* This assumes the vtype is sizeof (gpointer) long */
1419 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1423 switch (ins->opcode) {
1425 ins->opcode = OP_VCALL2;
1428 ins->opcode = OP_VCALL2_REG;
1430 case OP_VCALL_MEMBASE:
1431 ins->opcode = OP_VCALL2_MEMBASE;
1442 g_assert (cfg->cbb == first_bb);
1444 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1445 /* Replace the original instruction with the new code sequence */
1447 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1448 first_bb->code = first_bb->last_ins = NULL;
1449 first_bb->in_count = first_bb->out_count = 0;
1450 cfg->cbb = first_bb;
1457 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1462 mono_decompose_vtype_opts_llvm (MonoCompile *cfg)
1464 MonoBasicBlock *bb, *first_bb;
1466 /* Decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers */
1468 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1469 first_bb = cfg->cbb;
1471 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1473 MonoInst *prev = NULL;
1474 MonoInst *src_var, *src, *dest;
1478 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS(LLVM) ");
1480 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1486 for (ins = bb->code; ins; ins = ins->next) {
1487 switch (ins->opcode) {
1488 case OP_STOREV_MEMBASE: {
1489 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1492 g_assert (ins->klass);
1493 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1496 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1498 dreg = alloc_preg (cfg);
1499 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1500 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1507 g_assert (cfg->cbb == first_bb);
1509 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1510 /* Replace the original instruction with the new code sequence */
1512 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1513 first_bb->code = first_bb->last_ins = NULL;
1514 first_bb->in_count = first_bb->out_count = 0;
1515 cfg->cbb = first_bb;
1522 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS(LLVM) ");
1526 inline static MonoInst *
1527 mono_get_domainvar (MonoCompile *cfg)
1529 if (!cfg->domainvar)
1530 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1531 return cfg->domainvar;
1535 * mono_decompose_array_access_opts:
1537 * Decompose array access opcodes.
1540 mono_decompose_array_access_opts (MonoCompile *cfg)
1542 MonoBasicBlock *bb, *first_bb;
1545 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1546 * can be executed anytime. It should be run before decompose_long
1550 * Create a dummy bblock and emit code into it so we can use the normal
1551 * code generation macros.
1553 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1554 first_bb = cfg->cbb;
1556 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1558 MonoInst *prev = NULL;
1560 MonoInst *iargs [3];
1563 if (!bb->has_array_access)
1566 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1568 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1574 for (ins = bb->code; ins; ins = ins->next) {
1575 switch (ins->opcode) {
1577 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1578 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1579 MONO_ADD_INS (cfg->cbb, dest);
1581 case OP_BOUNDS_CHECK:
1582 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1583 if (COMPILE_LLVM (cfg))
1584 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1586 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1589 if (cfg->opt & MONO_OPT_SHARED) {
1590 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1591 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1592 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1593 iargs [2]->dreg = ins->sreg1;
1595 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1596 dest->dreg = ins->dreg;
1598 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1599 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1600 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1602 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1603 NEW_VTABLECONST (cfg, iargs [0], vtable);
1604 MONO_ADD_INS (cfg->cbb, iargs [0]);
1605 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1606 iargs [1]->dreg = ins->sreg1;
1609 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1611 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1612 dest->dreg = ins->dreg;
1616 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1617 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1623 g_assert (cfg->cbb == first_bb);
1625 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1626 /* Replace the original instruction with the new code sequence */
1628 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1629 first_bb->code = first_bb->last_ins = NULL;
1630 first_bb->in_count = first_bb->out_count = 0;
1631 cfg->cbb = first_bb;
1638 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1648 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1651 * mono_decompose_soft_float:
1653 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1654 * similar to long support on 32 bit platforms. 32 bit float values require special
1655 * handling when used as locals, arguments, and in calls.
1656 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1659 mono_decompose_soft_float (MonoCompile *cfg)
1661 MonoBasicBlock *bb, *first_bb;
1664 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1668 * Create a dummy bblock and emit code into it so we can use the normal
1669 * code generation macros.
1671 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1672 first_bb = cfg->cbb;
1674 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1676 MonoInst *prev = NULL;
1679 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1681 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1687 for (ins = bb->code; ins; ins = ins->next) {
1688 const char *spec = INS_INFO (ins->opcode);
1690 /* Most fp operations are handled automatically by opcode emulation */
1692 switch (ins->opcode) {
1695 d.vald = *(double*)ins->inst_p0;
1696 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1701 /* We load the r8 value */
1702 d.vald = *(float*)ins->inst_p0;
1703 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1707 ins->opcode = OP_LMOVE;
1710 ins->opcode = OP_MOVE;
1711 ins->sreg1 = ins->sreg1 + 1;
1714 ins->opcode = OP_MOVE;
1715 ins->sreg1 = ins->sreg1 + 2;
1718 int reg = ins->sreg1;
1720 ins->opcode = OP_SETLRET;
1722 ins->sreg1 = reg + 1;
1723 ins->sreg2 = reg + 2;
1726 case OP_LOADR8_MEMBASE:
1727 ins->opcode = OP_LOADI8_MEMBASE;
1729 case OP_STORER8_MEMBASE_REG:
1730 ins->opcode = OP_STOREI8_MEMBASE_REG;
1732 case OP_STORER4_MEMBASE_REG: {
1733 MonoInst *iargs [2];
1736 /* Arg 1 is the double value */
1737 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1738 iargs [0]->dreg = ins->sreg1;
1740 /* Arg 2 is the address to store to */
1741 addr_reg = mono_alloc_preg (cfg);
1742 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1743 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1747 case OP_LOADR4_MEMBASE: {
1748 MonoInst *iargs [1];
1752 addr_reg = mono_alloc_preg (cfg);
1753 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1754 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1755 conv->dreg = ins->dreg;
1760 case OP_FCALL_MEMBASE: {
1761 MonoCallInst *call = (MonoCallInst*)ins;
1762 if (call->signature->ret->type == MONO_TYPE_R4) {
1763 MonoCallInst *call2;
1764 MonoInst *iargs [1];
1768 /* Convert the call into a call returning an int */
1769 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1770 memcpy (call2, call, sizeof (MonoCallInst));
1771 switch (ins->opcode) {
1773 call2->inst.opcode = OP_CALL;
1776 call2->inst.opcode = OP_CALL_REG;
1778 case OP_FCALL_MEMBASE:
1779 call2->inst.opcode = OP_CALL_MEMBASE;
1782 g_assert_not_reached ();
1784 call2->inst.dreg = mono_alloc_ireg (cfg);
1785 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1787 /* Remap OUTARG_VT instructions referencing this call */
1788 for (l = call->outarg_vts; l; l = l->next)
1789 ((MonoInst*)(l->data))->inst_p0 = call2;
1791 /* FIXME: Optimize this */
1793 /* Emit an r4->r8 conversion */
1794 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1795 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1796 conv->dreg = ins->dreg;
1798 /* The call sequence might include fp ins */
1801 switch (ins->opcode) {
1803 ins->opcode = OP_LCALL;
1806 ins->opcode = OP_LCALL_REG;
1808 case OP_FCALL_MEMBASE:
1809 ins->opcode = OP_LCALL_MEMBASE;
1812 g_assert_not_reached ();
1818 MonoJitICallInfo *info;
1819 MonoInst *iargs [2];
1820 MonoInst *call, *cmp, *br;
1822 /* Convert fcompare+fbcc to icall+icompare+beq */
1825 /* The branch might be optimized away */
1830 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1832 /* The branch might be optimized away */
1837 /* Create dummy MonoInst's for the arguments */
1838 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1839 iargs [0]->dreg = ins->sreg1;
1840 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1841 iargs [1]->dreg = ins->sreg2;
1843 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1845 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1846 cmp->sreg1 = call->dreg;
1848 MONO_ADD_INS (cfg->cbb, cmp);
1850 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1851 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1852 br->inst_true_bb = ins->next->inst_true_bb;
1853 br->inst_false_bb = ins->next->inst_false_bb;
1854 MONO_ADD_INS (cfg->cbb, br);
1856 /* The call sequence might include fp ins */
1859 /* Skip fbcc or fccc */
1860 NULLIFY_INS (ins->next);
1868 MonoJitICallInfo *info;
1869 MonoInst *iargs [2];
1872 /* Convert fccc to icall+icompare+iceq */
1874 info = mono_find_jit_opcode_emulation (ins->opcode);
1877 /* Create dummy MonoInst's for the arguments */
1878 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1879 iargs [0]->dreg = ins->sreg1;
1880 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1881 iargs [1]->dreg = ins->sreg2;
1883 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1885 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1886 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1888 /* The call sequence might include fp ins */
1893 MonoInst *iargs [2];
1894 MonoInst *call, *cmp;
1896 /* Convert to icall+icompare+cond_exc+move */
1898 /* Create dummy MonoInst's for the arguments */
1899 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1900 iargs [0]->dreg = ins->sreg1;
1902 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1904 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1905 cmp->sreg1 = call->dreg;
1907 MONO_ADD_INS (cfg->cbb, cmp);
1909 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1911 /* Do the assignment if the value is finite */
1912 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1918 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1919 mono_print_ins (ins);
1920 g_assert_not_reached ();
1925 g_assert (cfg->cbb == first_bb);
1927 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1928 /* Replace the original instruction with the new code sequence */
1930 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1931 first_bb->code = first_bb->last_ins = NULL;
1932 first_bb->in_count = first_bb->out_count = 0;
1933 cfg->cbb = first_bb;
1940 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1943 mono_decompose_long_opts (cfg);
1948 #endif /* DISABLE_JIT */