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
33 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
35 MonoInst *repl = NULL;
39 /* FIXME: Instead of = NOP, don't emit the original ins at all */
41 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
42 mono_arch_decompose_opts (cfg, ins);
46 * The code below assumes that we are called immediately after emitting
47 * ins. This means we can emit code using the normal code generation
50 switch (ins->opcode) {
51 /* this doesn't make sense on ppc and other architectures */
52 #if !defined(MONO_ARCH_NO_IOV_CHECK)
54 if (COMPILE_LLVM (cfg))
56 ins->opcode = OP_IADDCC;
57 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
60 if (COMPILE_LLVM (cfg))
62 ins->opcode = OP_IADDCC;
63 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
66 if (COMPILE_LLVM (cfg))
68 ins->opcode = OP_ISUBCC;
69 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
72 if (COMPILE_LLVM (cfg))
74 ins->opcode = OP_ISUBCC;
75 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
78 case OP_ICONV_TO_OVF_I1:
79 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
80 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
81 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
82 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
83 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
86 case OP_ICONV_TO_OVF_I1_UN:
87 /* probe values between 0 to 127 */
88 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
89 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
90 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
93 case OP_ICONV_TO_OVF_U1:
94 case OP_ICONV_TO_OVF_U1_UN:
95 /* probe value to be within 0 to 255 */
96 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
97 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
98 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
101 case OP_ICONV_TO_OVF_I2:
102 /* Probe value to be within -32768 and 32767 */
103 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
104 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
105 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
106 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
107 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
110 case OP_ICONV_TO_OVF_I2_UN:
111 /* Convert uint value into short, value within 0 and 32767 */
112 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
113 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
114 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
117 case OP_ICONV_TO_OVF_U2:
118 case OP_ICONV_TO_OVF_U2_UN:
119 /* Probe value to be within 0 and 65535 */
120 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
121 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
122 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
125 case OP_ICONV_TO_OVF_U4:
126 case OP_ICONV_TO_OVF_I4_UN:
127 #if SIZEOF_REGISTER == 4
128 case OP_ICONV_TO_OVF_U:
129 case OP_ICONV_TO_OVF_I_UN:
131 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
132 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
133 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
138 case OP_ICONV_TO_OVF_I4:
139 #if SIZEOF_REGISTER == 4
140 case OP_ICONV_TO_OVF_I:
141 case OP_ICONV_TO_OVF_U_UN:
143 ins->opcode = OP_MOVE;
146 #if SIZEOF_REGISTER == 8
147 ins->opcode = OP_SEXT_I4;
149 ins->opcode = OP_MOVE;
153 #if SIZEOF_REGISTER == 8
154 ins->opcode = OP_ZEXT_I4;
156 ins->opcode = OP_MOVE;
161 ins->opcode = OP_FMOVE;
164 /* Long opcodes on 64 bit machines */
165 #if SIZEOF_REGISTER == 8
167 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
174 ins->opcode = OP_MOVE;
177 ins->opcode = OP_SEXT_I4;
180 ins->opcode = OP_ZEXT_I4;
183 /* Clean out the upper word */
184 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
188 if (COMPILE_LLVM (cfg))
190 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
191 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
195 if (COMPILE_LLVM (cfg))
197 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
198 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
201 #ifndef __mono_ppc64__
203 if (COMPILE_LLVM (cfg))
205 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
206 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
210 if (COMPILE_LLVM (cfg))
212 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
213 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
218 case OP_ICONV_TO_OVF_I8:
219 case OP_ICONV_TO_OVF_I:
220 ins->opcode = OP_SEXT_I4;
222 case OP_ICONV_TO_OVF_U8:
223 case OP_ICONV_TO_OVF_U:
224 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
225 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
226 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
229 case OP_ICONV_TO_OVF_I8_UN:
230 case OP_ICONV_TO_OVF_U8_UN:
231 case OP_ICONV_TO_OVF_I_UN:
232 case OP_ICONV_TO_OVF_U_UN:
233 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
234 /* Clean out the upper word */
235 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
238 case OP_LCONV_TO_OVF_I1:
239 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
240 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
241 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
242 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
243 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
246 case OP_LCONV_TO_OVF_I1_UN:
247 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
248 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
249 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
252 case OP_LCONV_TO_OVF_U1:
253 /* probe value to be within 0 to 255 */
254 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
255 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
256 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
259 case OP_LCONV_TO_OVF_U1_UN:
260 /* probe value to be within 0 to 255 */
261 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
262 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
263 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
266 case OP_LCONV_TO_OVF_I2:
267 /* Probe value to be within -32768 and 32767 */
268 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
269 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
270 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
271 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
272 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
275 case OP_LCONV_TO_OVF_I2_UN:
276 /* Probe value to be within 0 and 32767 */
277 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
278 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
279 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
282 case OP_LCONV_TO_OVF_U2:
283 /* Probe value to be within 0 and 65535 */
284 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
285 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
286 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
289 case OP_LCONV_TO_OVF_U2_UN:
290 /* Probe value to be within 0 and 65535 */
291 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
292 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
293 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
296 case OP_LCONV_TO_OVF_I4:
297 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
298 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
299 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
300 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
301 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
302 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
305 case OP_LCONV_TO_OVF_I4_UN:
306 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
307 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
308 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
311 case OP_LCONV_TO_OVF_U4:
312 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
313 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
314 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
315 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
316 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
319 case OP_LCONV_TO_OVF_U4_UN:
320 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
321 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
322 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
325 case OP_LCONV_TO_OVF_I:
326 case OP_LCONV_TO_OVF_U_UN:
327 case OP_LCONV_TO_OVF_U8_UN:
328 case OP_LCONV_TO_OVF_I8:
329 ins->opcode = OP_MOVE;
331 case OP_LCONV_TO_OVF_I_UN:
332 case OP_LCONV_TO_OVF_I8_UN:
333 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
334 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
335 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
338 case OP_LCONV_TO_OVF_U8:
339 case OP_LCONV_TO_OVF_U:
340 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
341 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
342 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
348 MonoJitICallInfo *info;
350 info = mono_find_jit_opcode_emulation (ins->opcode);
355 /* Create dummy MonoInst's for the arguments */
356 g_assert (!info->sig->hasthis);
357 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
359 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
360 if (info->sig->param_count > 0) {
361 int sregs [MONO_MAX_SRC_REGS];
363 num_sregs = mono_inst_get_src_registers (ins, sregs);
364 g_assert (num_sregs == info->sig->param_count);
365 for (i = 0; i < num_sregs; ++i) {
366 MONO_INST_NEW (cfg, args [i], OP_ARG);
367 args [i]->dreg = sregs [i];
371 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
372 call->dreg = ins->dreg;
380 if (ins->opcode == OP_NOP) {
385 /* Use the last emitted instruction */
386 ins = cfg->cbb->last_ins;
389 g_assert (ins->dreg == dreg);
397 #if SIZEOF_REGISTER == 4
398 static int lbr_decomp [][2] = {
400 {OP_IBGT, OP_IBGE_UN}, /* BGE */
401 {OP_IBGT, OP_IBGT_UN}, /* BGT */
402 {OP_IBLT, OP_IBLE_UN}, /* BLE */
403 {OP_IBLT, OP_IBLT_UN}, /* BLT */
405 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
406 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
407 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
408 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
411 static int lcset_decomp [][2] = {
413 {OP_IBLT, OP_IBLE_UN}, /* CGT */
414 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
415 {OP_IBGT, OP_IBGE_UN}, /* CLT */
416 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
421 * mono_decompose_long_opts:
423 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
426 mono_decompose_long_opts (MonoCompile *cfg)
428 #if SIZEOF_REGISTER == 4
429 MonoBasicBlock *bb, *first_bb;
432 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
433 * needs to be able to handle long vregs.
436 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
439 * Create a dummy bblock and emit code into it so we can use the normal
440 * code generation macros.
442 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
445 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
446 MonoInst *tree = bb->code;
447 MonoInst *prev = NULL;
450 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
454 cfg->cbb->code = cfg->cbb->last_ins = NULL;
458 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
459 mono_arch_decompose_long_opts (cfg, tree);
462 switch (tree->opcode) {
464 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
465 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
470 case OP_LCONV_TO_OVF_U8_UN:
471 case OP_LCONV_TO_OVF_I8:
472 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
473 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
475 case OP_STOREI8_MEMBASE_REG:
476 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
477 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
479 case OP_LOADI8_MEMBASE:
480 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
481 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
484 case OP_ICONV_TO_I8: {
485 guint32 tmpreg = alloc_ireg (cfg);
489 * tmp = low > -1 ? 1: 0;
490 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
492 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
493 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
494 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
495 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
499 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
500 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
502 case OP_ICONV_TO_OVF_I8:
503 /* a signed 32 bit num always fits in a signed 64 bit one */
504 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
505 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
507 case OP_ICONV_TO_OVF_U8:
508 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
509 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
510 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
511 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
513 case OP_ICONV_TO_OVF_I8_UN:
514 case OP_ICONV_TO_OVF_U8_UN:
515 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
516 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
517 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
520 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
523 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
526 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
529 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
535 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
538 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
541 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
543 case OP_LCONV_TO_R_UN:
544 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
546 case OP_LCONV_TO_OVF_I1: {
547 MonoBasicBlock *is_negative, *end_label;
549 NEW_BBLOCK (cfg, is_negative);
550 NEW_BBLOCK (cfg, end_label);
552 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
553 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
554 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
555 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
557 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
558 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
561 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
562 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
563 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
566 MONO_START_BB (cfg, is_negative);
567 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
568 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
570 MONO_START_BB (cfg, end_label);
572 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
575 case OP_LCONV_TO_OVF_I1_UN:
576 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
577 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
579 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
580 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
581 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
582 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
583 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
585 case OP_LCONV_TO_OVF_U1:
586 case OP_LCONV_TO_OVF_U1_UN:
587 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
588 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
590 /* probe value to be within 0 to 255 */
591 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
592 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
593 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
595 case OP_LCONV_TO_OVF_I2: {
596 MonoBasicBlock *is_negative, *end_label;
598 NEW_BBLOCK (cfg, is_negative);
599 NEW_BBLOCK (cfg, end_label);
601 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
602 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
603 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
604 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
606 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
607 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
610 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
611 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
612 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
615 MONO_START_BB (cfg, is_negative);
616 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
617 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
618 MONO_START_BB (cfg, end_label);
620 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
623 case OP_LCONV_TO_OVF_I2_UN:
624 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
625 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
627 /* Probe value to be within -32768 and 32767 */
628 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
629 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
630 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
631 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
632 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
634 case OP_LCONV_TO_OVF_U2:
635 case OP_LCONV_TO_OVF_U2_UN:
636 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
637 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
639 /* Probe value to be within 0 and 65535 */
640 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
641 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
642 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
644 case OP_LCONV_TO_OVF_I4:
645 case OP_LCONV_TO_OVF_I:
646 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
648 case OP_LCONV_TO_OVF_U4:
649 case OP_LCONV_TO_OVF_U:
650 case OP_LCONV_TO_OVF_U4_UN:
651 case OP_LCONV_TO_OVF_U_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");
654 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
656 case OP_LCONV_TO_OVF_I_UN:
657 case OP_LCONV_TO_OVF_I4_UN:
658 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
659 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
660 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
661 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
662 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
664 case OP_LCONV_TO_OVF_U8:
665 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
666 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
668 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
669 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
671 case OP_LCONV_TO_OVF_I8_UN:
672 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
673 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
675 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
676 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
680 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
681 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
684 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
685 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
689 /* ADC sets the condition code */
690 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
691 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
692 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
695 /* ADC sets the condition code */
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);
698 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
701 /* SBB sets the condition code */
702 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
703 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
704 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
707 /* SBB sets the condition code */
708 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
709 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
710 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
713 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
714 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
717 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
718 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
721 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
722 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
725 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
726 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
729 /* Handled in mono_arch_decompose_long_opts () */
730 g_assert_not_reached ();
734 /* FIXME: Add OP_BIGMUL optimization */
738 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
739 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
742 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
743 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
746 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
747 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
750 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
751 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
754 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
755 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
758 if (tree->inst_c1 == 32) {
760 /* The original code had this comment: */
761 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
762 * later apply the speedup to the left shift as well
765 /* FIXME: Move this to the strength reduction pass */
766 /* just move the upper half to the lower and zero the high word */
767 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
768 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
772 if (tree->inst_c1 == 32) {
773 /* just move the lower half to the upper and zero the lower word */
774 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
775 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
780 MonoInst *next = tree->next;
784 switch (next->opcode) {
789 /* Branchless version based on gcc code */
790 d1 = alloc_ireg (cfg);
791 d2 = alloc_ireg (cfg);
792 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
793 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
794 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
795 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
796 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
797 next->opcode = OP_NOP;
808 /* Convert into three comparisons + branches */
809 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
810 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
811 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
812 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
813 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
814 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
815 next->opcode = OP_NOP;
820 /* Branchless version based on gcc code */
821 d1 = alloc_ireg (cfg);
822 d2 = alloc_ireg (cfg);
823 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
824 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
825 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
827 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
828 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
829 next->opcode = OP_NOP;
836 MonoBasicBlock *set_to_0, *set_to_1;
838 NEW_BBLOCK (cfg, set_to_0);
839 NEW_BBLOCK (cfg, set_to_1);
841 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
842 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
843 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
844 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
845 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
846 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
847 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
848 MONO_START_BB (cfg, set_to_1);
849 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
850 MONO_START_BB (cfg, set_to_0);
851 next->opcode = OP_NOP;
855 g_assert_not_reached ();
860 /* Not yet used, since lcompare is decomposed before local cprop */
861 case OP_LCOMPARE_IMM: {
862 MonoInst *next = tree->next;
863 guint32 low_imm = tree->inst_ls_word;
864 guint32 high_imm = tree->inst_ms_word;
865 int low_reg = tree->sreg1 + 1;
866 int high_reg = tree->sreg1 + 2;
870 switch (next->opcode) {
875 /* Branchless version based on gcc code */
876 d1 = alloc_ireg (cfg);
877 d2 = alloc_ireg (cfg);
878 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
879 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
880 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
881 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
882 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
883 next->opcode = OP_NOP;
895 /* Convert into three comparisons + branches */
896 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
897 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
898 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
899 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
900 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
901 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
902 next->opcode = OP_NOP;
907 /* Branchless version based on gcc code */
908 d1 = alloc_ireg (cfg);
909 d2 = alloc_ireg (cfg);
910 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
911 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
912 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
914 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
915 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
916 next->opcode = OP_NOP;
923 MonoBasicBlock *set_to_0, *set_to_1;
925 NEW_BBLOCK (cfg, set_to_0);
926 NEW_BBLOCK (cfg, set_to_1);
928 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
930 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
932 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
934 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
935 MONO_START_BB (cfg, set_to_1);
936 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
937 MONO_START_BB (cfg, set_to_0);
938 next->opcode = OP_NOP;
942 g_assert_not_reached ();
951 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
954 /* Replace the original instruction with the new code sequence */
956 /* Ignore the new value of prev */
958 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
960 /* Process the newly added ops again since they can be long ops too */
966 first_bb->code = first_bb->last_ins = NULL;
967 first_bb->in_count = first_bb->out_count = 0;
979 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
980 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
985 * mono_decompose_vtype_opts:
987 * Decompose valuetype opcodes.
990 mono_decompose_vtype_opts (MonoCompile *cfg)
992 MonoBasicBlock *bb, *first_bb;
995 * Using OP_V opcodes and decomposing them later have two main benefits:
996 * - it simplifies method_to_ir () since there is no need to special-case vtypes
998 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
999 * enabling optimizations to work on vtypes too.
1000 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1001 * can be executed anytime. It should be executed as late as possible so vtype
1002 * opcodes can be optimized by the other passes.
1003 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1004 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1006 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1007 * when OP_VMOVE opcodes are decomposed.
1011 * Vregs have no associated type information, so we store the type of the vregs
1016 * Create a dummy bblock and emit code into it so we can use the normal
1017 * code generation macros.
1019 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1020 first_bb = cfg->cbb;
1022 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1024 MonoInst *prev = NULL;
1025 MonoInst *src_var, *dest_var, *src, *dest;
1029 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1031 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1037 for (ins = bb->code; ins; ins = ins->next) {
1038 switch (ins->opcode) {
1040 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1041 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1043 g_assert (ins->klass);
1046 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1049 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1052 if (src_var->backend.is_pinvoke)
1053 dest_var->backend.is_pinvoke = 1;
1055 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1056 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1058 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1062 g_assert (ins->klass);
1064 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1065 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1067 case OP_STOREV_MEMBASE: {
1068 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1071 g_assert (ins->klass);
1072 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1075 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1077 dreg = alloc_preg (cfg);
1078 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1079 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1082 case OP_LOADV_MEMBASE: {
1083 g_assert (ins->klass);
1085 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1088 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1090 dreg = alloc_preg (cfg);
1091 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1092 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1093 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1096 case OP_OUTARG_VT: {
1097 g_assert (ins->klass);
1099 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1101 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1102 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1104 mono_arch_emit_outarg_vt (cfg, ins, src);
1106 /* This might be decomposed into other vtype opcodes */
1110 case OP_OUTARG_VTRETADDR: {
1111 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1113 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1115 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1116 // FIXME: src_var->backend.is_pinvoke ?
1118 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1119 src->dreg = ins->dreg;
1124 case OP_VCALL_MEMBASE: {
1125 MonoCallInst *call = (MonoCallInst*)ins;
1128 if (call->vret_in_reg) {
1129 MonoCallInst *call2;
1131 /* Replace the vcall with an integer call */
1132 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1133 memcpy (call2, call, sizeof (MonoCallInst));
1134 switch (ins->opcode) {
1136 call2->inst.opcode = OP_CALL;
1139 call2->inst.opcode = OP_CALL_REG;
1141 case OP_VCALL_MEMBASE:
1142 call2->inst.opcode = OP_CALL_MEMBASE;
1145 call2->inst.dreg = alloc_preg (cfg);
1146 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1148 /* Compute the vtype location */
1149 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1151 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1152 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1154 /* Save the result */
1155 if (dest_var->backend.is_pinvoke)
1156 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1158 size = mono_type_size (dest_var->inst_vtype, NULL);
1161 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1164 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1167 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1170 #if SIZEOF_REGISTER == 4
1172 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1173 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1175 switch (call2->inst.opcode) {
1177 call2->inst.opcode = OP_LCALL;
1180 call2->inst.opcode = OP_LCALL_REG;
1182 case OP_CALL_MEMBASE:
1183 call2->inst.opcode = OP_LCALL_MEMBASE;
1186 call2->inst.dreg = alloc_lreg (cfg);
1187 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1188 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1190 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1194 /* This assumes the vtype is sizeof (gpointer) long */
1195 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1199 switch (ins->opcode) {
1201 ins->opcode = OP_VCALL2;
1204 ins->opcode = OP_VCALL2_REG;
1206 case OP_VCALL_MEMBASE:
1207 ins->opcode = OP_VCALL2_MEMBASE;
1218 g_assert (cfg->cbb == first_bb);
1220 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1221 /* Replace the original instruction with the new code sequence */
1223 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1224 first_bb->code = first_bb->last_ins = NULL;
1225 first_bb->in_count = first_bb->out_count = 0;
1226 cfg->cbb = first_bb;
1233 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1237 inline static MonoInst *
1238 mono_get_domainvar (MonoCompile *cfg)
1240 if (!cfg->domainvar)
1241 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1242 return cfg->domainvar;
1246 * mono_decompose_array_access_opts:
1248 * Decompose array access opcodes.
1251 mono_decompose_array_access_opts (MonoCompile *cfg)
1253 MonoBasicBlock *bb, *first_bb;
1256 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1257 * can be executed anytime. It should be run before decompose_long
1261 * Create a dummy bblock and emit code into it so we can use the normal
1262 * code generation macros.
1264 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1265 first_bb = cfg->cbb;
1267 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1269 MonoInst *prev = NULL;
1271 MonoInst *iargs [3];
1274 if (!bb->has_array_access)
1277 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1279 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1285 for (ins = bb->code; ins; ins = ins->next) {
1286 switch (ins->opcode) {
1288 NEW_LOAD_MEMBASE_FAULT (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1289 G_STRUCT_OFFSET (MonoArray, max_length));
1290 MONO_ADD_INS (cfg->cbb, dest);
1292 case OP_BOUNDS_CHECK:
1293 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1294 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1297 if (cfg->opt & MONO_OPT_SHARED) {
1298 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1299 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1300 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1301 iargs [2]->dreg = ins->sreg1;
1303 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1304 dest->dreg = ins->dreg;
1306 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1307 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1309 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1310 NEW_VTABLECONST (cfg, iargs [0], vtable);
1311 MONO_ADD_INS (cfg->cbb, iargs [0]);
1312 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1313 iargs [1]->dreg = ins->sreg1;
1316 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1318 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1319 dest->dreg = ins->dreg;
1323 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1324 ins->sreg1, G_STRUCT_OFFSET (MonoString, length));
1330 g_assert (cfg->cbb == first_bb);
1332 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1333 /* Replace the original instruction with the new code sequence */
1335 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1336 first_bb->code = first_bb->last_ins = NULL;
1337 first_bb->in_count = first_bb->out_count = 0;
1338 cfg->cbb = first_bb;
1345 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1355 #ifdef MONO_ARCH_SOFT_FLOAT
1358 * mono_decompose_soft_float:
1360 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1361 * similar to long support on 32 bit platforms. 32 bit float values require special
1362 * handling when used as locals, arguments, and in calls.
1363 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1366 mono_decompose_soft_float (MonoCompile *cfg)
1368 MonoBasicBlock *bb, *first_bb;
1371 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1375 * Create a dummy bblock and emit code into it so we can use the normal
1376 * code generation macros.
1378 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1379 first_bb = cfg->cbb;
1381 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1383 MonoInst *prev = NULL;
1386 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1388 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1394 for (ins = bb->code; ins; ins = ins->next) {
1395 const char *spec = INS_INFO (ins->opcode);
1397 /* Most fp operations are handled automatically by opcode emulation */
1399 switch (ins->opcode) {
1402 d.vald = *(double*)ins->inst_p0;
1403 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1408 /* We load the r8 value */
1409 d.vald = *(float*)ins->inst_p0;
1410 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1414 ins->opcode = OP_LMOVE;
1417 ins->opcode = OP_MOVE;
1418 ins->sreg1 = ins->sreg1 + 1;
1421 ins->opcode = OP_MOVE;
1422 ins->sreg1 = ins->sreg1 + 2;
1425 int reg = ins->sreg1;
1427 ins->opcode = OP_SETLRET;
1429 ins->sreg1 = reg + 1;
1430 ins->sreg2 = reg + 2;
1433 case OP_LOADR8_MEMBASE:
1434 ins->opcode = OP_LOADI8_MEMBASE;
1436 case OP_STORER8_MEMBASE_REG:
1437 ins->opcode = OP_STOREI8_MEMBASE_REG;
1439 case OP_STORER4_MEMBASE_REG: {
1440 MonoInst *iargs [2];
1443 /* Arg 1 is the double value */
1444 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1445 iargs [0]->dreg = ins->sreg1;
1447 /* Arg 2 is the address to store to */
1448 addr_reg = mono_alloc_preg (cfg);
1449 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1450 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1454 case OP_LOADR4_MEMBASE: {
1455 MonoInst *iargs [1];
1459 addr_reg = mono_alloc_preg (cfg);
1460 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1461 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1462 conv->dreg = ins->dreg;
1467 case OP_FCALL_MEMBASE: {
1468 MonoCallInst *call = (MonoCallInst*)ins;
1469 if (call->signature->ret->type == MONO_TYPE_R4) {
1470 MonoCallInst *call2;
1471 MonoInst *iargs [1];
1474 /* Convert the call into a call returning an int */
1475 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1476 memcpy (call2, call, sizeof (MonoCallInst));
1477 switch (ins->opcode) {
1479 call2->inst.opcode = OP_CALL;
1482 call2->inst.opcode = OP_CALL_REG;
1484 case OP_FCALL_MEMBASE:
1485 call2->inst.opcode = OP_CALL_MEMBASE;
1488 g_assert_not_reached ();
1490 call2->inst.dreg = mono_alloc_ireg (cfg);
1491 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1493 /* FIXME: Optimize this */
1495 /* Emit an r4->r8 conversion */
1496 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1497 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1498 conv->dreg = ins->dreg;
1500 /* The call sequence might include fp ins */
1503 switch (ins->opcode) {
1505 ins->opcode = OP_LCALL;
1508 ins->opcode = OP_LCALL_REG;
1510 case OP_FCALL_MEMBASE:
1511 ins->opcode = OP_LCALL_MEMBASE;
1514 g_assert_not_reached ();
1520 MonoJitICallInfo *info;
1521 MonoInst *iargs [2];
1522 MonoInst *call, *cmp, *br;
1524 /* Convert fcompare+fbcc to icall+icompare+beq */
1526 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1529 /* Create dummy MonoInst's for the arguments */
1530 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1531 iargs [0]->dreg = ins->sreg1;
1532 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1533 iargs [1]->dreg = ins->sreg2;
1535 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1537 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1538 cmp->sreg1 = call->dreg;
1540 MONO_ADD_INS (cfg->cbb, cmp);
1542 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1543 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1544 br->inst_true_bb = ins->next->inst_true_bb;
1545 br->inst_false_bb = ins->next->inst_false_bb;
1546 MONO_ADD_INS (cfg->cbb, br);
1548 /* The call sequence might include fp ins */
1551 /* Skip fbcc or fccc */
1552 NULLIFY_INS (ins->next);
1560 MonoJitICallInfo *info;
1561 MonoInst *iargs [2];
1564 /* Convert fccc to icall+icompare+iceq */
1566 info = mono_find_jit_opcode_emulation (ins->opcode);
1569 /* Create dummy MonoInst's for the arguments */
1570 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1571 iargs [0]->dreg = ins->sreg1;
1572 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1573 iargs [1]->dreg = ins->sreg2;
1575 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1577 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1578 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1580 /* The call sequence might include fp ins */
1585 MonoInst *iargs [2];
1586 MonoInst *call, *cmp;
1588 /* Convert to icall+icompare+cond_exc+move */
1590 /* Create dummy MonoInst's for the arguments */
1591 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1592 iargs [0]->dreg = ins->sreg1;
1594 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1596 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1597 cmp->sreg1 = call->dreg;
1599 MONO_ADD_INS (cfg->cbb, cmp);
1601 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1603 /* Do the assignment if the value is finite */
1604 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1610 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1611 mono_print_ins (ins);
1612 g_assert_not_reached ();
1617 g_assert (cfg->cbb == first_bb);
1619 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1620 /* Replace the original instruction with the new code sequence */
1622 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1623 first_bb->code = first_bb->last_ins = NULL;
1624 first_bb->in_count = first_bb->out_count = 0;
1625 cfg->cbb = first_bb;
1632 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1635 mono_decompose_long_opts (cfg);
1640 #endif /* DISABLE_JIT */