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>
21 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
22 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
23 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
24 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
27 * Decompose complex long opcodes on 64 bit machines.
28 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
31 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
33 MonoInst *repl = NULL;
37 switch (ins->opcode) {
39 ins->opcode = OP_SEXT_I4;
43 if (SIZEOF_VOID_P == 4)
44 ins->opcode = OP_LMOVE;
46 ins->opcode = OP_MOVE;
49 if (SIZEOF_VOID_P == 4)
51 ins->opcode = OP_SEXT_I4;
53 ins->opcode = OP_MOVE;
56 if (SIZEOF_VOID_P == 4) {
58 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
61 ins->opcode = OP_MOVE;
65 ins->opcode = OP_SEXT_I4;
68 ins->opcode = OP_ZEXT_I4;
71 /* Clean out the upper word */
72 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
78 if (COMPILE_LLVM (cfg))
80 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
84 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
85 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
89 case OP_LADD_OVF_UN: {
92 if (COMPILE_LLVM (cfg))
94 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
98 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
99 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
103 #ifndef __mono_ppc64__
107 if (COMPILE_LLVM (cfg))
109 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
113 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
114 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
118 case OP_LSUB_OVF_UN: {
121 if (COMPILE_LLVM (cfg))
123 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
127 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
128 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
134 case OP_ICONV_TO_OVF_I8:
135 case OP_ICONV_TO_OVF_I:
136 ins->opcode = OP_SEXT_I4;
138 case OP_ICONV_TO_OVF_U8:
139 case OP_ICONV_TO_OVF_U:
140 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
141 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
142 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
145 case OP_ICONV_TO_OVF_I8_UN:
146 case OP_ICONV_TO_OVF_U8_UN:
147 case OP_ICONV_TO_OVF_I_UN:
148 case OP_ICONV_TO_OVF_U_UN:
149 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
150 /* Clean out the upper word */
151 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
154 case OP_LCONV_TO_OVF_I1:
155 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
156 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
157 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
158 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
159 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
162 case OP_LCONV_TO_OVF_I1_UN:
163 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
164 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
165 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
168 case OP_LCONV_TO_OVF_U1:
169 /* probe value to be within 0 to 255 */
170 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
171 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
172 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
175 case OP_LCONV_TO_OVF_U1_UN:
176 /* probe value to be within 0 to 255 */
177 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
178 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
179 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
182 case OP_LCONV_TO_OVF_I2:
183 /* Probe value to be within -32768 and 32767 */
184 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
185 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
186 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
187 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
188 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
191 case OP_LCONV_TO_OVF_I2_UN:
192 /* Probe value to be within 0 and 32767 */
193 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
194 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
195 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
198 case OP_LCONV_TO_OVF_U2:
199 /* Probe value to be within 0 and 65535 */
200 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
201 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
202 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
205 case OP_LCONV_TO_OVF_U2_UN:
206 /* Probe value to be within 0 and 65535 */
207 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
208 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
209 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
212 case OP_LCONV_TO_OVF_I4:
213 #if SIZEOF_VOID_P == 4
214 case OP_LCONV_TO_OVF_I:
216 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
217 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
218 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
219 #if SIZEOF_REGISTER == 8
220 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
222 g_assert (COMPILE_LLVM (cfg));
223 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
225 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
226 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
229 case OP_LCONV_TO_OVF_I4_UN:
230 #if SIZEOF_VOID_P == 4
231 case OP_LCONV_TO_OVF_I_UN:
233 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
234 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
235 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
238 case OP_LCONV_TO_OVF_U4:
239 #if SIZEOF_VOID_P == 4
240 case OP_LCONV_TO_OVF_U:
242 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
243 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
244 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
245 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
246 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
249 case OP_LCONV_TO_OVF_U4_UN:
250 #if SIZEOF_VOID_P == 4
251 case OP_LCONV_TO_OVF_U_UN:
253 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
254 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
255 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
258 #if SIZEOF_VOID_P == 8
259 case OP_LCONV_TO_OVF_I:
260 case OP_LCONV_TO_OVF_U_UN:
262 case OP_LCONV_TO_OVF_U8_UN:
263 case OP_LCONV_TO_OVF_I8:
264 ins->opcode = OP_MOVE;
266 #if SIZEOF_VOID_P == 8
267 case OP_LCONV_TO_OVF_I_UN:
269 case OP_LCONV_TO_OVF_I8_UN:
270 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
271 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
272 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
275 case OP_LCONV_TO_OVF_U8:
276 #if SIZEOF_VOID_P == 8
277 case OP_LCONV_TO_OVF_U:
279 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
280 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
281 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
293 * mono_decompose_opcode:
295 * Decompose complex opcodes into ones closer to opcodes supported by
296 * the given architecture.
297 * Returns a MonoInst which represents the result of the decomposition, and can
298 * be pushed on the IL stack. This is needed because the original instruction is
300 * Sets the cfg exception if an opcode is not supported.
303 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
305 MonoInst *repl = NULL;
306 int type = ins->type;
307 int dreg = ins->dreg;
308 gboolean emulate = FALSE;
310 /* FIXME: Instead of = NOP, don't emit the original ins at all */
311 mono_arch_decompose_opts (cfg, ins);
314 * The code below assumes that we are called immediately after emitting
315 * ins. This means we can emit code using the normal code generation
318 switch (ins->opcode) {
319 /* this doesn't make sense on ppc and other architectures */
320 #if !defined(MONO_ARCH_NO_IOV_CHECK)
322 if (COMPILE_LLVM (cfg))
324 ins->opcode = OP_IADDCC;
325 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
328 if (COMPILE_LLVM (cfg))
330 ins->opcode = OP_IADDCC;
331 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
334 if (COMPILE_LLVM (cfg))
336 ins->opcode = OP_ISUBCC;
337 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
340 if (COMPILE_LLVM (cfg))
342 ins->opcode = OP_ISUBCC;
343 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
346 case OP_ICONV_TO_OVF_I1:
347 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
348 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
349 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
350 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
351 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
354 case OP_ICONV_TO_OVF_I1_UN:
355 /* probe values between 0 to 127 */
356 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
357 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
358 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
361 case OP_ICONV_TO_OVF_U1:
362 case OP_ICONV_TO_OVF_U1_UN:
363 /* probe value to be within 0 to 255 */
364 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
365 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
366 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
369 case OP_ICONV_TO_OVF_I2:
370 /* Probe value to be within -32768 and 32767 */
371 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
372 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
373 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
374 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
375 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
378 case OP_ICONV_TO_OVF_I2_UN:
379 /* Convert uint value into short, value within 0 and 32767 */
380 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
381 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
382 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
385 case OP_ICONV_TO_OVF_U2:
386 case OP_ICONV_TO_OVF_U2_UN:
387 /* Probe value to be within 0 and 65535 */
388 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
389 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
390 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
393 case OP_ICONV_TO_OVF_U4:
394 case OP_ICONV_TO_OVF_I4_UN:
395 #if SIZEOF_VOID_P == 4
396 case OP_ICONV_TO_OVF_U:
397 case OP_ICONV_TO_OVF_I_UN:
399 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
400 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
401 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
406 case OP_ICONV_TO_OVF_I4:
407 case OP_ICONV_TO_OVF_U4_UN:
408 #if SIZEOF_VOID_P == 4
409 case OP_ICONV_TO_OVF_I:
410 case OP_ICONV_TO_OVF_U_UN:
412 ins->opcode = OP_MOVE;
415 #if SIZEOF_VOID_P == 8
416 ins->opcode = OP_SEXT_I4;
418 ins->opcode = OP_MOVE;
422 #if SIZEOF_VOID_P == 8
423 ins->opcode = OP_ZEXT_I4;
425 ins->opcode = OP_MOVE;
430 ins->opcode = OP_FMOVE;
433 case OP_FCONV_TO_OVF_I1_UN:
434 case OP_FCONV_TO_OVF_I2_UN:
435 case OP_FCONV_TO_OVF_I4_UN:
436 case OP_FCONV_TO_OVF_I8_UN:
437 case OP_FCONV_TO_OVF_U1_UN:
438 case OP_FCONV_TO_OVF_U2_UN:
439 case OP_FCONV_TO_OVF_U4_UN:
440 case OP_FCONV_TO_OVF_U8_UN:
441 case OP_FCONV_TO_OVF_I_UN:
442 case OP_FCONV_TO_OVF_U_UN:
443 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
450 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
453 if (cfg->backend->need_div_check) {
454 int reg1 = alloc_ireg (cfg);
455 int reg2 = alloc_ireg (cfg);
457 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
458 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
459 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
460 /* b == -1 && a == 0x80000000 */
461 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
462 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
463 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
464 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
465 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
466 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
467 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
470 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
475 #if SIZEOF_VOID_P == 8
480 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
483 if (cfg->backend->need_div_check) {
484 int reg1 = alloc_ireg (cfg);
485 int reg2 = alloc_ireg (cfg);
486 int reg3 = alloc_ireg (cfg);
488 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
489 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
490 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
491 /* b == -1 && a == 0x80000000 */
492 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
493 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
494 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
495 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
496 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
497 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
498 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
499 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
500 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
503 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
515 if (cfg->backend->need_div_check) {
516 int reg1 = alloc_ireg (cfg);
518 if (ins->inst_imm == 0) {
519 // FIXME: Optimize this
520 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
521 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
522 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
524 if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
525 (ins->inst_imm == -1)) {
526 /* b == -1 && a == 0x80000000 */
527 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
528 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
530 MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
543 #if SIZEOF_REGISTER == 8
544 if (decompose_long_opcode (cfg, ins, &repl))
547 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
551 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
552 cfg->has_emulated_ops = TRUE;
555 if (ins->opcode == OP_NOP) {
560 /* Use the last emitted instruction */
561 ins = cfg->cbb->last_ins;
564 g_assert (ins->dreg == dreg);
572 #if SIZEOF_REGISTER == 4
573 static int lbr_decomp [][2] = {
575 {OP_IBGT, OP_IBGE_UN}, /* BGE */
576 {OP_IBGT, OP_IBGT_UN}, /* BGT */
577 {OP_IBLT, OP_IBLE_UN}, /* BLE */
578 {OP_IBLT, OP_IBLT_UN}, /* BLT */
580 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
581 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
582 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
583 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
586 static int lcset_decomp [][2] = {
588 {OP_IBLT, OP_IBLE_UN}, /* CGT */
589 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
590 {OP_IBGT, OP_IBGE_UN}, /* CLT */
591 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
596 * mono_decompose_long_opts:
598 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
601 mono_decompose_long_opts (MonoCompile *cfg)
603 #if SIZEOF_REGISTER == 4
604 MonoBasicBlock *bb, *first_bb;
607 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
608 * needs to be able to handle long vregs.
612 * Create a dummy bblock and emit code into it so we can use the normal
613 * code generation macros.
615 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
618 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
619 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
620 MonoInst *prev = NULL;
623 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
626 cfg->cbb->code = cfg->cbb->last_ins = NULL;
629 mono_arch_decompose_long_opts (cfg, tree);
631 switch (tree->opcode) {
633 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
634 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
636 case OP_DUMMY_I8CONST:
637 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
638 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
643 case OP_LCONV_TO_OVF_U8_UN:
644 case OP_LCONV_TO_OVF_I8:
645 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
646 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
648 case OP_STOREI8_MEMBASE_REG:
649 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));
650 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));
652 case OP_LOADI8_MEMBASE:
653 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);
654 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);
657 case OP_ICONV_TO_I8: {
658 guint32 tmpreg = alloc_ireg (cfg);
662 * tmp = low > -1 ? 1: 0;
663 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
665 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
666 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
667 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
668 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
672 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
673 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
675 case OP_ICONV_TO_OVF_I8:
676 /* a signed 32 bit num always fits in a signed 64 bit one */
677 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
678 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
680 case OP_ICONV_TO_OVF_U8:
681 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
682 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
683 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
684 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
686 case OP_ICONV_TO_OVF_I8_UN:
687 case OP_ICONV_TO_OVF_U8_UN:
688 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
689 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
690 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
693 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
696 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
699 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
702 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
708 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
710 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
712 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
715 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
717 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
720 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
721 case OP_LCONV_TO_R_UN:
722 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
725 case OP_LCONV_TO_OVF_I1: {
726 MonoBasicBlock *is_negative, *end_label;
728 NEW_BBLOCK (cfg, is_negative);
729 NEW_BBLOCK (cfg, end_label);
731 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
732 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
733 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
734 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
736 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
737 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
740 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
741 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
742 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
745 MONO_START_BB (cfg, is_negative);
746 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
747 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
749 MONO_START_BB (cfg, end_label);
751 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
754 case OP_LCONV_TO_OVF_I1_UN:
755 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
756 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
758 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
759 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
760 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
761 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
762 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
764 case OP_LCONV_TO_OVF_U1:
765 case OP_LCONV_TO_OVF_U1_UN:
766 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
767 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
769 /* probe value to be within 0 to 255 */
770 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
771 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
772 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
774 case OP_LCONV_TO_OVF_I2: {
775 MonoBasicBlock *is_negative, *end_label;
777 NEW_BBLOCK (cfg, is_negative);
778 NEW_BBLOCK (cfg, end_label);
780 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
781 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
783 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
785 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
786 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
789 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
790 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
791 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
794 MONO_START_BB (cfg, is_negative);
795 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
796 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
797 MONO_START_BB (cfg, end_label);
799 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
802 case OP_LCONV_TO_OVF_I2_UN:
803 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
804 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
806 /* Probe value to be within -32768 and 32767 */
807 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
808 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
809 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
810 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
811 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
813 case OP_LCONV_TO_OVF_U2:
814 case OP_LCONV_TO_OVF_U2_UN:
815 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
816 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
818 /* Probe value to be within 0 and 65535 */
819 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
820 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
821 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
823 case OP_LCONV_TO_OVF_I4:
824 case OP_LCONV_TO_OVF_I:
825 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
827 case OP_LCONV_TO_OVF_U4:
828 case OP_LCONV_TO_OVF_U:
829 case OP_LCONV_TO_OVF_U4_UN:
830 case OP_LCONV_TO_OVF_U_UN:
831 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
832 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
833 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
835 case OP_LCONV_TO_OVF_I_UN:
836 case OP_LCONV_TO_OVF_I4_UN:
837 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
838 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
839 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
840 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
841 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
843 case OP_LCONV_TO_OVF_U8:
844 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
845 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
847 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
848 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
850 case OP_LCONV_TO_OVF_I8_UN:
851 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
852 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
854 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
855 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
859 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
860 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
863 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
864 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
868 /* ADC sets the condition code */
869 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
870 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
871 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
874 /* ADC sets the condition code */
875 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
876 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
877 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
880 /* SBB sets the condition code */
881 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
882 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
883 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
886 /* SBB sets the condition code */
887 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
888 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
889 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
892 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
893 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
896 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
897 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
900 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
901 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
904 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
905 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
908 /* Handled in mono_arch_decompose_long_opts () */
909 g_assert_not_reached ();
913 /* FIXME: Add OP_BIGMUL optimization */
917 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
918 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
922 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
930 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
934 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
937 if (tree->inst_c1 == 32) {
939 /* The original code had this comment: */
940 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
941 * later apply the speedup to the left shift as well
944 /* FIXME: Move this to the strength reduction pass */
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);
951 if (tree->inst_c1 == 32) {
952 /* just move the lower half to the upper and zero the lower word */
953 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
954 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
959 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
963 switch (next->opcode) {
968 /* Branchless version based on gcc code */
969 d1 = alloc_ireg (cfg);
970 d2 = alloc_ireg (cfg);
971 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
972 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
973 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
974 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
975 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
987 /* Convert into three comparisons + branches */
988 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
989 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
990 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
991 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
992 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
993 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
999 /* Branchless version based on gcc code */
1000 d1 = alloc_ireg (cfg);
1001 d2 = alloc_ireg (cfg);
1002 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1003 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1004 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1006 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1007 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1015 MonoBasicBlock *set_to_0, *set_to_1;
1017 NEW_BBLOCK (cfg, set_to_0);
1018 NEW_BBLOCK (cfg, set_to_1);
1020 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1021 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1022 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1023 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1024 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1025 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1026 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1027 MONO_START_BB (cfg, set_to_1);
1028 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1029 MONO_START_BB (cfg, set_to_0);
1034 g_assert_not_reached ();
1039 /* Not yet used, since lcompare is decomposed before local cprop */
1040 case OP_LCOMPARE_IMM: {
1041 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1042 guint32 low_imm = tree->inst_ls_word;
1043 guint32 high_imm = tree->inst_ms_word;
1044 int low_reg = MONO_LVREG_LS (tree->sreg1);
1045 int high_reg = MONO_LVREG_MS (tree->sreg1);
1049 switch (next->opcode) {
1054 /* Branchless version based on gcc code */
1055 d1 = alloc_ireg (cfg);
1056 d2 = alloc_ireg (cfg);
1057 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1058 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1059 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1060 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1061 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1074 /* Convert into three comparisons + branches */
1075 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1076 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1077 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1078 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1079 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1080 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1086 /* Branchless version based on gcc code */
1087 d1 = alloc_ireg (cfg);
1088 d2 = alloc_ireg (cfg);
1089 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1090 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1091 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1093 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1094 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1102 MonoBasicBlock *set_to_0, *set_to_1;
1104 NEW_BBLOCK (cfg, set_to_0);
1105 NEW_BBLOCK (cfg, set_to_1);
1107 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1108 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1109 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1110 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1111 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1112 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1113 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1114 MONO_START_BB (cfg, set_to_1);
1115 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1116 MONO_START_BB (cfg, set_to_0);
1121 g_assert_not_reached ();
1130 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1133 /* Replace the original instruction with the new code sequence */
1135 /* Ignore the new value of prev */
1137 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1139 /* Process the newly added ops again since they can be long ops too */
1141 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1143 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1145 first_bb->code = first_bb->last_ins = NULL;
1146 first_bb->in_count = first_bb->out_count = 0;
1147 cfg->cbb = first_bb;
1151 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1158 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1159 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1164 * mono_decompose_vtype_opts:
1166 * Decompose valuetype opcodes.
1169 mono_decompose_vtype_opts (MonoCompile *cfg)
1171 MonoBasicBlock *bb, *first_bb;
1174 * Using OP_V opcodes and decomposing them later have two main benefits:
1175 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1177 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1178 * enabling optimizations to work on vtypes too.
1179 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1180 * can be executed anytime. It should be executed as late as possible so vtype
1181 * opcodes can be optimized by the other passes.
1182 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1183 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1185 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1186 * when OP_VMOVE opcodes are decomposed.
1190 * Vregs have no associated type information, so we store the type of the vregs
1195 * Create a dummy bblock and emit code into it so we can use the normal
1196 * code generation macros.
1198 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1199 first_bb = cfg->cbb;
1201 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1203 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1205 MonoInst *prev = NULL;
1206 MonoInst *src_var, *dest_var, *src, *dest;
1210 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1212 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1218 for (ins = bb->code; ins; ins = ins->next) {
1219 switch (ins->opcode) {
1221 g_assert (ins->klass);
1222 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1224 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1225 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1228 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1231 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1234 if (src_var->backend.is_pinvoke)
1235 dest_var->backend.is_pinvoke = 1;
1237 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1238 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1240 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1244 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1247 g_assert (ins->klass);
1249 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1250 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1252 if (cfg->compute_gc_maps) {
1256 * Tell the GC map code that the vtype is considered live after
1257 * the initialization.
1259 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1260 tmp->inst_c1 = ins->dreg;
1261 MONO_ADD_INS (cfg->cbb, tmp);
1264 case OP_DUMMY_VZERO:
1265 if (COMPILE_LLVM (cfg))
1270 case OP_STOREV_MEMBASE: {
1271 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1274 g_assert (ins->klass);
1275 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1278 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1280 dreg = alloc_preg (cfg);
1281 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1282 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1285 case OP_LOADV_MEMBASE: {
1286 g_assert (ins->klass);
1287 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1290 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1294 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1296 dreg = alloc_preg (cfg);
1297 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1298 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1299 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1302 case OP_OUTARG_VT: {
1303 if (COMPILE_LLVM (cfg))
1306 g_assert (ins->klass);
1308 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1310 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1311 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1313 mono_arch_emit_outarg_vt (cfg, ins, src);
1315 /* This might be decomposed into other vtype opcodes */
1319 case OP_OUTARG_VTRETADDR: {
1320 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1322 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1324 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1325 // FIXME: src_var->backend.is_pinvoke ?
1327 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1328 src->dreg = ins->dreg;
1333 case OP_VCALL_MEMBASE: {
1334 MonoCallInst *call = (MonoCallInst*)ins;
1337 if (COMPILE_LLVM (cfg))
1340 if (call->vret_in_reg) {
1341 MonoCallInst *call2;
1343 /* Replace the vcall with a scalar call */
1344 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1345 memcpy (call2, call, sizeof (MonoCallInst));
1346 switch (ins->opcode) {
1348 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1351 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1353 case OP_VCALL_MEMBASE:
1354 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1357 call2->inst.dreg = alloc_preg (cfg);
1358 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1360 /* Compute the vtype location */
1361 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1363 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1364 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1366 /* Save the result */
1367 if (dest_var->backend.is_pinvoke)
1368 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1370 size = mono_type_size (dest_var->inst_vtype, NULL);
1373 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1376 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1380 if (call->vret_in_reg_fp)
1381 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1383 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1389 if (call->vret_in_reg_fp) {
1390 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1393 #if SIZEOF_REGISTER == 4
1395 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1396 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1398 switch (call2->inst.opcode) {
1400 call2->inst.opcode = OP_LCALL;
1403 call2->inst.opcode = OP_LCALL_REG;
1405 case OP_CALL_MEMBASE:
1406 call2->inst.opcode = OP_LCALL_MEMBASE;
1409 call2->inst.dreg = alloc_lreg (cfg);
1410 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1411 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1413 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1417 /* This assumes the vtype is sizeof (gpointer) long */
1418 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1422 switch (ins->opcode) {
1424 ins->opcode = OP_VCALL2;
1427 ins->opcode = OP_VCALL2_REG;
1429 case OP_VCALL_MEMBASE:
1430 ins->opcode = OP_VCALL2_MEMBASE;
1441 g_assert (cfg->cbb == first_bb);
1443 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1444 /* Replace the original instruction with the new code sequence */
1446 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1447 first_bb->code = first_bb->last_ins = NULL;
1448 first_bb->in_count = first_bb->out_count = 0;
1449 cfg->cbb = first_bb;
1456 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1460 inline static MonoInst *
1461 mono_get_domainvar (MonoCompile *cfg)
1463 if (!cfg->domainvar)
1464 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1465 return cfg->domainvar;
1469 * mono_decompose_array_access_opts:
1471 * Decompose array access opcodes.
1474 mono_decompose_array_access_opts (MonoCompile *cfg)
1476 MonoBasicBlock *bb, *first_bb;
1479 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1480 * can be executed anytime. It should be run before decompose_long
1484 * Create a dummy bblock and emit code into it so we can use the normal
1485 * code generation macros.
1487 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1488 first_bb = cfg->cbb;
1490 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1492 MonoInst *prev = NULL;
1494 MonoInst *iargs [3];
1497 if (!bb->has_array_access)
1500 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1502 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1508 for (ins = bb->code; ins; ins = ins->next) {
1509 switch (ins->opcode) {
1511 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1512 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1513 MONO_ADD_INS (cfg->cbb, dest);
1515 case OP_BOUNDS_CHECK:
1516 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1517 if (COMPILE_LLVM (cfg))
1518 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1520 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1523 if (cfg->opt & MONO_OPT_SHARED) {
1524 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1525 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1526 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1527 iargs [2]->dreg = ins->sreg1;
1529 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1530 dest->dreg = ins->dreg;
1532 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1533 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1534 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1536 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1537 NEW_VTABLECONST (cfg, iargs [0], vtable);
1538 MONO_ADD_INS (cfg->cbb, iargs [0]);
1539 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1540 iargs [1]->dreg = ins->sreg1;
1543 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1545 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1546 dest->dreg = ins->dreg;
1550 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1551 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1557 g_assert (cfg->cbb == first_bb);
1559 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1560 /* Replace the original instruction with the new code sequence */
1562 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1563 first_bb->code = first_bb->last_ins = NULL;
1564 first_bb->in_count = first_bb->out_count = 0;
1565 cfg->cbb = first_bb;
1572 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1582 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1585 * mono_decompose_soft_float:
1587 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1588 * similar to long support on 32 bit platforms. 32 bit float values require special
1589 * handling when used as locals, arguments, and in calls.
1590 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1593 mono_decompose_soft_float (MonoCompile *cfg)
1595 MonoBasicBlock *bb, *first_bb;
1598 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1602 * Create a dummy bblock and emit code into it so we can use the normal
1603 * code generation macros.
1605 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1606 first_bb = cfg->cbb;
1608 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1610 MonoInst *prev = NULL;
1613 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1615 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1621 for (ins = bb->code; ins; ins = ins->next) {
1622 const char *spec = INS_INFO (ins->opcode);
1624 /* Most fp operations are handled automatically by opcode emulation */
1626 switch (ins->opcode) {
1629 d.vald = *(double*)ins->inst_p0;
1630 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1635 /* We load the r8 value */
1636 d.vald = *(float*)ins->inst_p0;
1637 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1641 ins->opcode = OP_LMOVE;
1644 ins->opcode = OP_MOVE;
1645 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1648 ins->opcode = OP_MOVE;
1649 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1652 int reg = ins->sreg1;
1654 ins->opcode = OP_SETLRET;
1656 ins->sreg1 = MONO_LVREG_LS (reg);
1657 ins->sreg2 = MONO_LVREG_MS (reg);
1660 case OP_LOADR8_MEMBASE:
1661 ins->opcode = OP_LOADI8_MEMBASE;
1663 case OP_STORER8_MEMBASE_REG:
1664 ins->opcode = OP_STOREI8_MEMBASE_REG;
1666 case OP_STORER4_MEMBASE_REG: {
1667 MonoInst *iargs [2];
1670 /* Arg 1 is the double value */
1671 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1672 iargs [0]->dreg = ins->sreg1;
1674 /* Arg 2 is the address to store to */
1675 addr_reg = mono_alloc_preg (cfg);
1676 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1677 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1681 case OP_LOADR4_MEMBASE: {
1682 MonoInst *iargs [1];
1686 addr_reg = mono_alloc_preg (cfg);
1687 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1688 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1689 conv->dreg = ins->dreg;
1694 case OP_FCALL_MEMBASE: {
1695 MonoCallInst *call = (MonoCallInst*)ins;
1696 if (call->signature->ret->type == MONO_TYPE_R4) {
1697 MonoCallInst *call2;
1698 MonoInst *iargs [1];
1702 /* Convert the call into a call returning an int */
1703 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1704 memcpy (call2, call, sizeof (MonoCallInst));
1705 switch (ins->opcode) {
1707 call2->inst.opcode = OP_CALL;
1710 call2->inst.opcode = OP_CALL_REG;
1712 case OP_FCALL_MEMBASE:
1713 call2->inst.opcode = OP_CALL_MEMBASE;
1716 g_assert_not_reached ();
1718 call2->inst.dreg = mono_alloc_ireg (cfg);
1719 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1721 /* Remap OUTARG_VT instructions referencing this call */
1722 for (l = call->outarg_vts; l; l = l->next)
1723 ((MonoInst*)(l->data))->inst_p0 = call2;
1725 /* FIXME: Optimize this */
1727 /* Emit an r4->r8 conversion */
1728 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1729 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1730 conv->dreg = ins->dreg;
1732 /* The call sequence might include fp ins */
1735 switch (ins->opcode) {
1737 ins->opcode = OP_LCALL;
1740 ins->opcode = OP_LCALL_REG;
1742 case OP_FCALL_MEMBASE:
1743 ins->opcode = OP_LCALL_MEMBASE;
1746 g_assert_not_reached ();
1752 MonoJitICallInfo *info;
1753 MonoInst *iargs [2];
1754 MonoInst *call, *cmp, *br;
1756 /* Convert fcompare+fbcc to icall+icompare+beq */
1759 /* The branch might be optimized away */
1764 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1766 /* The branch might be optimized away */
1771 /* Create dummy MonoInst's for the arguments */
1772 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1773 iargs [0]->dreg = ins->sreg1;
1774 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1775 iargs [1]->dreg = ins->sreg2;
1777 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1779 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1780 cmp->sreg1 = call->dreg;
1782 MONO_ADD_INS (cfg->cbb, cmp);
1784 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1785 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1786 br->inst_true_bb = ins->next->inst_true_bb;
1787 br->inst_false_bb = ins->next->inst_false_bb;
1788 MONO_ADD_INS (cfg->cbb, br);
1790 /* The call sequence might include fp ins */
1793 /* Skip fbcc or fccc */
1794 NULLIFY_INS (ins->next);
1802 MonoJitICallInfo *info;
1803 MonoInst *iargs [2];
1806 /* Convert fccc to icall+icompare+iceq */
1808 info = mono_find_jit_opcode_emulation (ins->opcode);
1811 /* Create dummy MonoInst's for the arguments */
1812 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1813 iargs [0]->dreg = ins->sreg1;
1814 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1815 iargs [1]->dreg = ins->sreg2;
1817 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1819 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1820 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1822 /* The call sequence might include fp ins */
1827 MonoInst *iargs [2];
1828 MonoInst *call, *cmp;
1830 /* Convert to icall+icompare+cond_exc+move */
1832 /* Create dummy MonoInst's for the arguments */
1833 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1834 iargs [0]->dreg = ins->sreg1;
1836 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1838 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1839 cmp->sreg1 = call->dreg;
1841 MONO_ADD_INS (cfg->cbb, cmp);
1843 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1845 /* Do the assignment if the value is finite */
1846 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1852 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1853 mono_print_ins (ins);
1854 g_assert_not_reached ();
1859 g_assert (cfg->cbb == first_bb);
1861 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1862 /* Replace the original instruction with the new code sequence */
1864 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1865 first_bb->code = first_bb->last_ins = NULL;
1866 first_bb->in_count = first_bb->out_count = 0;
1867 cfg->cbb = first_bb;
1874 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1877 mono_decompose_long_opts (cfg);
1883 mono_local_emulate_ops (MonoCompile *cfg)
1886 gboolean inlined_wrapper = FALSE;
1888 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1891 MONO_BB_FOR_EACH_INS (bb, ins) {
1892 int op_noimm = mono_op_imm_to_op (ins->opcode);
1893 MonoJitICallInfo *info;
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, 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 #endif /* DISABLE_JIT */