2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
12 #include "jit-icalls.h"
14 #include <mono/metadata/gc-internal.h>
18 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
19 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
20 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
21 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
24 * mono_decompose_opcode:
26 * Decompose complex opcodes into ones closer to opcodes supported by
27 * the given architecture.
28 * Returns a MonoInst which represents the result of the decomposition, and can
29 * be pushed on the IL stack. This is needed because the original instruction is
31 * Sets the cfg exception if an opcode is not supported.
34 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
36 MonoInst *repl = NULL;
40 /* FIXME: Instead of = NOP, don't emit the original ins at all */
42 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
43 mono_arch_decompose_opts (cfg, ins);
47 * The code below assumes that we are called immediately after emitting
48 * ins. This means we can emit code using the normal code generation
51 switch (ins->opcode) {
52 /* this doesn't make sense on ppc and other architectures */
53 #if !defined(MONO_ARCH_NO_IOV_CHECK)
55 if (COMPILE_LLVM (cfg))
57 ins->opcode = OP_IADDCC;
58 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
61 if (COMPILE_LLVM (cfg))
63 ins->opcode = OP_IADDCC;
64 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
67 if (COMPILE_LLVM (cfg))
69 ins->opcode = OP_ISUBCC;
70 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
73 if (COMPILE_LLVM (cfg))
75 ins->opcode = OP_ISUBCC;
76 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
79 case OP_ICONV_TO_OVF_I1:
80 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
81 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
82 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
83 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
84 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
87 case OP_ICONV_TO_OVF_I1_UN:
88 /* probe values between 0 to 127 */
89 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
90 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
91 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
94 case OP_ICONV_TO_OVF_U1:
95 case OP_ICONV_TO_OVF_U1_UN:
96 /* probe value to be within 0 to 255 */
97 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
98 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
99 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
102 case OP_ICONV_TO_OVF_I2:
103 /* Probe value to be within -32768 and 32767 */
104 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
105 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
106 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
107 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
108 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
111 case OP_ICONV_TO_OVF_I2_UN:
112 /* Convert uint value into short, value within 0 and 32767 */
113 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
114 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
115 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
118 case OP_ICONV_TO_OVF_U2:
119 case OP_ICONV_TO_OVF_U2_UN:
120 /* Probe value to be within 0 and 65535 */
121 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
122 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
123 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
126 case OP_ICONV_TO_OVF_U4:
127 case OP_ICONV_TO_OVF_I4_UN:
128 #if SIZEOF_REGISTER == 4
129 case OP_ICONV_TO_OVF_U:
130 case OP_ICONV_TO_OVF_I_UN:
132 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
133 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
134 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
139 case OP_ICONV_TO_OVF_I4:
140 case OP_ICONV_TO_OVF_U4_UN:
141 #if SIZEOF_REGISTER == 4
142 case OP_ICONV_TO_OVF_I:
143 case OP_ICONV_TO_OVF_U_UN:
145 ins->opcode = OP_MOVE;
148 #if SIZEOF_REGISTER == 8
149 ins->opcode = OP_SEXT_I4;
151 ins->opcode = OP_MOVE;
155 #if SIZEOF_REGISTER == 8
156 ins->opcode = OP_ZEXT_I4;
158 ins->opcode = OP_MOVE;
163 ins->opcode = OP_FMOVE;
166 case OP_FCONV_TO_OVF_I1_UN:
167 case OP_FCONV_TO_OVF_I2_UN:
168 case OP_FCONV_TO_OVF_I4_UN:
169 case OP_FCONV_TO_OVF_I8_UN:
170 case OP_FCONV_TO_OVF_U1_UN:
171 case OP_FCONV_TO_OVF_U2_UN:
172 case OP_FCONV_TO_OVF_U4_UN:
173 case OP_FCONV_TO_OVF_U8_UN:
174 case OP_FCONV_TO_OVF_I_UN:
175 case OP_FCONV_TO_OVF_U_UN:
176 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
177 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
180 /* Long opcodes on 64 bit machines */
181 #if SIZEOF_REGISTER == 8
183 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
190 ins->opcode = OP_MOVE;
193 ins->opcode = OP_SEXT_I4;
196 ins->opcode = OP_ZEXT_I4;
199 /* Clean out the upper word */
200 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
204 if (COMPILE_LLVM (cfg))
206 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
207 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
211 if (COMPILE_LLVM (cfg))
213 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
214 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
217 #ifndef __mono_ppc64__
219 if (COMPILE_LLVM (cfg))
221 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
222 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
226 if (COMPILE_LLVM (cfg))
228 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
229 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
234 case OP_ICONV_TO_OVF_I8:
235 case OP_ICONV_TO_OVF_I:
236 ins->opcode = OP_SEXT_I4;
238 case OP_ICONV_TO_OVF_U8:
239 case OP_ICONV_TO_OVF_U:
240 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
241 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
242 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
245 case OP_ICONV_TO_OVF_I8_UN:
246 case OP_ICONV_TO_OVF_U8_UN:
247 case OP_ICONV_TO_OVF_I_UN:
248 case OP_ICONV_TO_OVF_U_UN:
249 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
250 /* Clean out the upper word */
251 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
254 case OP_LCONV_TO_OVF_I1:
255 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
256 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
257 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
258 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
259 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
262 case OP_LCONV_TO_OVF_I1_UN:
263 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
264 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
265 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
268 case OP_LCONV_TO_OVF_U1:
269 /* probe value to be within 0 to 255 */
270 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
271 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
272 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
275 case OP_LCONV_TO_OVF_U1_UN:
276 /* probe value to be within 0 to 255 */
277 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
278 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
279 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
282 case OP_LCONV_TO_OVF_I2:
283 /* Probe value to be within -32768 and 32767 */
284 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
285 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
286 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
287 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
288 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
291 case OP_LCONV_TO_OVF_I2_UN:
292 /* Probe value to be within 0 and 32767 */
293 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
294 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
295 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
298 case OP_LCONV_TO_OVF_U2:
299 /* Probe value to be within 0 and 65535 */
300 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
301 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
302 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
305 case OP_LCONV_TO_OVF_U2_UN:
306 /* Probe value to be within 0 and 65535 */
307 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
308 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
309 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
312 case OP_LCONV_TO_OVF_I4:
313 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
314 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
315 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
316 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
317 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
318 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
321 case OP_LCONV_TO_OVF_I4_UN:
322 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
323 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
324 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
327 case OP_LCONV_TO_OVF_U4:
328 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
329 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
330 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
331 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
332 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
335 case OP_LCONV_TO_OVF_U4_UN:
336 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
337 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
338 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
341 case OP_LCONV_TO_OVF_I:
342 case OP_LCONV_TO_OVF_U_UN:
343 case OP_LCONV_TO_OVF_U8_UN:
344 case OP_LCONV_TO_OVF_I8:
345 ins->opcode = OP_MOVE;
347 case OP_LCONV_TO_OVF_I_UN:
348 case OP_LCONV_TO_OVF_I8_UN:
349 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
350 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
351 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
354 case OP_LCONV_TO_OVF_U8:
355 case OP_LCONV_TO_OVF_U:
356 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
357 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
358 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
364 MonoJitICallInfo *info;
366 info = mono_find_jit_opcode_emulation (ins->opcode);
371 /* Create dummy MonoInst's for the arguments */
372 g_assert (!info->sig->hasthis);
373 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
375 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
376 if (info->sig->param_count > 0) {
377 int sregs [MONO_MAX_SRC_REGS];
379 num_sregs = mono_inst_get_src_registers (ins, sregs);
380 g_assert (num_sregs == info->sig->param_count);
381 for (i = 0; i < num_sregs; ++i) {
382 MONO_INST_NEW (cfg, args [i], OP_ARG);
383 args [i]->dreg = sregs [i];
387 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
388 call->dreg = ins->dreg;
396 if (ins->opcode == OP_NOP) {
401 /* Use the last emitted instruction */
402 ins = cfg->cbb->last_ins;
405 g_assert (ins->dreg == dreg);
413 #if SIZEOF_REGISTER == 4
414 static int lbr_decomp [][2] = {
416 {OP_IBGT, OP_IBGE_UN}, /* BGE */
417 {OP_IBGT, OP_IBGT_UN}, /* BGT */
418 {OP_IBLT, OP_IBLE_UN}, /* BLE */
419 {OP_IBLT, OP_IBLT_UN}, /* BLT */
421 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
422 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
423 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
424 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
427 static int lcset_decomp [][2] = {
429 {OP_IBLT, OP_IBLE_UN}, /* CGT */
430 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
431 {OP_IBGT, OP_IBGE_UN}, /* CLT */
432 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
437 * mono_decompose_long_opts:
439 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
442 mono_decompose_long_opts (MonoCompile *cfg)
444 #if SIZEOF_REGISTER == 4
445 MonoBasicBlock *bb, *first_bb;
448 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
449 * needs to be able to handle long vregs.
452 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
455 * Create a dummy bblock and emit code into it so we can use the normal
456 * code generation macros.
458 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
461 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
462 MonoInst *tree = bb->code;
463 MonoInst *prev = NULL;
466 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
470 cfg->cbb->code = cfg->cbb->last_ins = NULL;
474 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
475 mono_arch_decompose_long_opts (cfg, tree);
478 switch (tree->opcode) {
480 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
481 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
486 case OP_LCONV_TO_OVF_U8_UN:
487 case OP_LCONV_TO_OVF_I8:
488 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
489 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
491 case OP_STOREI8_MEMBASE_REG:
492 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
493 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
495 case OP_LOADI8_MEMBASE:
496 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
497 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
500 case OP_ICONV_TO_I8: {
501 guint32 tmpreg = alloc_ireg (cfg);
505 * tmp = low > -1 ? 1: 0;
506 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
508 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
509 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
510 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
511 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
515 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
516 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
518 case OP_ICONV_TO_OVF_I8:
519 /* a signed 32 bit num always fits in a signed 64 bit one */
520 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
521 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
523 case OP_ICONV_TO_OVF_U8:
524 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
525 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
526 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
527 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
529 case OP_ICONV_TO_OVF_I8_UN:
530 case OP_ICONV_TO_OVF_U8_UN:
531 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
532 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
533 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
536 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
539 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
542 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
545 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
551 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
554 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
557 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
559 case OP_LCONV_TO_R_UN:
560 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
562 case OP_LCONV_TO_OVF_I1: {
563 MonoBasicBlock *is_negative, *end_label;
565 NEW_BBLOCK (cfg, is_negative);
566 NEW_BBLOCK (cfg, end_label);
568 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
569 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
570 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
571 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
573 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
574 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
577 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
578 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
579 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
582 MONO_START_BB (cfg, is_negative);
583 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
584 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
586 MONO_START_BB (cfg, end_label);
588 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
591 case OP_LCONV_TO_OVF_I1_UN:
592 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
593 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
595 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
596 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
597 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
598 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
599 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
601 case OP_LCONV_TO_OVF_U1:
602 case OP_LCONV_TO_OVF_U1_UN:
603 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
604 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
606 /* probe value to be within 0 to 255 */
607 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
608 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
609 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
611 case OP_LCONV_TO_OVF_I2: {
612 MonoBasicBlock *is_negative, *end_label;
614 NEW_BBLOCK (cfg, is_negative);
615 NEW_BBLOCK (cfg, end_label);
617 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
618 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
619 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
620 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
622 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
623 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
626 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
627 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
628 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
631 MONO_START_BB (cfg, is_negative);
632 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
633 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
634 MONO_START_BB (cfg, end_label);
636 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
639 case OP_LCONV_TO_OVF_I2_UN:
640 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
641 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
643 /* Probe value to be within -32768 and 32767 */
644 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
645 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
646 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
647 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
648 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
650 case OP_LCONV_TO_OVF_U2:
651 case OP_LCONV_TO_OVF_U2_UN:
652 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
653 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
655 /* Probe value to be within 0 and 65535 */
656 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
657 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
658 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
660 case OP_LCONV_TO_OVF_I4:
661 case OP_LCONV_TO_OVF_I:
662 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
664 case OP_LCONV_TO_OVF_U4:
665 case OP_LCONV_TO_OVF_U:
666 case OP_LCONV_TO_OVF_U4_UN:
667 case OP_LCONV_TO_OVF_U_UN:
668 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
669 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
670 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
672 case OP_LCONV_TO_OVF_I_UN:
673 case OP_LCONV_TO_OVF_I4_UN:
674 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
675 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
676 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
677 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
678 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
680 case OP_LCONV_TO_OVF_U8:
681 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
682 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
684 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
685 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
687 case OP_LCONV_TO_OVF_I8_UN:
688 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
689 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
691 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
692 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
696 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
697 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
700 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
701 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
705 /* ADC sets the condition code */
706 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
707 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
708 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
711 /* ADC sets the condition code */
712 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
713 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
714 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
717 /* SBB sets the condition code */
718 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
719 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
720 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
723 /* SBB sets the condition code */
724 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
725 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
726 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
729 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
730 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
733 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
734 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
737 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
738 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
741 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
742 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
745 /* Handled in mono_arch_decompose_long_opts () */
746 g_assert_not_reached ();
750 /* FIXME: Add OP_BIGMUL optimization */
754 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
755 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
759 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
762 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
763 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
766 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
767 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
770 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
771 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
774 if (tree->inst_c1 == 32) {
776 /* The original code had this comment: */
777 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
778 * later apply the speedup to the left shift as well
781 /* FIXME: Move this to the strength reduction pass */
782 /* just move the upper half to the lower and zero the high word */
783 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
784 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
788 if (tree->inst_c1 == 32) {
789 /* just move the lower half to the upper and zero the lower word */
790 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
791 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
796 MonoInst *next = tree->next;
800 switch (next->opcode) {
805 /* Branchless version based on gcc code */
806 d1 = alloc_ireg (cfg);
807 d2 = alloc_ireg (cfg);
808 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
809 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
810 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
811 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
812 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
813 next->opcode = OP_NOP;
824 /* Convert into three comparisons + branches */
825 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
826 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
827 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
828 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
829 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
830 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
831 next->opcode = OP_NOP;
836 /* Branchless version based on gcc code */
837 d1 = alloc_ireg (cfg);
838 d2 = alloc_ireg (cfg);
839 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
840 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
841 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
843 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
844 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
845 next->opcode = OP_NOP;
852 MonoBasicBlock *set_to_0, *set_to_1;
854 NEW_BBLOCK (cfg, set_to_0);
855 NEW_BBLOCK (cfg, set_to_1);
857 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
858 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
859 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
860 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
861 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
862 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
863 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
864 MONO_START_BB (cfg, set_to_1);
865 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
866 MONO_START_BB (cfg, set_to_0);
867 next->opcode = OP_NOP;
871 g_assert_not_reached ();
876 /* Not yet used, since lcompare is decomposed before local cprop */
877 case OP_LCOMPARE_IMM: {
878 MonoInst *next = tree->next;
879 guint32 low_imm = tree->inst_ls_word;
880 guint32 high_imm = tree->inst_ms_word;
881 int low_reg = tree->sreg1 + 1;
882 int high_reg = tree->sreg1 + 2;
886 switch (next->opcode) {
891 /* Branchless version based on gcc code */
892 d1 = alloc_ireg (cfg);
893 d2 = alloc_ireg (cfg);
894 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
895 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
896 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
897 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
898 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
899 next->opcode = OP_NOP;
911 /* Convert into three comparisons + branches */
912 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
913 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
914 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
915 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
916 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
917 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
918 next->opcode = OP_NOP;
923 /* Branchless version based on gcc code */
924 d1 = alloc_ireg (cfg);
925 d2 = alloc_ireg (cfg);
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
928 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
930 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
931 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
932 next->opcode = OP_NOP;
939 MonoBasicBlock *set_to_0, *set_to_1;
941 NEW_BBLOCK (cfg, set_to_0);
942 NEW_BBLOCK (cfg, set_to_1);
944 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
945 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
946 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
947 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
948 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
949 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
950 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
951 MONO_START_BB (cfg, set_to_1);
952 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
953 MONO_START_BB (cfg, set_to_0);
954 next->opcode = OP_NOP;
958 g_assert_not_reached ();
967 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
970 /* Replace the original instruction with the new code sequence */
972 /* Ignore the new value of prev */
974 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
976 /* Process the newly added ops again since they can be long ops too */
982 first_bb->code = first_bb->last_ins = NULL;
983 first_bb->in_count = first_bb->out_count = 0;
995 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
996 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1001 * mono_decompose_vtype_opts:
1003 * Decompose valuetype opcodes.
1006 mono_decompose_vtype_opts (MonoCompile *cfg)
1008 MonoBasicBlock *bb, *first_bb;
1011 * Using OP_V opcodes and decomposing them later have two main benefits:
1012 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1014 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1015 * enabling optimizations to work on vtypes too.
1016 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1017 * can be executed anytime. It should be executed as late as possible so vtype
1018 * opcodes can be optimized by the other passes.
1019 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1020 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1022 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1023 * when OP_VMOVE opcodes are decomposed.
1027 * Vregs have no associated type information, so we store the type of the vregs
1032 * Create a dummy bblock and emit code into it so we can use the normal
1033 * code generation macros.
1035 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1036 first_bb = cfg->cbb;
1038 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1040 MonoInst *prev = NULL;
1041 MonoInst *src_var, *dest_var, *src, *dest;
1045 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1047 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1053 for (ins = bb->code; ins; ins = ins->next) {
1054 switch (ins->opcode) {
1056 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1057 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1059 g_assert (ins->klass);
1062 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1065 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1068 if (src_var->backend.is_pinvoke)
1069 dest_var->backend.is_pinvoke = 1;
1071 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1072 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1074 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1078 g_assert (ins->klass);
1080 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1081 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1083 case OP_STOREV_MEMBASE: {
1084 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1087 g_assert (ins->klass);
1088 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1091 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1093 dreg = alloc_preg (cfg);
1094 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1095 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1098 case OP_LOADV_MEMBASE: {
1099 g_assert (ins->klass);
1101 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1104 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1106 dreg = alloc_preg (cfg);
1107 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1108 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1109 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1112 case OP_OUTARG_VT: {
1113 g_assert (ins->klass);
1115 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1117 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1118 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1120 mono_arch_emit_outarg_vt (cfg, ins, src);
1122 /* This might be decomposed into other vtype opcodes */
1126 case OP_OUTARG_VTRETADDR: {
1127 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1129 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1131 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1132 // FIXME: src_var->backend.is_pinvoke ?
1134 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1135 src->dreg = ins->dreg;
1140 case OP_VCALL_MEMBASE: {
1141 MonoCallInst *call = (MonoCallInst*)ins;
1144 if (call->vret_in_reg) {
1145 MonoCallInst *call2;
1147 /* Replace the vcall with an integer call */
1148 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1149 memcpy (call2, call, sizeof (MonoCallInst));
1150 switch (ins->opcode) {
1152 call2->inst.opcode = OP_CALL;
1155 call2->inst.opcode = OP_CALL_REG;
1157 case OP_VCALL_MEMBASE:
1158 call2->inst.opcode = OP_CALL_MEMBASE;
1161 call2->inst.dreg = alloc_preg (cfg);
1162 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1164 /* Compute the vtype location */
1165 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1167 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1168 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1170 /* Save the result */
1171 if (dest_var->backend.is_pinvoke)
1172 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1174 size = mono_type_size (dest_var->inst_vtype, NULL);
1177 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1180 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1183 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1186 #if SIZEOF_REGISTER == 4
1188 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1189 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1191 switch (call2->inst.opcode) {
1193 call2->inst.opcode = OP_LCALL;
1196 call2->inst.opcode = OP_LCALL_REG;
1198 case OP_CALL_MEMBASE:
1199 call2->inst.opcode = OP_LCALL_MEMBASE;
1202 call2->inst.dreg = alloc_lreg (cfg);
1203 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1204 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1206 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1210 /* This assumes the vtype is sizeof (gpointer) long */
1211 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1215 switch (ins->opcode) {
1217 ins->opcode = OP_VCALL2;
1220 ins->opcode = OP_VCALL2_REG;
1222 case OP_VCALL_MEMBASE:
1223 ins->opcode = OP_VCALL2_MEMBASE;
1234 g_assert (cfg->cbb == first_bb);
1236 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1237 /* Replace the original instruction with the new code sequence */
1239 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1240 first_bb->code = first_bb->last_ins = NULL;
1241 first_bb->in_count = first_bb->out_count = 0;
1242 cfg->cbb = first_bb;
1249 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1253 inline static MonoInst *
1254 mono_get_domainvar (MonoCompile *cfg)
1256 if (!cfg->domainvar)
1257 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1258 return cfg->domainvar;
1262 * mono_decompose_array_access_opts:
1264 * Decompose array access opcodes.
1267 mono_decompose_array_access_opts (MonoCompile *cfg)
1269 MonoBasicBlock *bb, *first_bb;
1272 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1273 * can be executed anytime. It should be run before decompose_long
1277 * Create a dummy bblock and emit code into it so we can use the normal
1278 * code generation macros.
1280 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1281 first_bb = cfg->cbb;
1283 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1285 MonoInst *prev = NULL;
1287 MonoInst *iargs [3];
1290 if (!bb->has_array_access)
1293 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1295 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1301 for (ins = bb->code; ins; ins = ins->next) {
1302 switch (ins->opcode) {
1304 NEW_LOAD_MEMBASE_FAULT (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1305 G_STRUCT_OFFSET (MonoArray, max_length));
1306 MONO_ADD_INS (cfg->cbb, dest);
1308 case OP_BOUNDS_CHECK:
1309 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1310 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1313 if (cfg->opt & MONO_OPT_SHARED) {
1314 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1315 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1316 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1317 iargs [2]->dreg = ins->sreg1;
1319 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1320 dest->dreg = ins->dreg;
1322 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1323 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1325 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1326 NEW_VTABLECONST (cfg, iargs [0], vtable);
1327 MONO_ADD_INS (cfg->cbb, iargs [0]);
1328 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1329 iargs [1]->dreg = ins->sreg1;
1332 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1334 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1335 dest->dreg = ins->dreg;
1339 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1340 ins->sreg1, G_STRUCT_OFFSET (MonoString, length));
1346 g_assert (cfg->cbb == first_bb);
1348 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1349 /* Replace the original instruction with the new code sequence */
1351 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1352 first_bb->code = first_bb->last_ins = NULL;
1353 first_bb->in_count = first_bb->out_count = 0;
1354 cfg->cbb = first_bb;
1361 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1371 #ifdef MONO_ARCH_SOFT_FLOAT
1374 * mono_decompose_soft_float:
1376 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1377 * similar to long support on 32 bit platforms. 32 bit float values require special
1378 * handling when used as locals, arguments, and in calls.
1379 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1382 mono_decompose_soft_float (MonoCompile *cfg)
1384 MonoBasicBlock *bb, *first_bb;
1387 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1391 * Create a dummy bblock and emit code into it so we can use the normal
1392 * code generation macros.
1394 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1395 first_bb = cfg->cbb;
1397 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1399 MonoInst *prev = NULL;
1402 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1404 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1410 for (ins = bb->code; ins; ins = ins->next) {
1411 const char *spec = INS_INFO (ins->opcode);
1413 /* Most fp operations are handled automatically by opcode emulation */
1415 switch (ins->opcode) {
1418 d.vald = *(double*)ins->inst_p0;
1419 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1424 /* We load the r8 value */
1425 d.vald = *(float*)ins->inst_p0;
1426 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1430 ins->opcode = OP_LMOVE;
1433 ins->opcode = OP_MOVE;
1434 ins->sreg1 = ins->sreg1 + 1;
1437 ins->opcode = OP_MOVE;
1438 ins->sreg1 = ins->sreg1 + 2;
1441 int reg = ins->sreg1;
1443 ins->opcode = OP_SETLRET;
1445 ins->sreg1 = reg + 1;
1446 ins->sreg2 = reg + 2;
1449 case OP_LOADR8_MEMBASE:
1450 ins->opcode = OP_LOADI8_MEMBASE;
1452 case OP_STORER8_MEMBASE_REG:
1453 ins->opcode = OP_STOREI8_MEMBASE_REG;
1455 case OP_STORER4_MEMBASE_REG: {
1456 MonoInst *iargs [2];
1459 /* Arg 1 is the double value */
1460 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1461 iargs [0]->dreg = ins->sreg1;
1463 /* Arg 2 is the address to store to */
1464 addr_reg = mono_alloc_preg (cfg);
1465 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1466 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1470 case OP_LOADR4_MEMBASE: {
1471 MonoInst *iargs [1];
1475 addr_reg = mono_alloc_preg (cfg);
1476 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1477 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1478 conv->dreg = ins->dreg;
1483 case OP_FCALL_MEMBASE: {
1484 MonoCallInst *call = (MonoCallInst*)ins;
1485 if (call->signature->ret->type == MONO_TYPE_R4) {
1486 MonoCallInst *call2;
1487 MonoInst *iargs [1];
1490 /* Convert the call into a call returning an int */
1491 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1492 memcpy (call2, call, sizeof (MonoCallInst));
1493 switch (ins->opcode) {
1495 call2->inst.opcode = OP_CALL;
1498 call2->inst.opcode = OP_CALL_REG;
1500 case OP_FCALL_MEMBASE:
1501 call2->inst.opcode = OP_CALL_MEMBASE;
1504 g_assert_not_reached ();
1506 call2->inst.dreg = mono_alloc_ireg (cfg);
1507 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1509 /* FIXME: Optimize this */
1511 /* Emit an r4->r8 conversion */
1512 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1513 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1514 conv->dreg = ins->dreg;
1516 /* The call sequence might include fp ins */
1519 switch (ins->opcode) {
1521 ins->opcode = OP_LCALL;
1524 ins->opcode = OP_LCALL_REG;
1526 case OP_FCALL_MEMBASE:
1527 ins->opcode = OP_LCALL_MEMBASE;
1530 g_assert_not_reached ();
1536 MonoJitICallInfo *info;
1537 MonoInst *iargs [2];
1538 MonoInst *call, *cmp, *br;
1540 /* Convert fcompare+fbcc to icall+icompare+beq */
1542 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1545 /* Create dummy MonoInst's for the arguments */
1546 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1547 iargs [0]->dreg = ins->sreg1;
1548 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1549 iargs [1]->dreg = ins->sreg2;
1551 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1553 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1554 cmp->sreg1 = call->dreg;
1556 MONO_ADD_INS (cfg->cbb, cmp);
1558 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1559 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1560 br->inst_true_bb = ins->next->inst_true_bb;
1561 br->inst_false_bb = ins->next->inst_false_bb;
1562 MONO_ADD_INS (cfg->cbb, br);
1564 /* The call sequence might include fp ins */
1567 /* Skip fbcc or fccc */
1568 NULLIFY_INS (ins->next);
1576 MonoJitICallInfo *info;
1577 MonoInst *iargs [2];
1580 /* Convert fccc to icall+icompare+iceq */
1582 info = mono_find_jit_opcode_emulation (ins->opcode);
1585 /* Create dummy MonoInst's for the arguments */
1586 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1587 iargs [0]->dreg = ins->sreg1;
1588 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1589 iargs [1]->dreg = ins->sreg2;
1591 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1593 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1594 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1596 /* The call sequence might include fp ins */
1601 MonoInst *iargs [2];
1602 MonoInst *call, *cmp;
1604 /* Convert to icall+icompare+cond_exc+move */
1606 /* Create dummy MonoInst's for the arguments */
1607 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1608 iargs [0]->dreg = ins->sreg1;
1610 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1612 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1613 cmp->sreg1 = call->dreg;
1615 MONO_ADD_INS (cfg->cbb, cmp);
1617 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1619 /* Do the assignment if the value is finite */
1620 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1626 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1627 mono_print_ins (ins);
1628 g_assert_not_reached ();
1633 g_assert (cfg->cbb == first_bb);
1635 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1636 /* Replace the original instruction with the new code sequence */
1638 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1639 first_bb->code = first_bb->last_ins = NULL;
1640 first_bb->in_count = first_bb->out_count = 0;
1641 cfg->cbb = first_bb;
1648 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1651 mono_decompose_long_opts (cfg);
1656 #endif /* DISABLE_JIT */