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)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include "jit-icalls.h"
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/metadata/abi-details.h>
18 #include <mono/utils/mono-compiler.h>
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);
474 #if SIZEOF_VOID_P == 8
479 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
482 if (cfg->backend->need_div_check) {
483 int reg1 = alloc_ireg (cfg);
484 int reg2 = alloc_ireg (cfg);
485 int reg3 = alloc_ireg (cfg);
487 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
488 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
489 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
490 /* b == -1 && a == 0x80000000 */
491 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
492 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
493 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
494 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
495 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
496 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
497 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
498 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
499 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
502 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
514 if (cfg->backend->need_div_check) {
515 int reg1 = alloc_ireg (cfg);
517 if (ins->inst_imm == 0) {
518 // FIXME: Optimize this
519 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
520 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
521 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
523 if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
524 (ins->inst_imm == -1)) {
525 /* b == -1 && a == 0x80000000 */
526 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
527 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
529 MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
542 #if SIZEOF_REGISTER == 8
543 if (decompose_long_opcode (cfg, ins, &repl))
546 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
550 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
551 cfg->has_emulated_ops = TRUE;
554 if (ins->opcode == OP_NOP) {
559 /* Use the last emitted instruction */
560 ins = cfg->cbb->last_ins;
563 g_assert (ins->dreg == dreg);
571 #if SIZEOF_REGISTER == 4
572 static int lbr_decomp [][2] = {
574 {OP_IBGT, OP_IBGE_UN}, /* BGE */
575 {OP_IBGT, OP_IBGT_UN}, /* BGT */
576 {OP_IBLT, OP_IBLE_UN}, /* BLE */
577 {OP_IBLT, OP_IBLT_UN}, /* BLT */
579 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
580 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
581 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
582 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
585 static int lcset_decomp [][2] = {
587 {OP_IBLT, OP_IBLE_UN}, /* CGT */
588 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
589 {OP_IBGT, OP_IBGE_UN}, /* CLT */
590 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
595 * mono_decompose_long_opts:
597 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
600 mono_decompose_long_opts (MonoCompile *cfg)
602 #if SIZEOF_REGISTER == 4
603 MonoBasicBlock *bb, *first_bb;
606 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
607 * needs to be able to handle long vregs.
611 * Create a dummy bblock and emit code into it so we can use the normal
612 * code generation macros.
614 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
617 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
618 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
619 MonoInst *prev = NULL;
622 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
625 cfg->cbb->code = cfg->cbb->last_ins = NULL;
628 mono_arch_decompose_long_opts (cfg, tree);
630 switch (tree->opcode) {
632 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
633 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
635 case OP_DUMMY_I8CONST:
636 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
637 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
642 case OP_LCONV_TO_OVF_U8_UN:
643 case OP_LCONV_TO_OVF_I8:
644 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
645 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
647 case OP_STOREI8_MEMBASE_REG:
648 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));
649 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));
651 case OP_LOADI8_MEMBASE:
652 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);
653 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);
656 case OP_ICONV_TO_I8: {
657 guint32 tmpreg = alloc_ireg (cfg);
661 * tmp = low > -1 ? 1: 0;
662 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
664 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
665 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
666 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
667 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
671 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
672 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
674 case OP_ICONV_TO_OVF_I8:
675 /* a signed 32 bit num always fits in a signed 64 bit one */
676 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
677 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
679 case OP_ICONV_TO_OVF_U8:
680 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
681 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
682 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
683 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
685 case OP_ICONV_TO_OVF_I8_UN:
686 case OP_ICONV_TO_OVF_U8_UN:
687 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
688 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
689 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
692 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
695 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
698 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
701 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
707 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
709 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
711 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
714 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
716 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
719 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
720 case OP_LCONV_TO_R_UN:
721 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
724 case OP_LCONV_TO_OVF_I1: {
725 MonoBasicBlock *is_negative, *end_label;
727 NEW_BBLOCK (cfg, is_negative);
728 NEW_BBLOCK (cfg, end_label);
730 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
731 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
732 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
733 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
735 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
736 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
739 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
740 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
741 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
744 MONO_START_BB (cfg, is_negative);
745 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
746 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
748 MONO_START_BB (cfg, end_label);
750 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
753 case OP_LCONV_TO_OVF_I1_UN:
754 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
755 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
757 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
758 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
759 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
760 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
761 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
763 case OP_LCONV_TO_OVF_U1:
764 case OP_LCONV_TO_OVF_U1_UN:
765 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
766 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
768 /* probe value to be within 0 to 255 */
769 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
770 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
771 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
773 case OP_LCONV_TO_OVF_I2: {
774 MonoBasicBlock *is_negative, *end_label;
776 NEW_BBLOCK (cfg, is_negative);
777 NEW_BBLOCK (cfg, end_label);
779 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
780 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
782 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
784 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
785 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
788 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
789 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
790 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
793 MONO_START_BB (cfg, is_negative);
794 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
795 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
796 MONO_START_BB (cfg, end_label);
798 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
801 case OP_LCONV_TO_OVF_I2_UN:
802 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
803 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
805 /* Probe value to be within -32768 and 32767 */
806 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
807 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
808 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
809 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
810 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
812 case OP_LCONV_TO_OVF_U2:
813 case OP_LCONV_TO_OVF_U2_UN:
814 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
815 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
817 /* Probe value to be within 0 and 65535 */
818 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
819 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
820 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
822 case OP_LCONV_TO_OVF_I4:
823 case OP_LCONV_TO_OVF_I:
824 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
826 case OP_LCONV_TO_OVF_U4:
827 case OP_LCONV_TO_OVF_U:
828 case OP_LCONV_TO_OVF_U4_UN:
829 case OP_LCONV_TO_OVF_U_UN:
830 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
831 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
832 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
834 case OP_LCONV_TO_OVF_I_UN:
835 case OP_LCONV_TO_OVF_I4_UN:
836 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
837 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
838 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
839 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
840 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
842 case OP_LCONV_TO_OVF_U8:
843 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
844 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
846 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
847 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
849 case OP_LCONV_TO_OVF_I8_UN:
850 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
851 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
853 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
854 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
858 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
859 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
862 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
863 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
867 /* ADC sets the condition code */
868 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
869 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
870 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
873 /* ADC sets the condition code */
874 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
875 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
876 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
879 /* SBB sets the condition code */
880 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
881 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
882 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
885 /* SBB sets the condition code */
886 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
887 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
888 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
891 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
892 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
895 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
896 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
899 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
900 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
903 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
904 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
907 /* Handled in mono_arch_decompose_long_opts () */
908 g_assert_not_reached ();
912 /* FIXME: Add OP_BIGMUL optimization */
916 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
917 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
920 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
932 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
935 #ifdef TARGET_POWERPC
936 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
938 if (tree->inst_c1 == 32) {
940 /* The original code had this comment: */
941 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
942 * later apply the speedup to the left shift as well
945 /* just move the upper half to the lower and zero the high word */
946 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
947 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
952 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
956 switch (next->opcode) {
961 /* Branchless version based on gcc code */
962 d1 = alloc_ireg (cfg);
963 d2 = alloc_ireg (cfg);
964 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
965 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
966 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
967 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
968 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
980 /* Convert into three comparisons + branches */
981 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
982 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
983 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
984 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
985 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
986 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
992 /* Branchless version based on gcc code */
993 d1 = alloc_ireg (cfg);
994 d2 = alloc_ireg (cfg);
995 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
996 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
997 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
999 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1000 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1008 MonoBasicBlock *set_to_0, *set_to_1;
1010 NEW_BBLOCK (cfg, set_to_0);
1011 NEW_BBLOCK (cfg, set_to_1);
1013 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1014 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1015 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1016 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1017 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1018 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1019 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1020 MONO_START_BB (cfg, set_to_1);
1021 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1022 MONO_START_BB (cfg, set_to_0);
1027 g_assert_not_reached ();
1032 /* Not yet used, since lcompare is decomposed before local cprop */
1033 case OP_LCOMPARE_IMM: {
1034 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1035 guint32 low_imm = tree->inst_ls_word;
1036 guint32 high_imm = tree->inst_ms_word;
1037 int low_reg = MONO_LVREG_LS (tree->sreg1);
1038 int high_reg = MONO_LVREG_MS (tree->sreg1);
1042 switch (next->opcode) {
1047 /* Branchless version based on gcc code */
1048 d1 = alloc_ireg (cfg);
1049 d2 = alloc_ireg (cfg);
1050 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1051 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1052 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1053 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1054 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1067 /* Convert into three comparisons + branches */
1068 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1069 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1070 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1071 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1072 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1073 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1079 /* Branchless version based on gcc code */
1080 d1 = alloc_ireg (cfg);
1081 d2 = alloc_ireg (cfg);
1082 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1083 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1084 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1086 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1087 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1095 MonoBasicBlock *set_to_0, *set_to_1;
1097 NEW_BBLOCK (cfg, set_to_0);
1098 NEW_BBLOCK (cfg, set_to_1);
1100 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1101 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1102 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1103 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1104 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1105 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1106 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1107 MONO_START_BB (cfg, set_to_1);
1108 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1109 MONO_START_BB (cfg, set_to_0);
1114 g_assert_not_reached ();
1123 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1126 /* Replace the original instruction with the new code sequence */
1128 /* Ignore the new value of prev */
1130 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1132 /* Process the newly added ops again since they can be long ops too */
1134 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1136 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1138 first_bb->code = first_bb->last_ins = NULL;
1139 first_bb->in_count = first_bb->out_count = 0;
1140 cfg->cbb = first_bb;
1144 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1151 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1152 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1157 * mono_decompose_vtype_opts:
1159 * Decompose valuetype opcodes.
1162 mono_decompose_vtype_opts (MonoCompile *cfg)
1164 MonoBasicBlock *bb, *first_bb;
1167 * Using OP_V opcodes and decomposing them later have two main benefits:
1168 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1170 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1171 * enabling optimizations to work on vtypes too.
1172 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1173 * can be executed anytime. It should be executed as late as possible so vtype
1174 * opcodes can be optimized by the other passes.
1175 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1176 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1178 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1179 * when OP_VMOVE opcodes are decomposed.
1183 * Vregs have no associated type information, so we store the type of the vregs
1188 * Create a dummy bblock and emit code into it so we can use the normal
1189 * code generation macros.
1191 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1192 first_bb = cfg->cbb;
1194 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1196 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1198 MonoInst *prev = NULL;
1199 MonoInst *src_var, *dest_var, *src, *dest;
1203 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1205 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1211 for (ins = bb->code; ins; ins = ins->next) {
1212 switch (ins->opcode) {
1214 g_assert (ins->klass);
1215 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1217 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1218 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1221 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1224 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1227 if (src_var->backend.is_pinvoke)
1228 dest_var->backend.is_pinvoke = 1;
1230 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1231 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1233 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1237 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1240 g_assert (ins->klass);
1242 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1243 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1245 if (cfg->compute_gc_maps) {
1249 * Tell the GC map code that the vtype is considered live after
1250 * the initialization.
1252 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1253 tmp->inst_c1 = ins->dreg;
1254 MONO_ADD_INS (cfg->cbb, tmp);
1257 case OP_DUMMY_VZERO:
1258 if (COMPILE_LLVM (cfg))
1263 case OP_STOREV_MEMBASE: {
1264 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1266 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !cfg->gen_write_barriers)
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, ves_icall_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 * These opcodes don't have logical equivalence to the emulating native
1893 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1895 if (MONO_HAS_CUSTOM_EMULATION (ins))
1899 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1900 * to check whether its non-imm counterpart is emulated and, if so,
1901 * decompose it back to its non-imm counterpart.
1904 info = mono_find_jit_opcode_emulation (op_noimm);
1906 info = mono_find_jit_opcode_emulation (ins->opcode);
1911 MonoBasicBlock *first_bb;
1913 /* Create dummy MonoInst's for the arguments */
1914 g_assert (!info->sig->hasthis);
1915 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1918 mono_decompose_op_imm (cfg, bb, ins);
1920 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1921 if (info->sig->param_count > 0) {
1922 int sregs [MONO_MAX_SRC_REGS];
1924 num_sregs = mono_inst_get_src_registers (ins, sregs);
1925 g_assert (num_sregs == info->sig->param_count);
1926 for (i = 0; i < num_sregs; ++i) {
1927 MONO_INST_NEW (cfg, args [i], OP_ARG);
1928 args [i]->dreg = sregs [i];
1932 /* We emit the call on a separate dummy basic block */
1933 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1934 first_bb = cfg->cbb;
1936 call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
1937 call->dreg = ins->dreg;
1939 /* Replace ins with the emitted code and do the necessary bb linking */
1940 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1941 MonoInst *saved_prev = ins->prev;
1943 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1944 first_bb->code = first_bb->last_ins = NULL;
1945 first_bb->in_count = first_bb->out_count = 0;
1946 cfg->cbb = first_bb;
1948 /* ins is hanging, continue scanning the emitted code */
1951 g_error ("Failed to emit emulation code");
1953 inlined_wrapper = TRUE;
1959 * Avoid rerunning these passes by emitting directly the exception checkpoint
1960 * at IR level, instead of inlining the icall wrapper. FIXME
1962 if (inlined_wrapper) {
1963 if (!COMPILE_LLVM (cfg))
1964 mono_decompose_long_opts (cfg);
1965 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1966 mono_local_cprop (cfg);
1970 #else /* !DISABLE_JIT */
1972 MONO_EMPTY_SOURCE_FILE (decompose);
1974 #endif /* !DISABLE_JIT */