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);
936 #ifdef TARGET_POWERPC
937 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
939 if (tree->inst_c1 == 32) {
941 /* The original code had this comment: */
942 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
943 * later apply the speedup to the left shift as well
946 /* just move the upper half to the lower and zero the high word */
947 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
948 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
953 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
957 switch (next->opcode) {
962 /* Branchless version based on gcc code */
963 d1 = alloc_ireg (cfg);
964 d2 = alloc_ireg (cfg);
965 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
966 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
967 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
968 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
969 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
981 /* Convert into three comparisons + branches */
982 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
983 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
984 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
985 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
986 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
987 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
993 /* Branchless version based on gcc code */
994 d1 = alloc_ireg (cfg);
995 d2 = alloc_ireg (cfg);
996 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
997 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
998 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1000 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1001 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1009 MonoBasicBlock *set_to_0, *set_to_1;
1011 NEW_BBLOCK (cfg, set_to_0);
1012 NEW_BBLOCK (cfg, set_to_1);
1014 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1015 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1016 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1017 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1018 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1019 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1020 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1021 MONO_START_BB (cfg, set_to_1);
1022 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1023 MONO_START_BB (cfg, set_to_0);
1028 g_assert_not_reached ();
1033 /* Not yet used, since lcompare is decomposed before local cprop */
1034 case OP_LCOMPARE_IMM: {
1035 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1036 guint32 low_imm = tree->inst_ls_word;
1037 guint32 high_imm = tree->inst_ms_word;
1038 int low_reg = MONO_LVREG_LS (tree->sreg1);
1039 int high_reg = MONO_LVREG_MS (tree->sreg1);
1043 switch (next->opcode) {
1048 /* Branchless version based on gcc code */
1049 d1 = alloc_ireg (cfg);
1050 d2 = alloc_ireg (cfg);
1051 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1052 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1053 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1054 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1055 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1068 /* Convert into three comparisons + branches */
1069 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1070 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1071 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1072 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1073 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1074 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1080 /* Branchless version based on gcc code */
1081 d1 = alloc_ireg (cfg);
1082 d2 = alloc_ireg (cfg);
1083 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1084 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1085 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1087 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1088 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1096 MonoBasicBlock *set_to_0, *set_to_1;
1098 NEW_BBLOCK (cfg, set_to_0);
1099 NEW_BBLOCK (cfg, set_to_1);
1101 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1102 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1103 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1104 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1105 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1106 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1107 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1108 MONO_START_BB (cfg, set_to_1);
1109 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1110 MONO_START_BB (cfg, set_to_0);
1115 g_assert_not_reached ();
1124 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1127 /* Replace the original instruction with the new code sequence */
1129 /* Ignore the new value of prev */
1131 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1133 /* Process the newly added ops again since they can be long ops too */
1135 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1137 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1139 first_bb->code = first_bb->last_ins = NULL;
1140 first_bb->in_count = first_bb->out_count = 0;
1141 cfg->cbb = first_bb;
1145 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1152 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1153 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1158 * mono_decompose_vtype_opts:
1160 * Decompose valuetype opcodes.
1163 mono_decompose_vtype_opts (MonoCompile *cfg)
1165 MonoBasicBlock *bb, *first_bb;
1168 * Using OP_V opcodes and decomposing them later have two main benefits:
1169 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1171 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1172 * enabling optimizations to work on vtypes too.
1173 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1174 * can be executed anytime. It should be executed as late as possible so vtype
1175 * opcodes can be optimized by the other passes.
1176 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1177 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1179 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1180 * when OP_VMOVE opcodes are decomposed.
1184 * Vregs have no associated type information, so we store the type of the vregs
1189 * Create a dummy bblock and emit code into it so we can use the normal
1190 * code generation macros.
1192 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1193 first_bb = cfg->cbb;
1195 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1197 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1199 MonoInst *prev = NULL;
1200 MonoInst *src_var, *dest_var, *src, *dest;
1204 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1206 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1212 for (ins = bb->code; ins; ins = ins->next) {
1213 switch (ins->opcode) {
1215 g_assert (ins->klass);
1216 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1218 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1219 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1222 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1225 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1228 if (src_var->backend.is_pinvoke)
1229 dest_var->backend.is_pinvoke = 1;
1231 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1232 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1234 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1238 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1241 g_assert (ins->klass);
1243 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1244 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1246 if (cfg->compute_gc_maps) {
1250 * Tell the GC map code that the vtype is considered live after
1251 * the initialization.
1253 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1254 tmp->inst_c1 = ins->dreg;
1255 MONO_ADD_INS (cfg->cbb, tmp);
1258 case OP_DUMMY_VZERO:
1259 if (COMPILE_LLVM (cfg))
1264 case OP_STOREV_MEMBASE: {
1265 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1267 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !cfg->gen_write_barriers)
1271 g_assert (ins->klass);
1272 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1275 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1277 dreg = alloc_preg (cfg);
1278 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1279 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1282 case OP_LOADV_MEMBASE: {
1283 g_assert (ins->klass);
1284 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1287 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1291 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1293 dreg = alloc_preg (cfg);
1294 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1295 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1296 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1299 case OP_OUTARG_VT: {
1300 if (COMPILE_LLVM (cfg))
1303 g_assert (ins->klass);
1305 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1307 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1308 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1310 mono_arch_emit_outarg_vt (cfg, ins, src);
1312 /* This might be decomposed into other vtype opcodes */
1316 case OP_OUTARG_VTRETADDR: {
1317 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1319 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1321 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1322 // FIXME: src_var->backend.is_pinvoke ?
1324 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1325 src->dreg = ins->dreg;
1330 case OP_VCALL_MEMBASE: {
1331 MonoCallInst *call = (MonoCallInst*)ins;
1334 if (COMPILE_LLVM (cfg))
1337 if (call->vret_in_reg) {
1338 MonoCallInst *call2;
1340 /* Replace the vcall with a scalar call */
1341 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1342 memcpy (call2, call, sizeof (MonoCallInst));
1343 switch (ins->opcode) {
1345 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1348 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1350 case OP_VCALL_MEMBASE:
1351 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1354 call2->inst.dreg = alloc_preg (cfg);
1355 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1357 /* Compute the vtype location */
1358 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1360 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1361 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1363 /* Save the result */
1364 if (dest_var->backend.is_pinvoke)
1365 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1367 size = mono_type_size (dest_var->inst_vtype, NULL);
1370 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1373 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1377 if (call->vret_in_reg_fp)
1378 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1380 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1386 if (call->vret_in_reg_fp) {
1387 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1390 #if SIZEOF_REGISTER == 4
1392 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1393 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1395 switch (call2->inst.opcode) {
1397 call2->inst.opcode = OP_LCALL;
1400 call2->inst.opcode = OP_LCALL_REG;
1402 case OP_CALL_MEMBASE:
1403 call2->inst.opcode = OP_LCALL_MEMBASE;
1406 call2->inst.dreg = alloc_lreg (cfg);
1407 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1408 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1410 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1414 /* This assumes the vtype is sizeof (gpointer) long */
1415 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1419 switch (ins->opcode) {
1421 ins->opcode = OP_VCALL2;
1424 ins->opcode = OP_VCALL2_REG;
1426 case OP_VCALL_MEMBASE:
1427 ins->opcode = OP_VCALL2_MEMBASE;
1438 g_assert (cfg->cbb == first_bb);
1440 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1441 /* Replace the original instruction with the new code sequence */
1443 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1444 first_bb->code = first_bb->last_ins = NULL;
1445 first_bb->in_count = first_bb->out_count = 0;
1446 cfg->cbb = first_bb;
1453 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1457 inline static MonoInst *
1458 mono_get_domainvar (MonoCompile *cfg)
1460 if (!cfg->domainvar)
1461 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1462 return cfg->domainvar;
1466 * mono_decompose_array_access_opts:
1468 * Decompose array access opcodes.
1471 mono_decompose_array_access_opts (MonoCompile *cfg)
1473 MonoBasicBlock *bb, *first_bb;
1476 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1477 * can be executed anytime. It should be run before decompose_long
1481 * Create a dummy bblock and emit code into it so we can use the normal
1482 * code generation macros.
1484 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1485 first_bb = cfg->cbb;
1487 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1489 MonoInst *prev = NULL;
1491 MonoInst *iargs [3];
1494 if (!bb->has_array_access)
1497 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1499 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1505 for (ins = bb->code; ins; ins = ins->next) {
1506 switch (ins->opcode) {
1508 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1509 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1510 MONO_ADD_INS (cfg->cbb, dest);
1512 case OP_BOUNDS_CHECK:
1513 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1514 if (COMPILE_LLVM (cfg))
1515 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1517 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1520 if (cfg->opt & MONO_OPT_SHARED) {
1521 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1522 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1523 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1524 iargs [2]->dreg = ins->sreg1;
1526 dest = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
1527 dest->dreg = ins->dreg;
1529 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1530 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1531 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1533 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1534 NEW_VTABLECONST (cfg, iargs [0], vtable);
1535 MONO_ADD_INS (cfg->cbb, iargs [0]);
1536 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1537 iargs [1]->dreg = ins->sreg1;
1540 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1542 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1543 dest->dreg = ins->dreg;
1547 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1548 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1554 g_assert (cfg->cbb == first_bb);
1556 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1557 /* Replace the original instruction with the new code sequence */
1559 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1560 first_bb->code = first_bb->last_ins = NULL;
1561 first_bb->in_count = first_bb->out_count = 0;
1562 cfg->cbb = first_bb;
1569 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1579 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1582 * mono_decompose_soft_float:
1584 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1585 * similar to long support on 32 bit platforms. 32 bit float values require special
1586 * handling when used as locals, arguments, and in calls.
1587 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1590 mono_decompose_soft_float (MonoCompile *cfg)
1592 MonoBasicBlock *bb, *first_bb;
1595 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1599 * Create a dummy bblock and emit code into it so we can use the normal
1600 * code generation macros.
1602 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1603 first_bb = cfg->cbb;
1605 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1607 MonoInst *prev = NULL;
1610 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1612 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1618 for (ins = bb->code; ins; ins = ins->next) {
1619 const char *spec = INS_INFO (ins->opcode);
1621 /* Most fp operations are handled automatically by opcode emulation */
1623 switch (ins->opcode) {
1626 d.vald = *(double*)ins->inst_p0;
1627 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1632 /* We load the r8 value */
1633 d.vald = *(float*)ins->inst_p0;
1634 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1638 ins->opcode = OP_LMOVE;
1641 ins->opcode = OP_MOVE;
1642 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1645 ins->opcode = OP_MOVE;
1646 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1649 int reg = ins->sreg1;
1651 ins->opcode = OP_SETLRET;
1653 ins->sreg1 = MONO_LVREG_LS (reg);
1654 ins->sreg2 = MONO_LVREG_MS (reg);
1657 case OP_LOADR8_MEMBASE:
1658 ins->opcode = OP_LOADI8_MEMBASE;
1660 case OP_STORER8_MEMBASE_REG:
1661 ins->opcode = OP_STOREI8_MEMBASE_REG;
1663 case OP_STORER4_MEMBASE_REG: {
1664 MonoInst *iargs [2];
1667 /* Arg 1 is the double value */
1668 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1669 iargs [0]->dreg = ins->sreg1;
1671 /* Arg 2 is the address to store to */
1672 addr_reg = mono_alloc_preg (cfg);
1673 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1674 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1678 case OP_LOADR4_MEMBASE: {
1679 MonoInst *iargs [1];
1683 addr_reg = mono_alloc_preg (cfg);
1684 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1685 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1686 conv->dreg = ins->dreg;
1691 case OP_FCALL_MEMBASE: {
1692 MonoCallInst *call = (MonoCallInst*)ins;
1693 if (call->signature->ret->type == MONO_TYPE_R4) {
1694 MonoCallInst *call2;
1695 MonoInst *iargs [1];
1699 /* Convert the call into a call returning an int */
1700 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1701 memcpy (call2, call, sizeof (MonoCallInst));
1702 switch (ins->opcode) {
1704 call2->inst.opcode = OP_CALL;
1707 call2->inst.opcode = OP_CALL_REG;
1709 case OP_FCALL_MEMBASE:
1710 call2->inst.opcode = OP_CALL_MEMBASE;
1713 g_assert_not_reached ();
1715 call2->inst.dreg = mono_alloc_ireg (cfg);
1716 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1718 /* Remap OUTARG_VT instructions referencing this call */
1719 for (l = call->outarg_vts; l; l = l->next)
1720 ((MonoInst*)(l->data))->inst_p0 = call2;
1722 /* FIXME: Optimize this */
1724 /* Emit an r4->r8 conversion */
1725 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1726 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1727 conv->dreg = ins->dreg;
1729 /* The call sequence might include fp ins */
1732 switch (ins->opcode) {
1734 ins->opcode = OP_LCALL;
1737 ins->opcode = OP_LCALL_REG;
1739 case OP_FCALL_MEMBASE:
1740 ins->opcode = OP_LCALL_MEMBASE;
1743 g_assert_not_reached ();
1749 MonoJitICallInfo *info;
1750 MonoInst *iargs [2];
1751 MonoInst *call, *cmp, *br;
1753 /* Convert fcompare+fbcc to icall+icompare+beq */
1756 /* The branch might be optimized away */
1761 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1763 /* The branch might be optimized away */
1768 /* Create dummy MonoInst's for the arguments */
1769 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1770 iargs [0]->dreg = ins->sreg1;
1771 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1772 iargs [1]->dreg = ins->sreg2;
1774 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1776 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1777 cmp->sreg1 = call->dreg;
1779 MONO_ADD_INS (cfg->cbb, cmp);
1781 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1782 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1783 br->inst_true_bb = ins->next->inst_true_bb;
1784 br->inst_false_bb = ins->next->inst_false_bb;
1785 MONO_ADD_INS (cfg->cbb, br);
1787 /* The call sequence might include fp ins */
1790 /* Skip fbcc or fccc */
1791 NULLIFY_INS (ins->next);
1799 MonoJitICallInfo *info;
1800 MonoInst *iargs [2];
1803 /* Convert fccc to icall+icompare+iceq */
1805 info = mono_find_jit_opcode_emulation (ins->opcode);
1808 /* Create dummy MonoInst's for the arguments */
1809 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1810 iargs [0]->dreg = ins->sreg1;
1811 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1812 iargs [1]->dreg = ins->sreg2;
1814 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1816 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1817 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1819 /* The call sequence might include fp ins */
1824 MonoInst *iargs [2];
1825 MonoInst *call, *cmp;
1827 /* Convert to icall+icompare+cond_exc+move */
1829 /* Create dummy MonoInst's for the arguments */
1830 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1831 iargs [0]->dreg = ins->sreg1;
1833 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1835 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1836 cmp->sreg1 = call->dreg;
1838 MONO_ADD_INS (cfg->cbb, cmp);
1840 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1842 /* Do the assignment if the value is finite */
1843 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1849 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1850 mono_print_ins (ins);
1851 g_assert_not_reached ();
1856 g_assert (cfg->cbb == first_bb);
1858 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1859 /* Replace the original instruction with the new code sequence */
1861 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1862 first_bb->code = first_bb->last_ins = NULL;
1863 first_bb->in_count = first_bb->out_count = 0;
1864 cfg->cbb = first_bb;
1871 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1874 mono_decompose_long_opts (cfg);
1880 mono_local_emulate_ops (MonoCompile *cfg)
1883 gboolean inlined_wrapper = FALSE;
1885 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1888 MONO_BB_FOR_EACH_INS (bb, ins) {
1889 int op_noimm = mono_op_imm_to_op (ins->opcode);
1890 MonoJitICallInfo *info;
1893 * These opcodes don't have logical equivalence to the emulating native
1894 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1896 if (MONO_HAS_CUSTOM_EMULATION (ins))
1900 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1901 * to check whether its non-imm counterpart is emulated and, if so,
1902 * decompose it back to its non-imm counterpart.
1905 info = mono_find_jit_opcode_emulation (op_noimm);
1907 info = mono_find_jit_opcode_emulation (ins->opcode);
1912 MonoBasicBlock *first_bb;
1914 /* Create dummy MonoInst's for the arguments */
1915 g_assert (!info->sig->hasthis);
1916 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1919 mono_decompose_op_imm (cfg, bb, ins);
1921 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1922 if (info->sig->param_count > 0) {
1923 int sregs [MONO_MAX_SRC_REGS];
1925 num_sregs = mono_inst_get_src_registers (ins, sregs);
1926 g_assert (num_sregs == info->sig->param_count);
1927 for (i = 0; i < num_sregs; ++i) {
1928 MONO_INST_NEW (cfg, args [i], OP_ARG);
1929 args [i]->dreg = sregs [i];
1933 /* We emit the call on a separate dummy basic block */
1934 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1935 first_bb = cfg->cbb;
1937 call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
1938 call->dreg = ins->dreg;
1940 /* Replace ins with the emitted code and do the necessary bb linking */
1941 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1942 MonoInst *saved_prev = ins->prev;
1944 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1945 first_bb->code = first_bb->last_ins = NULL;
1946 first_bb->in_count = first_bb->out_count = 0;
1947 cfg->cbb = first_bb;
1949 /* ins is hanging, continue scanning the emitted code */
1952 g_error ("Failed to emit emulation code");
1954 inlined_wrapper = TRUE;
1960 * Avoid rerunning these passes by emitting directly the exception checkpoint
1961 * at IR level, instead of inlining the icall wrapper. FIXME
1963 if (inlined_wrapper) {
1964 if (!COMPILE_LLVM (cfg))
1965 mono_decompose_long_opts (cfg);
1966 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1967 mono_local_cprop (cfg);
1971 #endif /* DISABLE_JIT */