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>
23 * Decompose complex long opcodes on 64 bit machines.
24 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
27 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
29 MonoInst *repl = NULL;
33 switch (ins->opcode) {
35 ins->opcode = OP_SEXT_I4;
39 if (SIZEOF_VOID_P == 4)
40 ins->opcode = OP_LMOVE;
42 ins->opcode = OP_MOVE;
45 if (SIZEOF_VOID_P == 4)
47 ins->opcode = OP_SEXT_I4;
49 ins->opcode = OP_MOVE;
52 if (SIZEOF_VOID_P == 4) {
54 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
57 ins->opcode = OP_MOVE;
61 ins->opcode = OP_SEXT_I4;
64 ins->opcode = OP_ZEXT_I4;
67 /* Clean out the upper word */
68 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
74 if (COMPILE_LLVM (cfg))
76 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
80 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
81 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
85 case OP_LADD_OVF_UN: {
88 if (COMPILE_LLVM (cfg))
90 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
94 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
95 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
99 #ifndef __mono_ppc64__
103 if (COMPILE_LLVM (cfg))
105 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
109 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
110 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
114 case OP_LSUB_OVF_UN: {
117 if (COMPILE_LLVM (cfg))
119 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
123 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
124 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
130 case OP_ICONV_TO_OVF_I8:
131 case OP_ICONV_TO_OVF_I:
132 ins->opcode = OP_SEXT_I4;
134 case OP_ICONV_TO_OVF_U8:
135 case OP_ICONV_TO_OVF_U:
136 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
137 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
138 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
141 case OP_ICONV_TO_OVF_I8_UN:
142 case OP_ICONV_TO_OVF_U8_UN:
143 case OP_ICONV_TO_OVF_I_UN:
144 case OP_ICONV_TO_OVF_U_UN:
145 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
146 /* Clean out the upper word */
147 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
150 case OP_LCONV_TO_OVF_I1:
151 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
152 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
153 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
154 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
155 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
158 case OP_LCONV_TO_OVF_I1_UN:
159 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
160 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
161 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
164 case OP_LCONV_TO_OVF_U1:
165 /* probe value to be within 0 to 255 */
166 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
167 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
168 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
171 case OP_LCONV_TO_OVF_U1_UN:
172 /* probe value to be within 0 to 255 */
173 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
174 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
175 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
178 case OP_LCONV_TO_OVF_I2:
179 /* Probe value to be within -32768 and 32767 */
180 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
181 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
182 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
183 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
184 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
187 case OP_LCONV_TO_OVF_I2_UN:
188 /* Probe value to be within 0 and 32767 */
189 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
190 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
191 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
194 case OP_LCONV_TO_OVF_U2:
195 /* Probe value to be within 0 and 65535 */
196 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
197 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
198 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
201 case OP_LCONV_TO_OVF_U2_UN:
202 /* Probe value to be within 0 and 65535 */
203 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
204 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
205 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
208 case OP_LCONV_TO_OVF_I4:
209 #if SIZEOF_VOID_P == 4
210 case OP_LCONV_TO_OVF_I:
212 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
213 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
214 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
215 #if SIZEOF_REGISTER == 8
216 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
218 g_assert (COMPILE_LLVM (cfg));
219 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
221 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
222 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
225 case OP_LCONV_TO_OVF_I4_UN:
226 #if SIZEOF_VOID_P == 4
227 case OP_LCONV_TO_OVF_I_UN:
229 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
230 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
231 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
234 case OP_LCONV_TO_OVF_U4:
235 #if SIZEOF_VOID_P == 4
236 case OP_LCONV_TO_OVF_U:
238 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
239 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
240 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
241 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
242 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
245 case OP_LCONV_TO_OVF_U4_UN:
246 #if SIZEOF_VOID_P == 4
247 case OP_LCONV_TO_OVF_U_UN:
249 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
250 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
251 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
254 #if SIZEOF_VOID_P == 8
255 case OP_LCONV_TO_OVF_I:
256 case OP_LCONV_TO_OVF_U_UN:
258 case OP_LCONV_TO_OVF_U8_UN:
259 case OP_LCONV_TO_OVF_I8:
260 ins->opcode = OP_MOVE;
262 #if SIZEOF_VOID_P == 8
263 case OP_LCONV_TO_OVF_I_UN:
265 case OP_LCONV_TO_OVF_I8_UN:
266 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
267 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
268 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
271 case OP_LCONV_TO_OVF_U8:
272 #if SIZEOF_VOID_P == 8
273 case OP_LCONV_TO_OVF_U:
275 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
276 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
277 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
289 * mono_decompose_opcode:
291 * Decompose complex opcodes into ones closer to opcodes supported by
292 * the given architecture.
293 * Returns a MonoInst which represents the result of the decomposition, and can
294 * be pushed on the IL stack. This is needed because the original instruction is
296 * Sets the cfg exception if an opcode is not supported.
299 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
301 MonoInst *repl = NULL;
302 int type = ins->type;
303 int dreg = ins->dreg;
304 gboolean emulate = FALSE;
306 /* FIXME: Instead of = NOP, don't emit the original ins at all */
307 mono_arch_decompose_opts (cfg, ins);
310 * The code below assumes that we are called immediately after emitting
311 * ins. This means we can emit code using the normal code generation
314 switch (ins->opcode) {
315 /* this doesn't make sense on ppc and other architectures */
316 #if !defined(MONO_ARCH_NO_IOV_CHECK)
318 if (COMPILE_LLVM (cfg))
320 ins->opcode = OP_IADDCC;
321 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
324 if (COMPILE_LLVM (cfg))
326 ins->opcode = OP_IADDCC;
327 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
330 if (COMPILE_LLVM (cfg))
332 ins->opcode = OP_ISUBCC;
333 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
336 if (COMPILE_LLVM (cfg))
338 ins->opcode = OP_ISUBCC;
339 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
342 case OP_ICONV_TO_OVF_I1:
343 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
344 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
345 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
346 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
347 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
350 case OP_ICONV_TO_OVF_I1_UN:
351 /* probe values between 0 to 127 */
352 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
353 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
354 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
357 case OP_ICONV_TO_OVF_U1:
358 case OP_ICONV_TO_OVF_U1_UN:
359 /* probe value to be within 0 to 255 */
360 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
361 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
362 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
365 case OP_ICONV_TO_OVF_I2:
366 /* Probe value to be within -32768 and 32767 */
367 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
368 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
369 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
370 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
371 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
374 case OP_ICONV_TO_OVF_I2_UN:
375 /* Convert uint value into short, value within 0 and 32767 */
376 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
377 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
378 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
381 case OP_ICONV_TO_OVF_U2:
382 case OP_ICONV_TO_OVF_U2_UN:
383 /* Probe value to be within 0 and 65535 */
384 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
385 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
386 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
389 case OP_ICONV_TO_OVF_U4:
390 case OP_ICONV_TO_OVF_I4_UN:
391 #if SIZEOF_VOID_P == 4
392 case OP_ICONV_TO_OVF_U:
393 case OP_ICONV_TO_OVF_I_UN:
395 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
396 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
397 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
402 case OP_ICONV_TO_OVF_I4:
403 case OP_ICONV_TO_OVF_U4_UN:
404 #if SIZEOF_VOID_P == 4
405 case OP_ICONV_TO_OVF_I:
406 case OP_ICONV_TO_OVF_U_UN:
408 ins->opcode = OP_MOVE;
411 #if SIZEOF_VOID_P == 8
412 ins->opcode = OP_SEXT_I4;
414 ins->opcode = OP_MOVE;
418 #if SIZEOF_VOID_P == 8
419 ins->opcode = OP_ZEXT_I4;
421 ins->opcode = OP_MOVE;
426 ins->opcode = OP_FMOVE;
429 case OP_FCONV_TO_OVF_I1_UN:
430 case OP_FCONV_TO_OVF_I2_UN:
431 case OP_FCONV_TO_OVF_I4_UN:
432 case OP_FCONV_TO_OVF_I8_UN:
433 case OP_FCONV_TO_OVF_U1_UN:
434 case OP_FCONV_TO_OVF_U2_UN:
435 case OP_FCONV_TO_OVF_U4_UN:
436 case OP_FCONV_TO_OVF_U8_UN:
437 case OP_FCONV_TO_OVF_I_UN:
438 case OP_FCONV_TO_OVF_U_UN:
439 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
446 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
449 if (cfg->backend->need_div_check) {
450 int reg1 = alloc_ireg (cfg);
451 int reg2 = alloc_ireg (cfg);
453 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
454 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
455 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
456 /* b == -1 && a == 0x80000000 */
457 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
458 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
459 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
460 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
461 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
463 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
466 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
471 #if SIZEOF_VOID_P == 8
476 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
479 if (cfg->backend->need_div_check) {
480 int reg1 = alloc_ireg (cfg);
481 int reg2 = alloc_ireg (cfg);
482 int reg3 = alloc_ireg (cfg);
484 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
485 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
486 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
487 /* b == -1 && a == 0x80000000 */
488 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
489 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
490 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
491 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
492 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
493 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
494 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
495 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
496 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
499 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);
932 #ifdef TARGET_POWERPC
933 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
935 if (tree->inst_c1 == 32) {
937 /* The original code had this comment: */
938 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
939 * later apply the speedup to the left shift as well
942 /* just move the upper half to the lower and zero the high word */
943 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
944 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
949 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
953 switch (next->opcode) {
958 /* Branchless version based on gcc code */
959 d1 = alloc_ireg (cfg);
960 d2 = alloc_ireg (cfg);
961 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
962 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
963 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
964 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
965 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
977 /* Convert into three comparisons + branches */
978 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
979 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
980 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
981 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
982 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
983 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
989 /* Branchless version based on gcc code */
990 d1 = alloc_ireg (cfg);
991 d2 = alloc_ireg (cfg);
992 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
993 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
994 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
996 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
997 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1005 MonoBasicBlock *set_to_0, *set_to_1;
1007 NEW_BBLOCK (cfg, set_to_0);
1008 NEW_BBLOCK (cfg, set_to_1);
1010 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1011 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1012 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1013 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1014 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1015 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1016 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1017 MONO_START_BB (cfg, set_to_1);
1018 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1019 MONO_START_BB (cfg, set_to_0);
1024 g_assert_not_reached ();
1029 /* Not yet used, since lcompare is decomposed before local cprop */
1030 case OP_LCOMPARE_IMM: {
1031 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1032 guint32 low_imm = tree->inst_ls_word;
1033 guint32 high_imm = tree->inst_ms_word;
1034 int low_reg = MONO_LVREG_LS (tree->sreg1);
1035 int high_reg = MONO_LVREG_MS (tree->sreg1);
1039 switch (next->opcode) {
1044 /* Branchless version based on gcc code */
1045 d1 = alloc_ireg (cfg);
1046 d2 = alloc_ireg (cfg);
1047 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1048 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1049 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1050 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1051 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1064 /* Convert into three comparisons + branches */
1065 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1066 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1067 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1068 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1069 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1070 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1076 /* Branchless version based on gcc code */
1077 d1 = alloc_ireg (cfg);
1078 d2 = alloc_ireg (cfg);
1079 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1080 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1081 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1083 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1084 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1092 MonoBasicBlock *set_to_0, *set_to_1;
1094 NEW_BBLOCK (cfg, set_to_0);
1095 NEW_BBLOCK (cfg, set_to_1);
1097 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1098 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1099 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1100 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1101 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1102 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1103 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1104 MONO_START_BB (cfg, set_to_1);
1105 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1106 MONO_START_BB (cfg, set_to_0);
1111 g_assert_not_reached ();
1120 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1123 /* Replace the original instruction with the new code sequence */
1125 /* Ignore the new value of prev */
1127 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1129 /* Process the newly added ops again since they can be long ops too */
1131 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1133 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1135 first_bb->code = first_bb->last_ins = NULL;
1136 first_bb->in_count = first_bb->out_count = 0;
1137 cfg->cbb = first_bb;
1141 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1148 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1149 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1154 * mono_decompose_vtype_opts:
1156 * Decompose valuetype opcodes.
1159 mono_decompose_vtype_opts (MonoCompile *cfg)
1161 MonoBasicBlock *bb, *first_bb;
1164 * Using OP_V opcodes and decomposing them later have two main benefits:
1165 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1167 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1168 * enabling optimizations to work on vtypes too.
1169 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1170 * can be executed anytime. It should be executed as late as possible so vtype
1171 * opcodes can be optimized by the other passes.
1172 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1173 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1175 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1176 * when OP_VMOVE opcodes are decomposed.
1180 * Vregs have no associated type information, so we store the type of the vregs
1185 * Create a dummy bblock and emit code into it so we can use the normal
1186 * code generation macros.
1188 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1189 first_bb = cfg->cbb;
1191 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1193 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1195 MonoInst *prev = NULL;
1196 MonoInst *src_var, *dest_var, *src, *dest;
1200 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1202 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1208 for (ins = bb->code; ins; ins = ins->next) {
1209 switch (ins->opcode) {
1211 g_assert (ins->klass);
1212 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1214 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1215 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1218 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1221 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1224 if (src_var->backend.is_pinvoke)
1225 dest_var->backend.is_pinvoke = 1;
1227 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1228 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1230 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1234 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1237 g_assert (ins->klass);
1239 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1240 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1242 if (cfg->compute_gc_maps) {
1246 * Tell the GC map code that the vtype is considered live after
1247 * the initialization.
1249 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1250 tmp->inst_c1 = ins->dreg;
1251 MONO_ADD_INS (cfg->cbb, tmp);
1254 case OP_DUMMY_VZERO:
1255 if (COMPILE_LLVM (cfg))
1260 case OP_STOREV_MEMBASE: {
1261 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1263 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !cfg->gen_write_barriers)
1267 g_assert (ins->klass);
1268 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1271 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1273 dreg = alloc_preg (cfg);
1274 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1275 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1278 case OP_LOADV_MEMBASE: {
1279 g_assert (ins->klass);
1280 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1283 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1287 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1289 dreg = alloc_preg (cfg);
1290 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1291 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1292 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1295 case OP_OUTARG_VT: {
1296 if (COMPILE_LLVM (cfg))
1299 g_assert (ins->klass);
1301 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1303 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1304 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1306 mono_arch_emit_outarg_vt (cfg, ins, src);
1308 /* This might be decomposed into other vtype opcodes */
1312 case OP_OUTARG_VTRETADDR: {
1313 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1315 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1317 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1318 // FIXME: src_var->backend.is_pinvoke ?
1320 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1321 src->dreg = ins->dreg;
1326 case OP_VCALL_MEMBASE: {
1327 MonoCallInst *call = (MonoCallInst*)ins;
1330 if (COMPILE_LLVM (cfg))
1333 if (call->vret_in_reg) {
1334 MonoCallInst *call2;
1336 /* Replace the vcall with a scalar call */
1337 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1338 memcpy (call2, call, sizeof (MonoCallInst));
1339 switch (ins->opcode) {
1341 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1344 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1346 case OP_VCALL_MEMBASE:
1347 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1350 call2->inst.dreg = alloc_preg (cfg);
1351 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1353 /* Compute the vtype location */
1354 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1356 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1357 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1359 /* Save the result */
1360 if (dest_var->backend.is_pinvoke)
1361 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1363 size = mono_type_size (dest_var->inst_vtype, NULL);
1366 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1369 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1373 if (call->vret_in_reg_fp)
1374 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1376 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1382 if (call->vret_in_reg_fp) {
1383 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1386 #if SIZEOF_REGISTER == 4
1388 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1389 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1391 switch (call2->inst.opcode) {
1393 call2->inst.opcode = OP_LCALL;
1396 call2->inst.opcode = OP_LCALL_REG;
1398 case OP_CALL_MEMBASE:
1399 call2->inst.opcode = OP_LCALL_MEMBASE;
1402 call2->inst.dreg = alloc_lreg (cfg);
1403 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1404 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1406 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1410 /* This assumes the vtype is sizeof (gpointer) long */
1411 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1415 switch (ins->opcode) {
1417 ins->opcode = OP_VCALL2;
1420 ins->opcode = OP_VCALL2_REG;
1422 case OP_VCALL_MEMBASE:
1423 ins->opcode = OP_VCALL2_MEMBASE;
1434 g_assert (cfg->cbb == first_bb);
1436 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1437 /* Replace the original instruction with the new code sequence */
1439 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1440 first_bb->code = first_bb->last_ins = NULL;
1441 first_bb->in_count = first_bb->out_count = 0;
1442 cfg->cbb = first_bb;
1449 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1453 inline static MonoInst *
1454 mono_get_domainvar (MonoCompile *cfg)
1456 if (!cfg->domainvar)
1457 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1458 return cfg->domainvar;
1462 * mono_decompose_array_access_opts:
1464 * Decompose array access opcodes.
1467 mono_decompose_array_access_opts (MonoCompile *cfg)
1469 MonoBasicBlock *bb, *first_bb;
1472 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1473 * can be executed anytime. It should be run before decompose_long
1477 * Create a dummy bblock and emit code into it so we can use the normal
1478 * code generation macros.
1480 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1481 first_bb = cfg->cbb;
1483 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1485 MonoInst *prev = NULL;
1487 MonoInst *iargs [3];
1490 if (!bb->has_array_access)
1493 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1495 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1501 for (ins = bb->code; ins; ins = ins->next) {
1502 switch (ins->opcode) {
1504 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1505 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1506 MONO_ADD_INS (cfg->cbb, dest);
1508 case OP_BOUNDS_CHECK:
1509 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1510 if (COMPILE_LLVM (cfg))
1511 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1513 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1516 if (cfg->opt & MONO_OPT_SHARED) {
1517 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1518 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1519 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1520 iargs [2]->dreg = ins->sreg1;
1522 dest = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
1523 dest->dreg = ins->dreg;
1525 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1526 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1527 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1529 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1530 NEW_VTABLECONST (cfg, iargs [0], vtable);
1531 MONO_ADD_INS (cfg->cbb, iargs [0]);
1532 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1533 iargs [1]->dreg = ins->sreg1;
1536 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1538 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1539 dest->dreg = ins->dreg;
1543 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1544 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1550 g_assert (cfg->cbb == first_bb);
1552 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1553 /* Replace the original instruction with the new code sequence */
1555 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1556 first_bb->code = first_bb->last_ins = NULL;
1557 first_bb->in_count = first_bb->out_count = 0;
1558 cfg->cbb = first_bb;
1565 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1575 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1578 * mono_decompose_soft_float:
1580 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1581 * similar to long support on 32 bit platforms. 32 bit float values require special
1582 * handling when used as locals, arguments, and in calls.
1583 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1586 mono_decompose_soft_float (MonoCompile *cfg)
1588 MonoBasicBlock *bb, *first_bb;
1591 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1595 * Create a dummy bblock and emit code into it so we can use the normal
1596 * code generation macros.
1598 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1599 first_bb = cfg->cbb;
1601 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1603 MonoInst *prev = NULL;
1606 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1608 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1614 for (ins = bb->code; ins; ins = ins->next) {
1615 const char *spec = INS_INFO (ins->opcode);
1617 /* Most fp operations are handled automatically by opcode emulation */
1619 switch (ins->opcode) {
1622 d.vald = *(double*)ins->inst_p0;
1623 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1628 /* We load the r8 value */
1629 d.vald = *(float*)ins->inst_p0;
1630 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1634 ins->opcode = OP_LMOVE;
1637 ins->opcode = OP_MOVE;
1638 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1641 ins->opcode = OP_MOVE;
1642 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1645 int reg = ins->sreg1;
1647 ins->opcode = OP_SETLRET;
1649 ins->sreg1 = MONO_LVREG_LS (reg);
1650 ins->sreg2 = MONO_LVREG_MS (reg);
1653 case OP_LOADR8_MEMBASE:
1654 ins->opcode = OP_LOADI8_MEMBASE;
1656 case OP_STORER8_MEMBASE_REG:
1657 ins->opcode = OP_STOREI8_MEMBASE_REG;
1659 case OP_STORER4_MEMBASE_REG: {
1660 MonoInst *iargs [2];
1663 /* Arg 1 is the double value */
1664 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1665 iargs [0]->dreg = ins->sreg1;
1667 /* Arg 2 is the address to store to */
1668 addr_reg = mono_alloc_preg (cfg);
1669 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1670 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1674 case OP_LOADR4_MEMBASE: {
1675 MonoInst *iargs [1];
1679 addr_reg = mono_alloc_preg (cfg);
1680 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1681 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1682 conv->dreg = ins->dreg;
1687 case OP_FCALL_MEMBASE: {
1688 MonoCallInst *call = (MonoCallInst*)ins;
1689 if (call->signature->ret->type == MONO_TYPE_R4) {
1690 MonoCallInst *call2;
1691 MonoInst *iargs [1];
1695 /* Convert the call into a call returning an int */
1696 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1697 memcpy (call2, call, sizeof (MonoCallInst));
1698 switch (ins->opcode) {
1700 call2->inst.opcode = OP_CALL;
1703 call2->inst.opcode = OP_CALL_REG;
1705 case OP_FCALL_MEMBASE:
1706 call2->inst.opcode = OP_CALL_MEMBASE;
1709 g_assert_not_reached ();
1711 call2->inst.dreg = mono_alloc_ireg (cfg);
1712 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1714 /* Remap OUTARG_VT instructions referencing this call */
1715 for (l = call->outarg_vts; l; l = l->next)
1716 ((MonoInst*)(l->data))->inst_p0 = call2;
1718 /* FIXME: Optimize this */
1720 /* Emit an r4->r8 conversion */
1721 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1722 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1723 conv->dreg = ins->dreg;
1725 /* The call sequence might include fp ins */
1728 switch (ins->opcode) {
1730 ins->opcode = OP_LCALL;
1733 ins->opcode = OP_LCALL_REG;
1735 case OP_FCALL_MEMBASE:
1736 ins->opcode = OP_LCALL_MEMBASE;
1739 g_assert_not_reached ();
1745 MonoJitICallInfo *info;
1746 MonoInst *iargs [2];
1747 MonoInst *call, *cmp, *br;
1749 /* Convert fcompare+fbcc to icall+icompare+beq */
1752 /* The branch might be optimized away */
1757 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1759 /* The branch might be optimized away */
1764 /* Create dummy MonoInst's for the arguments */
1765 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1766 iargs [0]->dreg = ins->sreg1;
1767 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1768 iargs [1]->dreg = ins->sreg2;
1770 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1772 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1773 cmp->sreg1 = call->dreg;
1775 MONO_ADD_INS (cfg->cbb, cmp);
1777 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1778 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1779 br->inst_true_bb = ins->next->inst_true_bb;
1780 br->inst_false_bb = ins->next->inst_false_bb;
1781 MONO_ADD_INS (cfg->cbb, br);
1783 /* The call sequence might include fp ins */
1786 /* Skip fbcc or fccc */
1787 NULLIFY_INS (ins->next);
1795 MonoJitICallInfo *info;
1796 MonoInst *iargs [2];
1799 /* Convert fccc to icall+icompare+iceq */
1801 info = mono_find_jit_opcode_emulation (ins->opcode);
1804 /* Create dummy MonoInst's for the arguments */
1805 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1806 iargs [0]->dreg = ins->sreg1;
1807 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1808 iargs [1]->dreg = ins->sreg2;
1810 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1812 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1813 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1815 /* The call sequence might include fp ins */
1820 MonoInst *iargs [2];
1821 MonoInst *call, *cmp;
1823 /* Convert to icall+icompare+cond_exc+move */
1825 /* Create dummy MonoInst's for the arguments */
1826 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1827 iargs [0]->dreg = ins->sreg1;
1829 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1831 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1832 cmp->sreg1 = call->dreg;
1834 MONO_ADD_INS (cfg->cbb, cmp);
1836 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1838 /* Do the assignment if the value is finite */
1839 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1845 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1846 mono_print_ins (ins);
1847 g_assert_not_reached ();
1852 g_assert (cfg->cbb == first_bb);
1854 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1855 /* Replace the original instruction with the new code sequence */
1857 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1858 first_bb->code = first_bb->last_ins = NULL;
1859 first_bb->in_count = first_bb->out_count = 0;
1860 cfg->cbb = first_bb;
1867 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1870 mono_decompose_long_opts (cfg);
1876 mono_local_emulate_ops (MonoCompile *cfg)
1879 gboolean inlined_wrapper = FALSE;
1881 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1884 MONO_BB_FOR_EACH_INS (bb, ins) {
1885 int op_noimm = mono_op_imm_to_op (ins->opcode);
1886 MonoJitICallInfo *info;
1889 * These opcodes don't have logical equivalence to the emulating native
1890 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1892 if (MONO_HAS_CUSTOM_EMULATION (ins))
1896 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1897 * to check whether its non-imm counterpart is emulated and, if so,
1898 * decompose it back to its non-imm counterpart.
1901 info = mono_find_jit_opcode_emulation (op_noimm);
1903 info = mono_find_jit_opcode_emulation (ins->opcode);
1908 MonoBasicBlock *first_bb;
1910 /* Create dummy MonoInst's for the arguments */
1911 g_assert (!info->sig->hasthis);
1912 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1915 mono_decompose_op_imm (cfg, bb, ins);
1917 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1918 if (info->sig->param_count > 0) {
1919 int sregs [MONO_MAX_SRC_REGS];
1921 num_sregs = mono_inst_get_src_registers (ins, sregs);
1922 g_assert (num_sregs == info->sig->param_count);
1923 for (i = 0; i < num_sregs; ++i) {
1924 MONO_INST_NEW (cfg, args [i], OP_ARG);
1925 args [i]->dreg = sregs [i];
1929 /* We emit the call on a separate dummy basic block */
1930 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1931 first_bb = cfg->cbb;
1933 call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
1934 call->dreg = ins->dreg;
1936 /* Replace ins with the emitted code and do the necessary bb linking */
1937 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1938 MonoInst *saved_prev = ins->prev;
1940 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1941 first_bb->code = first_bb->last_ins = NULL;
1942 first_bb->in_count = first_bb->out_count = 0;
1943 cfg->cbb = first_bb;
1945 /* ins is hanging, continue scanning the emitted code */
1948 g_error ("Failed to emit emulation code");
1950 inlined_wrapper = TRUE;
1956 * Avoid rerunning these passes by emitting directly the exception checkpoint
1957 * at IR level, instead of inlining the icall wrapper. FIXME
1959 if (inlined_wrapper) {
1960 if (!COMPILE_LLVM (cfg))
1961 mono_decompose_long_opts (cfg);
1962 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1963 mono_local_cprop (cfg);
1967 #else /* !DISABLE_JIT */
1969 MONO_EMPTY_SOURCE_FILE (decompose);
1971 #endif /* !DISABLE_JIT */