2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13 #include "jit-icalls.h"
15 #include <mono/metadata/gc-internals.h>
16 #include <mono/metadata/abi-details.h>
20 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
21 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
22 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
23 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
26 * Decompose complex long opcodes on 64 bit machines.
27 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
30 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
32 MonoInst *repl = NULL;
36 switch (ins->opcode) {
38 ins->opcode = OP_SEXT_I4;
42 if (SIZEOF_VOID_P == 4)
43 ins->opcode = OP_LMOVE;
45 ins->opcode = OP_MOVE;
48 if (SIZEOF_VOID_P == 4)
50 ins->opcode = OP_SEXT_I4;
52 ins->opcode = OP_MOVE;
55 if (SIZEOF_VOID_P == 4) {
57 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
60 ins->opcode = OP_MOVE;
64 ins->opcode = OP_SEXT_I4;
67 ins->opcode = OP_ZEXT_I4;
70 /* Clean out the upper word */
71 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
77 if (COMPILE_LLVM (cfg))
79 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
83 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
84 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
88 case OP_LADD_OVF_UN: {
91 if (COMPILE_LLVM (cfg))
93 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
97 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
98 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
102 #ifndef __mono_ppc64__
106 if (COMPILE_LLVM (cfg))
108 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
112 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
113 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
117 case OP_LSUB_OVF_UN: {
120 if (COMPILE_LLVM (cfg))
122 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
126 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
127 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
133 case OP_ICONV_TO_OVF_I8:
134 case OP_ICONV_TO_OVF_I:
135 ins->opcode = OP_SEXT_I4;
137 case OP_ICONV_TO_OVF_U8:
138 case OP_ICONV_TO_OVF_U:
139 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
140 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
141 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
144 case OP_ICONV_TO_OVF_I8_UN:
145 case OP_ICONV_TO_OVF_U8_UN:
146 case OP_ICONV_TO_OVF_I_UN:
147 case OP_ICONV_TO_OVF_U_UN:
148 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
149 /* Clean out the upper word */
150 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
153 case OP_LCONV_TO_OVF_I1:
154 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
155 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
156 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
157 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
158 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
161 case OP_LCONV_TO_OVF_I1_UN:
162 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
163 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
164 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
167 case OP_LCONV_TO_OVF_U1:
168 /* probe value to be within 0 to 255 */
169 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
170 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
171 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
174 case OP_LCONV_TO_OVF_U1_UN:
175 /* probe value to be within 0 to 255 */
176 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
177 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
178 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
181 case OP_LCONV_TO_OVF_I2:
182 /* Probe value to be within -32768 and 32767 */
183 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
184 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
185 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
186 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
187 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
190 case OP_LCONV_TO_OVF_I2_UN:
191 /* Probe value to be within 0 and 32767 */
192 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
193 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
194 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
197 case OP_LCONV_TO_OVF_U2:
198 /* Probe value to be within 0 and 65535 */
199 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
200 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
201 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
204 case OP_LCONV_TO_OVF_U2_UN:
205 /* Probe value to be within 0 and 65535 */
206 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
207 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
208 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
211 case OP_LCONV_TO_OVF_I4:
212 #if SIZEOF_VOID_P == 4
213 case OP_LCONV_TO_OVF_I:
215 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
216 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
217 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
218 #if SIZEOF_REGISTER == 8
219 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
221 g_assert (COMPILE_LLVM (cfg));
222 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
224 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
225 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
228 case OP_LCONV_TO_OVF_I4_UN:
229 #if SIZEOF_VOID_P == 4
230 case OP_LCONV_TO_OVF_I_UN:
232 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
233 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
234 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
237 case OP_LCONV_TO_OVF_U4:
238 #if SIZEOF_VOID_P == 4
239 case OP_LCONV_TO_OVF_U:
241 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
242 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
243 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
244 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
245 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
248 case OP_LCONV_TO_OVF_U4_UN:
249 #if SIZEOF_VOID_P == 4
250 case OP_LCONV_TO_OVF_U_UN:
252 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
253 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
254 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
257 #if SIZEOF_VOID_P == 8
258 case OP_LCONV_TO_OVF_I:
259 case OP_LCONV_TO_OVF_U_UN:
261 case OP_LCONV_TO_OVF_U8_UN:
262 case OP_LCONV_TO_OVF_I8:
263 ins->opcode = OP_MOVE;
265 #if SIZEOF_VOID_P == 8
266 case OP_LCONV_TO_OVF_I_UN:
268 case OP_LCONV_TO_OVF_I8_UN:
269 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
270 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
271 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
274 case OP_LCONV_TO_OVF_U8:
275 #if SIZEOF_VOID_P == 8
276 case OP_LCONV_TO_OVF_U:
278 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
279 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
280 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
292 * mono_decompose_opcode:
294 * Decompose complex opcodes into ones closer to opcodes supported by
295 * the given architecture.
296 * Returns a MonoInst which represents the result of the decomposition, and can
297 * be pushed on the IL stack. This is needed because the original instruction is
299 * Sets the cfg exception if an opcode is not supported.
302 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
304 MonoInst *repl = NULL;
305 int type = ins->type;
306 int dreg = ins->dreg;
307 gboolean emulate = FALSE;
309 /* FIXME: Instead of = NOP, don't emit the original ins at all */
310 mono_arch_decompose_opts (cfg, ins);
313 * The code below assumes that we are called immediately after emitting
314 * ins. This means we can emit code using the normal code generation
317 switch (ins->opcode) {
318 /* this doesn't make sense on ppc and other architectures */
319 #if !defined(MONO_ARCH_NO_IOV_CHECK)
321 if (COMPILE_LLVM (cfg))
323 ins->opcode = OP_IADDCC;
324 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
327 if (COMPILE_LLVM (cfg))
329 ins->opcode = OP_IADDCC;
330 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
333 if (COMPILE_LLVM (cfg))
335 ins->opcode = OP_ISUBCC;
336 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
339 if (COMPILE_LLVM (cfg))
341 ins->opcode = OP_ISUBCC;
342 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
345 case OP_ICONV_TO_OVF_I1:
346 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
347 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
348 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
349 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
350 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
353 case OP_ICONV_TO_OVF_I1_UN:
354 /* probe values between 0 to 127 */
355 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
356 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
357 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
360 case OP_ICONV_TO_OVF_U1:
361 case OP_ICONV_TO_OVF_U1_UN:
362 /* probe value to be within 0 to 255 */
363 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
364 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
365 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
368 case OP_ICONV_TO_OVF_I2:
369 /* Probe value to be within -32768 and 32767 */
370 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
371 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
372 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
373 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
374 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
377 case OP_ICONV_TO_OVF_I2_UN:
378 /* Convert uint value into short, value within 0 and 32767 */
379 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
380 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
381 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
384 case OP_ICONV_TO_OVF_U2:
385 case OP_ICONV_TO_OVF_U2_UN:
386 /* Probe value to be within 0 and 65535 */
387 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
388 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
389 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
392 case OP_ICONV_TO_OVF_U4:
393 case OP_ICONV_TO_OVF_I4_UN:
394 #if SIZEOF_VOID_P == 4
395 case OP_ICONV_TO_OVF_U:
396 case OP_ICONV_TO_OVF_I_UN:
398 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
399 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
400 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
405 case OP_ICONV_TO_OVF_I4:
406 case OP_ICONV_TO_OVF_U4_UN:
407 #if SIZEOF_VOID_P == 4
408 case OP_ICONV_TO_OVF_I:
409 case OP_ICONV_TO_OVF_U_UN:
411 ins->opcode = OP_MOVE;
414 #if SIZEOF_VOID_P == 8
415 ins->opcode = OP_SEXT_I4;
417 ins->opcode = OP_MOVE;
421 #if SIZEOF_VOID_P == 8
422 ins->opcode = OP_ZEXT_I4;
424 ins->opcode = OP_MOVE;
429 ins->opcode = OP_FMOVE;
432 case OP_FCONV_TO_OVF_I1_UN:
433 case OP_FCONV_TO_OVF_I2_UN:
434 case OP_FCONV_TO_OVF_I4_UN:
435 case OP_FCONV_TO_OVF_I8_UN:
436 case OP_FCONV_TO_OVF_U1_UN:
437 case OP_FCONV_TO_OVF_U2_UN:
438 case OP_FCONV_TO_OVF_U4_UN:
439 case OP_FCONV_TO_OVF_U8_UN:
440 case OP_FCONV_TO_OVF_I_UN:
441 case OP_FCONV_TO_OVF_U_UN:
442 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
449 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
452 if (cfg->backend->need_div_check) {
453 int reg1 = alloc_ireg (cfg);
454 int reg2 = alloc_ireg (cfg);
456 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
457 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
458 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
459 /* b == -1 && a == 0x80000000 */
460 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
461 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
463 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
464 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
465 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
466 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
469 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
478 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
481 if (cfg->backend->need_div_check) {
482 int reg1 = alloc_ireg (cfg);
483 int reg2 = alloc_ireg (cfg);
484 int reg3 = alloc_ireg (cfg);
486 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
487 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
488 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
489 /* b == -1 && a == 0x80000000 */
490 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
491 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
492 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
493 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
494 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
495 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
496 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
497 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
498 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
501 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
511 if (cfg->backend->need_div_check) {
512 int reg1 = alloc_ireg (cfg);
514 if (ins->inst_imm == 0) {
515 // FIXME: Optimize this
516 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
517 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
518 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
520 if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
521 (ins->inst_imm == -1)) {
522 /* b == -1 && a == 0x80000000 */
523 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
524 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
526 MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
539 #if SIZEOF_REGISTER == 8
540 if (decompose_long_opcode (cfg, ins, &repl))
543 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
547 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
548 cfg->has_emulated_ops = TRUE;
551 if (ins->opcode == OP_NOP) {
556 /* Use the last emitted instruction */
557 ins = cfg->cbb->last_ins;
560 g_assert (ins->dreg == dreg);
568 #if SIZEOF_REGISTER == 4
569 static int lbr_decomp [][2] = {
571 {OP_IBGT, OP_IBGE_UN}, /* BGE */
572 {OP_IBGT, OP_IBGT_UN}, /* BGT */
573 {OP_IBLT, OP_IBLE_UN}, /* BLE */
574 {OP_IBLT, OP_IBLT_UN}, /* BLT */
576 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
577 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
578 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
579 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
582 static int lcset_decomp [][2] = {
584 {OP_IBLT, OP_IBLE_UN}, /* CGT */
585 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
586 {OP_IBGT, OP_IBGE_UN}, /* CLT */
587 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
592 * mono_decompose_long_opts:
594 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
597 mono_decompose_long_opts (MonoCompile *cfg)
599 #if SIZEOF_REGISTER == 4
600 MonoBasicBlock *bb, *first_bb;
603 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
604 * needs to be able to handle long vregs.
608 * Create a dummy bblock and emit code into it so we can use the normal
609 * code generation macros.
611 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
614 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
615 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
616 MonoInst *prev = NULL;
619 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
622 cfg->cbb->code = cfg->cbb->last_ins = NULL;
625 mono_arch_decompose_long_opts (cfg, tree);
627 switch (tree->opcode) {
629 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
630 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
632 case OP_DUMMY_I8CONST:
633 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
634 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
639 case OP_LCONV_TO_OVF_U8_UN:
640 case OP_LCONV_TO_OVF_I8:
641 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
642 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
644 case OP_STOREI8_MEMBASE_REG:
645 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (tree->sreg1));
646 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (tree->sreg1));
648 case OP_LOADI8_MEMBASE:
649 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_MS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
650 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_LS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
653 case OP_ICONV_TO_I8: {
654 guint32 tmpreg = alloc_ireg (cfg);
658 * tmp = low > -1 ? 1: 0;
659 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
661 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
662 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
663 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
664 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
668 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
669 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
671 case OP_ICONV_TO_OVF_I8:
672 /* a signed 32 bit num always fits in a signed 64 bit one */
673 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
674 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
676 case OP_ICONV_TO_OVF_U8:
677 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
678 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
679 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
680 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
682 case OP_ICONV_TO_OVF_I8_UN:
683 case OP_ICONV_TO_OVF_U8_UN:
684 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
685 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
686 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
689 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
692 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
695 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
698 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
704 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
706 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
708 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
711 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
713 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
716 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
717 case OP_LCONV_TO_R_UN:
718 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
721 case OP_LCONV_TO_OVF_I1: {
722 MonoBasicBlock *is_negative, *end_label;
724 NEW_BBLOCK (cfg, is_negative);
725 NEW_BBLOCK (cfg, end_label);
727 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
728 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
729 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
730 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
732 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
733 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
736 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
737 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
738 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
741 MONO_START_BB (cfg, is_negative);
742 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
743 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
745 MONO_START_BB (cfg, end_label);
747 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
750 case OP_LCONV_TO_OVF_I1_UN:
751 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
752 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
754 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
755 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
756 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
757 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
758 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
760 case OP_LCONV_TO_OVF_U1:
761 case OP_LCONV_TO_OVF_U1_UN:
762 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
763 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
765 /* probe value to be within 0 to 255 */
766 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
767 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
768 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
770 case OP_LCONV_TO_OVF_I2: {
771 MonoBasicBlock *is_negative, *end_label;
773 NEW_BBLOCK (cfg, is_negative);
774 NEW_BBLOCK (cfg, end_label);
776 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
777 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
778 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
779 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
782 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
785 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
786 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
787 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
790 MONO_START_BB (cfg, is_negative);
791 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
792 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
793 MONO_START_BB (cfg, end_label);
795 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
798 case OP_LCONV_TO_OVF_I2_UN:
799 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
800 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
802 /* Probe value to be within -32768 and 32767 */
803 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
804 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
805 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
806 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
807 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
809 case OP_LCONV_TO_OVF_U2:
810 case OP_LCONV_TO_OVF_U2_UN:
811 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
812 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
814 /* Probe value to be within 0 and 65535 */
815 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
816 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
817 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
819 case OP_LCONV_TO_OVF_I4:
820 case OP_LCONV_TO_OVF_I:
821 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
823 case OP_LCONV_TO_OVF_U4:
824 case OP_LCONV_TO_OVF_U:
825 case OP_LCONV_TO_OVF_U4_UN:
826 case OP_LCONV_TO_OVF_U_UN:
827 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
828 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
829 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
831 case OP_LCONV_TO_OVF_I_UN:
832 case OP_LCONV_TO_OVF_I4_UN:
833 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
834 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
835 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
836 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
837 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
839 case OP_LCONV_TO_OVF_U8:
840 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
841 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
843 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
844 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
846 case OP_LCONV_TO_OVF_I8_UN:
847 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
848 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
850 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
851 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
855 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
856 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
859 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
860 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
864 /* ADC sets the condition code */
865 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
866 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
867 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
870 /* ADC sets the condition code */
871 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
872 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
873 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
876 /* SBB sets the condition code */
877 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
878 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
879 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
882 /* SBB sets the condition code */
883 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
884 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
885 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
888 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
889 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
892 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
893 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
896 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
897 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
900 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
901 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
904 /* Handled in mono_arch_decompose_long_opts () */
905 g_assert_not_reached ();
909 /* FIXME: Add OP_BIGMUL optimization */
913 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
914 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
917 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
918 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
922 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
930 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
933 if (tree->inst_c1 == 32) {
935 /* The original code had this comment: */
936 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
937 * later apply the speedup to the left shift as well
940 /* FIXME: Move this to the strength reduction pass */
941 /* just move the upper half to the lower and zero the high word */
942 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
943 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
947 if (tree->inst_c1 == 32) {
948 /* just move the lower half to the upper and zero the lower word */
949 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
950 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
955 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
959 switch (next->opcode) {
964 /* Branchless version based on gcc code */
965 d1 = alloc_ireg (cfg);
966 d2 = alloc_ireg (cfg);
967 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
968 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
969 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
970 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
971 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
983 /* Convert into three comparisons + branches */
984 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
985 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
986 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
987 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
988 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
989 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
995 /* Branchless version based on gcc code */
996 d1 = alloc_ireg (cfg);
997 d2 = alloc_ireg (cfg);
998 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
999 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1000 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1002 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1003 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1011 MonoBasicBlock *set_to_0, *set_to_1;
1013 NEW_BBLOCK (cfg, set_to_0);
1014 NEW_BBLOCK (cfg, set_to_1);
1016 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1017 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1018 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1019 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1020 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1021 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1022 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1023 MONO_START_BB (cfg, set_to_1);
1024 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1025 MONO_START_BB (cfg, set_to_0);
1030 g_assert_not_reached ();
1035 /* Not yet used, since lcompare is decomposed before local cprop */
1036 case OP_LCOMPARE_IMM: {
1037 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1038 guint32 low_imm = tree->inst_ls_word;
1039 guint32 high_imm = tree->inst_ms_word;
1040 int low_reg = MONO_LVREG_LS (tree->sreg1);
1041 int high_reg = MONO_LVREG_MS (tree->sreg1);
1045 switch (next->opcode) {
1050 /* Branchless version based on gcc code */
1051 d1 = alloc_ireg (cfg);
1052 d2 = alloc_ireg (cfg);
1053 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1054 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1055 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1056 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1057 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1070 /* Convert into three comparisons + branches */
1071 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1072 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1073 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1074 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1075 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1076 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1082 /* Branchless version based on gcc code */
1083 d1 = alloc_ireg (cfg);
1084 d2 = alloc_ireg (cfg);
1085 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1086 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1087 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1089 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1090 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1098 MonoBasicBlock *set_to_0, *set_to_1;
1100 NEW_BBLOCK (cfg, set_to_0);
1101 NEW_BBLOCK (cfg, set_to_1);
1103 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1104 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1105 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1106 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1107 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1108 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1109 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1110 MONO_START_BB (cfg, set_to_1);
1111 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1112 MONO_START_BB (cfg, set_to_0);
1117 g_assert_not_reached ();
1126 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1129 /* Replace the original instruction with the new code sequence */
1131 /* Ignore the new value of prev */
1133 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1135 /* Process the newly added ops again since they can be long ops too */
1137 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1139 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1141 first_bb->code = first_bb->last_ins = NULL;
1142 first_bb->in_count = first_bb->out_count = 0;
1143 cfg->cbb = first_bb;
1147 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1154 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1155 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1160 * mono_decompose_vtype_opts:
1162 * Decompose valuetype opcodes.
1165 mono_decompose_vtype_opts (MonoCompile *cfg)
1167 MonoBasicBlock *bb, *first_bb;
1170 * Using OP_V opcodes and decomposing them later have two main benefits:
1171 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1173 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1174 * enabling optimizations to work on vtypes too.
1175 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1176 * can be executed anytime. It should be executed as late as possible so vtype
1177 * opcodes can be optimized by the other passes.
1178 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1179 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1181 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1182 * when OP_VMOVE opcodes are decomposed.
1186 * Vregs have no associated type information, so we store the type of the vregs
1191 * Create a dummy bblock and emit code into it so we can use the normal
1192 * code generation macros.
1194 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1195 first_bb = cfg->cbb;
1197 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1199 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1201 MonoInst *prev = NULL;
1202 MonoInst *src_var, *dest_var, *src, *dest;
1206 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1208 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1214 for (ins = bb->code; ins; ins = ins->next) {
1215 switch (ins->opcode) {
1217 g_assert (ins->klass);
1218 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1220 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1221 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1224 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1227 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1230 if (src_var->backend.is_pinvoke)
1231 dest_var->backend.is_pinvoke = 1;
1233 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1234 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1236 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1240 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1243 g_assert (ins->klass);
1245 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1246 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1248 if (cfg->compute_gc_maps) {
1252 * Tell the GC map code that the vtype is considered live after
1253 * the initialization.
1255 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1256 tmp->inst_c1 = ins->dreg;
1257 MONO_ADD_INS (cfg->cbb, tmp);
1260 case OP_DUMMY_VZERO:
1261 if (COMPILE_LLVM (cfg))
1266 case OP_STOREV_MEMBASE: {
1267 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1270 g_assert (ins->klass);
1271 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1274 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1276 dreg = alloc_preg (cfg);
1277 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1278 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1281 case OP_LOADV_MEMBASE: {
1282 g_assert (ins->klass);
1283 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (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 if (COMPILE_LLVM (cfg))
1302 g_assert (ins->klass);
1304 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1306 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1307 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1309 mono_arch_emit_outarg_vt (cfg, ins, src);
1311 /* This might be decomposed into other vtype opcodes */
1315 case OP_OUTARG_VTRETADDR: {
1316 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1318 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1320 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1321 // FIXME: src_var->backend.is_pinvoke ?
1323 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1324 src->dreg = ins->dreg;
1329 case OP_VCALL_MEMBASE: {
1330 MonoCallInst *call = (MonoCallInst*)ins;
1333 if (COMPILE_LLVM (cfg))
1336 if (call->vret_in_reg) {
1337 MonoCallInst *call2;
1339 /* Replace the vcall with a scalar call */
1340 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1341 memcpy (call2, call, sizeof (MonoCallInst));
1342 switch (ins->opcode) {
1344 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1347 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1349 case OP_VCALL_MEMBASE:
1350 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1353 call2->inst.dreg = alloc_preg (cfg);
1354 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1356 /* Compute the vtype location */
1357 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1359 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1360 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1362 /* Save the result */
1363 if (dest_var->backend.is_pinvoke)
1364 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1366 size = mono_type_size (dest_var->inst_vtype, NULL);
1369 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1372 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1376 if (call->vret_in_reg_fp)
1377 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1379 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1385 if (call->vret_in_reg_fp) {
1386 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1389 #if SIZEOF_REGISTER == 4
1391 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1392 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1394 switch (call2->inst.opcode) {
1396 call2->inst.opcode = OP_LCALL;
1399 call2->inst.opcode = OP_LCALL_REG;
1401 case OP_CALL_MEMBASE:
1402 call2->inst.opcode = OP_LCALL_MEMBASE;
1405 call2->inst.dreg = alloc_lreg (cfg);
1406 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1407 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1409 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1413 /* This assumes the vtype is sizeof (gpointer) long */
1414 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1418 switch (ins->opcode) {
1420 ins->opcode = OP_VCALL2;
1423 ins->opcode = OP_VCALL2_REG;
1425 case OP_VCALL_MEMBASE:
1426 ins->opcode = OP_VCALL2_MEMBASE;
1437 g_assert (cfg->cbb == first_bb);
1439 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1440 /* Replace the original instruction with the new code sequence */
1442 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1443 first_bb->code = first_bb->last_ins = NULL;
1444 first_bb->in_count = first_bb->out_count = 0;
1445 cfg->cbb = first_bb;
1452 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1456 inline static MonoInst *
1457 mono_get_domainvar (MonoCompile *cfg)
1459 if (!cfg->domainvar)
1460 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1461 return cfg->domainvar;
1465 * mono_decompose_array_access_opts:
1467 * Decompose array access opcodes.
1470 mono_decompose_array_access_opts (MonoCompile *cfg)
1472 MonoBasicBlock *bb, *first_bb;
1475 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1476 * can be executed anytime. It should be run before decompose_long
1480 * Create a dummy bblock and emit code into it so we can use the normal
1481 * code generation macros.
1483 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1484 first_bb = cfg->cbb;
1486 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1488 MonoInst *prev = NULL;
1490 MonoInst *iargs [3];
1493 if (!bb->has_array_access)
1496 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1498 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1504 for (ins = bb->code; ins; ins = ins->next) {
1505 switch (ins->opcode) {
1507 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1508 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1509 MONO_ADD_INS (cfg->cbb, dest);
1511 case OP_BOUNDS_CHECK:
1512 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1513 if (COMPILE_LLVM (cfg))
1514 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1516 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1519 if (cfg->opt & MONO_OPT_SHARED) {
1520 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1521 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1522 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1523 iargs [2]->dreg = ins->sreg1;
1525 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1526 dest->dreg = ins->dreg;
1528 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1529 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1530 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1532 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1533 NEW_VTABLECONST (cfg, iargs [0], vtable);
1534 MONO_ADD_INS (cfg->cbb, iargs [0]);
1535 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1536 iargs [1]->dreg = ins->sreg1;
1539 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1541 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1542 dest->dreg = ins->dreg;
1546 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1547 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1553 g_assert (cfg->cbb == first_bb);
1555 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1556 /* Replace the original instruction with the new code sequence */
1558 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1559 first_bb->code = first_bb->last_ins = NULL;
1560 first_bb->in_count = first_bb->out_count = 0;
1561 cfg->cbb = first_bb;
1568 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1578 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1581 * mono_decompose_soft_float:
1583 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1584 * similar to long support on 32 bit platforms. 32 bit float values require special
1585 * handling when used as locals, arguments, and in calls.
1586 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1589 mono_decompose_soft_float (MonoCompile *cfg)
1591 MonoBasicBlock *bb, *first_bb;
1594 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1598 * Create a dummy bblock and emit code into it so we can use the normal
1599 * code generation macros.
1601 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1602 first_bb = cfg->cbb;
1604 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1606 MonoInst *prev = NULL;
1609 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1611 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1617 for (ins = bb->code; ins; ins = ins->next) {
1618 const char *spec = INS_INFO (ins->opcode);
1620 /* Most fp operations are handled automatically by opcode emulation */
1622 switch (ins->opcode) {
1625 d.vald = *(double*)ins->inst_p0;
1626 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1631 /* We load the r8 value */
1632 d.vald = *(float*)ins->inst_p0;
1633 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1637 ins->opcode = OP_LMOVE;
1640 ins->opcode = OP_MOVE;
1641 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1644 ins->opcode = OP_MOVE;
1645 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1648 int reg = ins->sreg1;
1650 ins->opcode = OP_SETLRET;
1652 ins->sreg1 = MONO_LVREG_LS (reg);
1653 ins->sreg2 = MONO_LVREG_MS (reg);
1656 case OP_LOADR8_MEMBASE:
1657 ins->opcode = OP_LOADI8_MEMBASE;
1659 case OP_STORER8_MEMBASE_REG:
1660 ins->opcode = OP_STOREI8_MEMBASE_REG;
1662 case OP_STORER4_MEMBASE_REG: {
1663 MonoInst *iargs [2];
1666 /* Arg 1 is the double value */
1667 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1668 iargs [0]->dreg = ins->sreg1;
1670 /* Arg 2 is the address to store to */
1671 addr_reg = mono_alloc_preg (cfg);
1672 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1673 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1677 case OP_LOADR4_MEMBASE: {
1678 MonoInst *iargs [1];
1682 addr_reg = mono_alloc_preg (cfg);
1683 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1684 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1685 conv->dreg = ins->dreg;
1690 case OP_FCALL_MEMBASE: {
1691 MonoCallInst *call = (MonoCallInst*)ins;
1692 if (call->signature->ret->type == MONO_TYPE_R4) {
1693 MonoCallInst *call2;
1694 MonoInst *iargs [1];
1698 /* Convert the call into a call returning an int */
1699 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1700 memcpy (call2, call, sizeof (MonoCallInst));
1701 switch (ins->opcode) {
1703 call2->inst.opcode = OP_CALL;
1706 call2->inst.opcode = OP_CALL_REG;
1708 case OP_FCALL_MEMBASE:
1709 call2->inst.opcode = OP_CALL_MEMBASE;
1712 g_assert_not_reached ();
1714 call2->inst.dreg = mono_alloc_ireg (cfg);
1715 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1717 /* Remap OUTARG_VT instructions referencing this call */
1718 for (l = call->outarg_vts; l; l = l->next)
1719 ((MonoInst*)(l->data))->inst_p0 = call2;
1721 /* FIXME: Optimize this */
1723 /* Emit an r4->r8 conversion */
1724 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1725 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1726 conv->dreg = ins->dreg;
1728 /* The call sequence might include fp ins */
1731 switch (ins->opcode) {
1733 ins->opcode = OP_LCALL;
1736 ins->opcode = OP_LCALL_REG;
1738 case OP_FCALL_MEMBASE:
1739 ins->opcode = OP_LCALL_MEMBASE;
1742 g_assert_not_reached ();
1748 MonoJitICallInfo *info;
1749 MonoInst *iargs [2];
1750 MonoInst *call, *cmp, *br;
1752 /* Convert fcompare+fbcc to icall+icompare+beq */
1755 /* The branch might be optimized away */
1760 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1762 /* The branch might be optimized away */
1767 /* Create dummy MonoInst's for the arguments */
1768 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1769 iargs [0]->dreg = ins->sreg1;
1770 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1771 iargs [1]->dreg = ins->sreg2;
1773 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1775 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1776 cmp->sreg1 = call->dreg;
1778 MONO_ADD_INS (cfg->cbb, cmp);
1780 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1781 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1782 br->inst_true_bb = ins->next->inst_true_bb;
1783 br->inst_false_bb = ins->next->inst_false_bb;
1784 MONO_ADD_INS (cfg->cbb, br);
1786 /* The call sequence might include fp ins */
1789 /* Skip fbcc or fccc */
1790 NULLIFY_INS (ins->next);
1798 MonoJitICallInfo *info;
1799 MonoInst *iargs [2];
1802 /* Convert fccc to icall+icompare+iceq */
1804 info = mono_find_jit_opcode_emulation (ins->opcode);
1807 /* Create dummy MonoInst's for the arguments */
1808 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1809 iargs [0]->dreg = ins->sreg1;
1810 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1811 iargs [1]->dreg = ins->sreg2;
1813 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1815 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1816 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1818 /* The call sequence might include fp ins */
1823 MonoInst *iargs [2];
1824 MonoInst *call, *cmp;
1826 /* Convert to icall+icompare+cond_exc+move */
1828 /* Create dummy MonoInst's for the arguments */
1829 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1830 iargs [0]->dreg = ins->sreg1;
1832 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1834 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1835 cmp->sreg1 = call->dreg;
1837 MONO_ADD_INS (cfg->cbb, cmp);
1839 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1841 /* Do the assignment if the value is finite */
1842 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1848 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1849 mono_print_ins (ins);
1850 g_assert_not_reached ();
1855 g_assert (cfg->cbb == first_bb);
1857 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1858 /* Replace the original instruction with the new code sequence */
1860 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1861 first_bb->code = first_bb->last_ins = NULL;
1862 first_bb->in_count = first_bb->out_count = 0;
1863 cfg->cbb = first_bb;
1870 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1873 mono_decompose_long_opts (cfg);
1879 mono_local_emulate_ops (MonoCompile *cfg)
1882 gboolean inlined_wrapper = FALSE;
1884 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1887 MONO_BB_FOR_EACH_INS (bb, ins) {
1888 int op_noimm = mono_op_imm_to_op (ins->opcode);
1889 MonoJitICallInfo *info;
1892 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1893 * to check whether its non-imm counterpart is emulated and, if so,
1894 * decompose it back to its non-imm counterpart.
1897 info = mono_find_jit_opcode_emulation (op_noimm);
1899 info = mono_find_jit_opcode_emulation (ins->opcode);
1904 MonoBasicBlock *first_bb;
1906 /* Create dummy MonoInst's for the arguments */
1907 g_assert (!info->sig->hasthis);
1908 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1911 mono_decompose_op_imm (cfg, bb, ins);
1913 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1914 if (info->sig->param_count > 0) {
1915 int sregs [MONO_MAX_SRC_REGS];
1917 num_sregs = mono_inst_get_src_registers (ins, sregs);
1918 g_assert (num_sregs == info->sig->param_count);
1919 for (i = 0; i < num_sregs; ++i) {
1920 MONO_INST_NEW (cfg, args [i], OP_ARG);
1921 args [i]->dreg = sregs [i];
1925 /* We emit the call on a separate dummy basic block */
1926 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1927 first_bb = cfg->cbb;
1929 call = mono_emit_jit_icall_by_info (cfg, info, args);
1930 call->dreg = ins->dreg;
1932 /* Replace ins with the emitted code and do the necessary bb linking */
1933 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1934 MonoInst *saved_prev = ins->prev;
1936 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1937 first_bb->code = first_bb->last_ins = NULL;
1938 first_bb->in_count = first_bb->out_count = 0;
1939 cfg->cbb = first_bb;
1941 /* ins is hanging, continue scanning the emitted code */
1944 g_error ("Failed to emit emulation code");
1946 inlined_wrapper = TRUE;
1952 * Avoid rerunning these passes by emitting directly the exception checkpoint
1953 * at IR level, instead of inlining the icall wrapper. FIXME
1955 if (inlined_wrapper) {
1956 if (!COMPILE_LLVM (cfg))
1957 mono_decompose_long_opts (cfg);
1958 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1959 mono_local_cprop (cfg);
1963 #endif /* DISABLE_JIT */