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 Other ABIs might return in different regs than the ones used for LCALL.
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 */