2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
15 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
16 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
17 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
18 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
21 * mono_decompose_opcode:
23 * Decompose complex opcodes into ones closer to opcodes supported by
24 * the given architecture.
25 * Returns a MonoInst which represents the result of the decomposition, and can
26 * be pushed on the IL stack. This is needed because the original instruction is
30 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
32 MonoInst *repl = NULL;
36 /* FIXME: Instead of = NOP, don't emit the original ins at all */
38 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
39 mono_arch_decompose_opts (cfg, ins);
43 * The code below assumes that we are called immediately after emitting
44 * ins. This means we can emit code using the normal code generation
47 switch (ins->opcode) {
48 /* this doesn't make sense on ppc and other architectures */
49 #if !defined(MONO_ARCH_NO_IOV_CHECK)
51 if (COMPILE_LLVM (cfg))
53 ins->opcode = OP_IADDCC;
54 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
57 if (COMPILE_LLVM (cfg))
59 ins->opcode = OP_IADDCC;
60 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
63 if (COMPILE_LLVM (cfg))
65 ins->opcode = OP_ISUBCC;
66 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
69 if (COMPILE_LLVM (cfg))
71 ins->opcode = OP_ISUBCC;
72 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
75 case OP_ICONV_TO_OVF_I1:
76 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
77 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
78 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
79 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
80 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
83 case OP_ICONV_TO_OVF_I1_UN:
84 /* probe values between 0 to 127 */
85 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
86 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
87 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
90 case OP_ICONV_TO_OVF_U1:
91 case OP_ICONV_TO_OVF_U1_UN:
92 /* probe value to be within 0 to 255 */
93 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
94 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
95 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
98 case OP_ICONV_TO_OVF_I2:
99 /* Probe value to be within -32768 and 32767 */
100 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
101 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
102 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
103 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
104 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
107 case OP_ICONV_TO_OVF_I2_UN:
108 /* Convert uint value into short, value within 0 and 32767 */
109 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
110 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
111 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
114 case OP_ICONV_TO_OVF_U2:
115 case OP_ICONV_TO_OVF_U2_UN:
116 /* Probe value to be within 0 and 65535 */
117 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
118 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
119 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
122 case OP_ICONV_TO_OVF_U4:
123 case OP_ICONV_TO_OVF_I4_UN:
124 #if SIZEOF_REGISTER == 4
125 case OP_ICONV_TO_OVF_U:
126 case OP_ICONV_TO_OVF_I_UN:
128 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
129 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
130 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
135 case OP_ICONV_TO_OVF_I4:
136 #if SIZEOF_REGISTER == 4
137 case OP_ICONV_TO_OVF_I:
138 case OP_ICONV_TO_OVF_U_UN:
140 ins->opcode = OP_MOVE;
143 #if SIZEOF_REGISTER == 8
144 ins->opcode = OP_SEXT_I4;
146 ins->opcode = OP_MOVE;
150 #if SIZEOF_REGISTER == 8
151 ins->opcode = OP_ZEXT_I4;
153 ins->opcode = OP_MOVE;
158 ins->opcode = OP_FMOVE;
161 /* Long opcodes on 64 bit machines */
162 #if SIZEOF_REGISTER == 8
164 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
171 ins->opcode = OP_MOVE;
174 ins->opcode = OP_SEXT_I4;
177 ins->opcode = OP_ZEXT_I4;
180 /* Clean out the upper word */
181 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
185 if (COMPILE_LLVM (cfg))
187 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
188 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
192 if (COMPILE_LLVM (cfg))
194 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
195 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
198 #ifndef __mono_ppc64__
200 if (COMPILE_LLVM (cfg))
202 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
203 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
207 if (COMPILE_LLVM (cfg))
209 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
210 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
215 case OP_ICONV_TO_OVF_I8:
216 case OP_ICONV_TO_OVF_I:
217 ins->opcode = OP_SEXT_I4;
219 case OP_ICONV_TO_OVF_U8:
220 case OP_ICONV_TO_OVF_U:
221 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
222 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
223 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
226 case OP_ICONV_TO_OVF_I8_UN:
227 case OP_ICONV_TO_OVF_U8_UN:
228 case OP_ICONV_TO_OVF_I_UN:
229 case OP_ICONV_TO_OVF_U_UN:
230 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
231 /* Clean out the upper word */
232 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
235 case OP_LCONV_TO_OVF_I1:
236 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
237 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
238 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
239 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
240 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
243 case OP_LCONV_TO_OVF_I1_UN:
244 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
245 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
246 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
249 case OP_LCONV_TO_OVF_U1:
250 /* probe value to be within 0 to 255 */
251 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
252 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
253 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
256 case OP_LCONV_TO_OVF_U1_UN:
257 /* probe value to be within 0 to 255 */
258 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
259 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
260 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
263 case OP_LCONV_TO_OVF_I2:
264 /* Probe value to be within -32768 and 32767 */
265 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
266 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
267 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
268 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
269 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
272 case OP_LCONV_TO_OVF_I2_UN:
273 /* Probe value to be within 0 and 32767 */
274 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
275 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
276 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
279 case OP_LCONV_TO_OVF_U2:
280 /* Probe value to be within 0 and 65535 */
281 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
282 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
283 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
286 case OP_LCONV_TO_OVF_U2_UN:
287 /* Probe value to be within 0 and 65535 */
288 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
289 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
290 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
293 case OP_LCONV_TO_OVF_I4:
294 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
295 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
296 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
297 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
298 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
299 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
302 case OP_LCONV_TO_OVF_I4_UN:
303 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
304 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
305 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
308 case OP_LCONV_TO_OVF_U4:
309 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
310 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
311 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
312 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
313 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
316 case OP_LCONV_TO_OVF_U4_UN:
317 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
318 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
319 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
322 case OP_LCONV_TO_OVF_I:
323 case OP_LCONV_TO_OVF_U_UN:
324 case OP_LCONV_TO_OVF_U8_UN:
325 ins->opcode = OP_MOVE;
327 case OP_LCONV_TO_OVF_I_UN:
328 case OP_LCONV_TO_OVF_I8_UN:
329 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
330 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
331 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
334 case OP_LCONV_TO_OVF_U8:
335 case OP_LCONV_TO_OVF_U:
336 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
337 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
338 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
344 MonoJitICallInfo *info;
346 info = mono_find_jit_opcode_emulation (ins->opcode);
351 /* Create dummy MonoInst's for the arguments */
352 g_assert (!info->sig->hasthis);
353 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
355 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
356 if (info->sig->param_count > 0) {
357 int sregs [MONO_MAX_SRC_REGS];
359 num_sregs = mono_inst_get_src_registers (ins, sregs);
360 g_assert (num_sregs == info->sig->param_count);
361 for (i = 0; i < num_sregs; ++i) {
362 MONO_INST_NEW (cfg, args [i], OP_ARG);
363 args [i]->dreg = sregs [i];
367 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
368 call->dreg = ins->dreg;
376 if (ins->opcode == OP_NOP) {
381 /* Use the last emitted instruction */
382 ins = cfg->cbb->last_ins;
385 g_assert (ins->dreg == dreg);
393 #if SIZEOF_REGISTER == 4
394 static int lbr_decomp [][2] = {
396 {OP_IBGT, OP_IBGE_UN}, /* BGE */
397 {OP_IBGT, OP_IBGT_UN}, /* BGT */
398 {OP_IBLT, OP_IBLE_UN}, /* BLE */
399 {OP_IBLT, OP_IBLT_UN}, /* BLT */
401 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
402 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
403 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
404 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
407 static int lcset_decomp [][2] = {
409 {OP_IBLT, OP_IBLE_UN}, /* CGT */
410 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
411 {OP_IBGT, OP_IBGE_UN}, /* CLT */
412 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
417 * mono_decompose_long_opts:
419 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
422 mono_decompose_long_opts (MonoCompile *cfg)
424 #if SIZEOF_REGISTER == 4
425 MonoBasicBlock *bb, *first_bb;
428 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
429 * needs to be able to handle long vregs.
432 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
435 * Create a dummy bblock and emit code into it so we can use the normal
436 * code generation macros.
438 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
441 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
442 MonoInst *tree = bb->code;
443 MonoInst *prev = NULL;
446 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
450 cfg->cbb->code = cfg->cbb->last_ins = NULL;
454 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
455 mono_arch_decompose_long_opts (cfg, tree);
458 switch (tree->opcode) {
460 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
461 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
466 case OP_LCONV_TO_OVF_U8_UN:
467 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
468 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
470 case OP_STOREI8_MEMBASE_REG:
471 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
472 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
474 case OP_LOADI8_MEMBASE:
475 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
476 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
479 case OP_ICONV_TO_I8: {
480 guint32 tmpreg = alloc_ireg (cfg);
484 * tmp = low > -1 ? 1: 0;
485 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
487 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
488 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
489 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
490 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
494 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
495 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
497 case OP_ICONV_TO_OVF_I8:
498 /* a signed 32 bit num always fits in a signed 64 bit one */
499 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
500 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
502 case OP_ICONV_TO_OVF_U8:
503 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
504 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
505 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
506 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
508 case OP_ICONV_TO_OVF_I8_UN:
509 case OP_ICONV_TO_OVF_U8_UN:
510 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
511 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
512 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
515 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
518 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
521 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
524 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
530 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
533 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
536 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
538 case OP_LCONV_TO_R_UN:
539 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
541 case OP_LCONV_TO_OVF_I1: {
542 MonoBasicBlock *is_negative, *end_label;
544 NEW_BBLOCK (cfg, is_negative);
545 NEW_BBLOCK (cfg, end_label);
547 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
548 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
549 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
550 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
552 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
553 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
556 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
557 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
558 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
561 MONO_START_BB (cfg, is_negative);
562 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
563 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
565 MONO_START_BB (cfg, end_label);
567 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
570 case OP_LCONV_TO_OVF_I1_UN:
571 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
572 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
574 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
575 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
576 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
577 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
578 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
580 case OP_LCONV_TO_OVF_U1:
581 case OP_LCONV_TO_OVF_U1_UN:
582 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
583 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
585 /* probe value to be within 0 to 255 */
586 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
587 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
588 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
590 case OP_LCONV_TO_OVF_I2: {
591 MonoBasicBlock *is_negative, *end_label;
593 NEW_BBLOCK (cfg, is_negative);
594 NEW_BBLOCK (cfg, end_label);
596 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
597 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
598 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
599 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
601 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
602 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
605 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
606 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
607 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
610 MONO_START_BB (cfg, is_negative);
611 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
612 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
613 MONO_START_BB (cfg, end_label);
615 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
618 case OP_LCONV_TO_OVF_I2_UN:
619 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
620 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
622 /* Probe value to be within -32768 and 32767 */
623 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
624 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
625 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
626 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
627 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
629 case OP_LCONV_TO_OVF_U2:
630 case OP_LCONV_TO_OVF_U2_UN:
631 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
632 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
634 /* Probe value to be within 0 and 65535 */
635 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
636 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
637 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
639 case OP_LCONV_TO_OVF_I4:
640 case OP_LCONV_TO_OVF_I:
641 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
643 case OP_LCONV_TO_OVF_U4:
644 case OP_LCONV_TO_OVF_U:
645 case OP_LCONV_TO_OVF_U4_UN:
646 case OP_LCONV_TO_OVF_U_UN:
647 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
648 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
649 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
651 case OP_LCONV_TO_OVF_I_UN:
652 case OP_LCONV_TO_OVF_I4_UN:
653 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
654 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
655 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
656 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
657 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
659 case OP_LCONV_TO_OVF_U8:
660 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
661 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
663 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
664 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
666 case OP_LCONV_TO_OVF_I8_UN:
667 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
668 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
670 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
671 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
675 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
676 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
679 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
680 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
684 /* ADC sets the condition code */
685 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
686 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
687 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
690 /* ADC sets the condition code */
691 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
692 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
693 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
696 /* SBB sets the condition code */
697 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
698 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
699 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
702 /* SBB sets the condition code */
703 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
704 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
705 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
708 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
709 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
712 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
713 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
716 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
717 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
720 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
721 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
724 /* Handled in mono_arch_decompose_long_opts () */
725 g_assert_not_reached ();
729 /* FIXME: Add OP_BIGMUL optimization */
733 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
734 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
737 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
738 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
741 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
742 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
745 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
746 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
749 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
750 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
753 if (tree->inst_c1 == 32) {
755 /* The original code had this comment: */
756 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
757 * later apply the speedup to the left shift as well
760 /* FIXME: Move this to the strength reduction pass */
761 /* just move the upper half to the lower and zero the high word */
762 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
763 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
767 if (tree->inst_c1 == 32) {
768 /* just move the lower half to the upper and zero the lower word */
769 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
770 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
775 MonoInst *next = tree->next;
779 switch (next->opcode) {
784 /* Branchless version based on gcc code */
785 d1 = alloc_ireg (cfg);
786 d2 = alloc_ireg (cfg);
787 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
788 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
789 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
790 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
791 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
792 next->opcode = OP_NOP;
803 /* Convert into three comparisons + branches */
804 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
805 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
806 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
807 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
808 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
809 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
810 next->opcode = OP_NOP;
815 /* Branchless version based on gcc code */
816 d1 = alloc_ireg (cfg);
817 d2 = alloc_ireg (cfg);
818 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
819 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
820 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
822 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
823 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
824 next->opcode = OP_NOP;
831 MonoBasicBlock *set_to_0, *set_to_1;
833 NEW_BBLOCK (cfg, set_to_0);
834 NEW_BBLOCK (cfg, set_to_1);
836 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
837 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
838 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
839 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
840 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
841 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
842 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
843 MONO_START_BB (cfg, set_to_1);
844 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
845 MONO_START_BB (cfg, set_to_0);
846 next->opcode = OP_NOP;
850 g_assert_not_reached ();
855 /* Not yet used, since lcompare is decomposed before local cprop */
856 case OP_LCOMPARE_IMM: {
857 MonoInst *next = tree->next;
858 guint32 low_imm = tree->inst_ls_word;
859 guint32 high_imm = tree->inst_ms_word;
860 int low_reg = tree->sreg1 + 1;
861 int high_reg = tree->sreg1 + 2;
865 switch (next->opcode) {
870 /* Branchless version based on gcc code */
871 d1 = alloc_ireg (cfg);
872 d2 = alloc_ireg (cfg);
873 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
874 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
875 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
876 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
877 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
878 next->opcode = OP_NOP;
890 /* Convert into three comparisons + branches */
891 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
892 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
893 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
894 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
895 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
896 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
897 next->opcode = OP_NOP;
902 /* Branchless version based on gcc code */
903 d1 = alloc_ireg (cfg);
904 d2 = alloc_ireg (cfg);
905 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
906 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
907 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
909 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
910 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
911 next->opcode = OP_NOP;
918 MonoBasicBlock *set_to_0, *set_to_1;
920 NEW_BBLOCK (cfg, set_to_0);
921 NEW_BBLOCK (cfg, set_to_1);
923 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
925 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
927 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
929 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
930 MONO_START_BB (cfg, set_to_1);
931 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
932 MONO_START_BB (cfg, set_to_0);
933 next->opcode = OP_NOP;
937 g_assert_not_reached ();
946 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
949 /* Replace the original instruction with the new code sequence */
951 /* Ignore the new value of prev */
953 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
955 /* Process the newly added ops again since they can be long ops too */
961 first_bb->code = first_bb->last_ins = NULL;
962 first_bb->in_count = first_bb->out_count = 0;
974 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
975 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
980 * mono_decompose_vtype_opts:
982 * Decompose valuetype opcodes.
985 mono_decompose_vtype_opts (MonoCompile *cfg)
987 MonoBasicBlock *bb, *first_bb;
990 * Using OP_V opcodes and decomposing them later have two main benefits:
991 * - it simplifies method_to_ir () since there is no need to special-case vtypes
993 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
994 * enabling optimizations to work on vtypes too.
995 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
996 * can be executed anytime. It should be executed as late as possible so vtype
997 * opcodes can be optimized by the other passes.
998 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
999 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1001 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1002 * when OP_VMOVE opcodes are decomposed.
1006 * Vregs have no associated type information, so we store the type of the vregs
1011 * Create a dummy bblock and emit code into it so we can use the normal
1012 * code generation macros.
1014 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1015 first_bb = cfg->cbb;
1017 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1019 MonoInst *prev = NULL;
1020 MonoInst *src_var, *dest_var, *src, *dest;
1024 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1026 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1032 for (ins = bb->code; ins; ins = ins->next) {
1033 switch (ins->opcode) {
1035 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1036 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1038 g_assert (ins->klass);
1041 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1044 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1047 if (src_var->backend.is_pinvoke)
1048 dest_var->backend.is_pinvoke = 1;
1050 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1051 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1053 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1057 g_assert (ins->klass);
1059 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1060 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1062 case OP_STOREV_MEMBASE: {
1063 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1066 g_assert (ins->klass);
1067 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1070 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1072 dreg = alloc_preg (cfg);
1073 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1074 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1077 case OP_LOADV_MEMBASE: {
1078 g_assert (ins->klass);
1080 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1083 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1085 dreg = alloc_preg (cfg);
1086 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1087 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1088 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1091 case OP_OUTARG_VT: {
1092 g_assert (ins->klass);
1094 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1096 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1097 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1099 mono_arch_emit_outarg_vt (cfg, ins, src);
1101 /* This might be decomposed into other vtype opcodes */
1105 case OP_OUTARG_VTRETADDR: {
1106 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1108 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1110 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1111 // FIXME: src_var->backend.is_pinvoke ?
1113 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1114 src->dreg = ins->dreg;
1119 case OP_VCALL_MEMBASE: {
1120 MonoCallInst *call = (MonoCallInst*)ins;
1123 if (call->vret_in_reg) {
1124 MonoCallInst *call2;
1126 /* Replace the vcall with an integer call */
1127 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1128 memcpy (call2, call, sizeof (MonoCallInst));
1129 switch (ins->opcode) {
1131 call2->inst.opcode = OP_CALL;
1134 call2->inst.opcode = OP_CALL_REG;
1136 case OP_VCALL_MEMBASE:
1137 call2->inst.opcode = OP_CALL_MEMBASE;
1140 call2->inst.dreg = alloc_preg (cfg);
1141 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1143 /* Compute the vtype location */
1144 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1146 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1147 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1149 /* Save the result */
1150 if (dest_var->backend.is_pinvoke)
1151 size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
1153 size = mono_type_size (dest_var->inst_vtype, NULL);
1156 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1159 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1162 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1165 #if SIZEOF_REGISTER == 4
1167 FIXME It would be nice to fix the operding of OP_CALL to make it possible to use numbering voodoo
1168 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1170 switch (call2->inst.opcode) {
1172 call2->inst.opcode = OP_LCALL;
1175 call2->inst.opcode = OP_LCALL_REG;
1177 case OP_CALL_MEMBASE:
1178 call2->inst.opcode = OP_LCALL_MEMBASE;
1181 call2->inst.dreg = alloc_lreg (cfg);
1182 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1183 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1185 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1189 /* This assumes the vtype is sizeof (gpointer) long */
1190 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1194 switch (ins->opcode) {
1196 ins->opcode = OP_VCALL2;
1199 ins->opcode = OP_VCALL2_REG;
1201 case OP_VCALL_MEMBASE:
1202 ins->opcode = OP_VCALL2_MEMBASE;
1213 g_assert (cfg->cbb == first_bb);
1215 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1216 /* Replace the original instruction with the new code sequence */
1218 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1219 first_bb->code = first_bb->last_ins = NULL;
1220 first_bb->in_count = first_bb->out_count = 0;
1221 cfg->cbb = first_bb;
1228 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1232 #endif /* DISABLE_JIT */