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);
184 #if defined(__mono_ppc__) && !defined(__mono_ppc64__)
186 /* ADC sets the condition code */
187 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
188 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
190 g_assert_not_reached ();
193 /* ADC sets the condition code */
194 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
195 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
197 g_assert_not_reached ();
200 /* SBB sets the condition code */
201 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
202 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
204 g_assert_not_reached ();
207 /* SBB sets the condition code */
208 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
209 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
211 g_assert_not_reached ();
215 if (COMPILE_LLVM (cfg))
217 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
218 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
222 if (COMPILE_LLVM (cfg))
224 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
225 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
228 #ifndef __mono_ppc64__
230 if (COMPILE_LLVM (cfg))
232 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
233 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
237 if (COMPILE_LLVM (cfg))
239 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
240 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
246 case OP_ICONV_TO_OVF_I8:
247 case OP_ICONV_TO_OVF_I:
248 ins->opcode = OP_SEXT_I4;
250 case OP_ICONV_TO_OVF_U8:
251 case OP_ICONV_TO_OVF_U:
252 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
253 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
254 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
257 case OP_ICONV_TO_OVF_I8_UN:
258 case OP_ICONV_TO_OVF_U8_UN:
259 case OP_ICONV_TO_OVF_I_UN:
260 case OP_ICONV_TO_OVF_U_UN:
261 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
262 /* Clean out the upper word */
263 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
266 case OP_LCONV_TO_OVF_I1:
267 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
268 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
269 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
270 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
271 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
274 case OP_LCONV_TO_OVF_I1_UN:
275 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
276 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
277 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
280 case OP_LCONV_TO_OVF_U1:
281 /* probe value to be within 0 to 255 */
282 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
283 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
284 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
287 case OP_LCONV_TO_OVF_U1_UN:
288 /* probe value to be within 0 to 255 */
289 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
290 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
291 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
294 case OP_LCONV_TO_OVF_I2:
295 /* Probe value to be within -32768 and 32767 */
296 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
297 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
298 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
299 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
300 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
303 case OP_LCONV_TO_OVF_I2_UN:
304 /* Probe value to be within 0 and 32767 */
305 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
306 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
307 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
310 case OP_LCONV_TO_OVF_U2:
311 /* Probe value to be within 0 and 65535 */
312 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
313 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
314 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
317 case OP_LCONV_TO_OVF_U2_UN:
318 /* Probe value to be within 0 and 65535 */
319 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
320 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
321 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
324 case OP_LCONV_TO_OVF_I4:
325 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
326 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
327 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
328 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
329 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
330 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
333 case OP_LCONV_TO_OVF_I4_UN:
334 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
335 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
336 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
339 case OP_LCONV_TO_OVF_U4:
340 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
341 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
342 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
343 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
344 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
347 case OP_LCONV_TO_OVF_U4_UN:
348 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
349 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
350 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
353 case OP_LCONV_TO_OVF_I:
354 case OP_LCONV_TO_OVF_U_UN:
355 case OP_LCONV_TO_OVF_U8_UN:
356 ins->opcode = OP_MOVE;
358 case OP_LCONV_TO_OVF_I_UN:
359 case OP_LCONV_TO_OVF_I8_UN:
360 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
361 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
362 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
365 case OP_LCONV_TO_OVF_U8:
366 case OP_LCONV_TO_OVF_U:
367 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
368 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
369 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
375 MonoJitICallInfo *info;
377 info = mono_find_jit_opcode_emulation (ins->opcode);
382 /* Create dummy MonoInst's for the arguments */
383 g_assert (!info->sig->hasthis);
384 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
386 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
387 if (info->sig->param_count > 0) {
388 int sregs [MONO_MAX_SRC_REGS];
390 num_sregs = mono_inst_get_src_registers (ins, sregs);
391 g_assert (num_sregs == info->sig->param_count);
392 for (i = 0; i < num_sregs; ++i) {
393 MONO_INST_NEW (cfg, args [i], OP_ARG);
394 args [i]->dreg = sregs [i];
398 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
399 call->dreg = ins->dreg;
407 if (ins->opcode == OP_NOP) {
412 /* Use the last emitted instruction */
413 ins = cfg->cbb->last_ins;
416 g_assert (ins->dreg == dreg);
424 #if SIZEOF_REGISTER == 4
425 static int lbr_decomp [][2] = {
427 {OP_IBGT, OP_IBGE_UN}, /* BGE */
428 {OP_IBGT, OP_IBGT_UN}, /* BGT */
429 {OP_IBLT, OP_IBLE_UN}, /* BLE */
430 {OP_IBLT, OP_IBLT_UN}, /* BLT */
432 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
433 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
434 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
435 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
438 static int lcset_decomp [][2] = {
440 {OP_IBLT, OP_IBLE_UN}, /* CGT */
441 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
442 {OP_IBGT, OP_IBGE_UN}, /* CLT */
443 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
448 * mono_decompose_long_opts:
450 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
453 mono_decompose_long_opts (MonoCompile *cfg)
455 #if SIZEOF_REGISTER == 4
456 MonoBasicBlock *bb, *first_bb;
459 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
460 * needs to be able to handle long vregs.
463 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
466 * Create a dummy bblock and emit code into it so we can use the normal
467 * code generation macros.
469 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
472 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
473 MonoInst *tree = bb->code;
474 MonoInst *prev = NULL;
477 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
481 cfg->cbb->code = cfg->cbb->last_ins = NULL;
485 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
486 mono_arch_decompose_long_opts (cfg, tree);
489 switch (tree->opcode) {
491 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
492 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
497 case OP_LCONV_TO_OVF_U8_UN:
498 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
499 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
501 case OP_STOREI8_MEMBASE_REG:
502 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
503 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
505 case OP_LOADI8_MEMBASE:
506 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
507 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
510 case OP_ICONV_TO_I8: {
511 guint32 tmpreg = alloc_ireg (cfg);
515 * tmp = low > -1 ? 1: 0;
516 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
518 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
519 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
520 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
521 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
525 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
526 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
528 case OP_ICONV_TO_OVF_I8:
529 /* a signed 32 bit num always fits in a signed 64 bit one */
530 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
531 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
533 case OP_ICONV_TO_OVF_U8:
534 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
535 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
536 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
537 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
539 case OP_ICONV_TO_OVF_I8_UN:
540 case OP_ICONV_TO_OVF_U8_UN:
541 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
542 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
543 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
546 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
549 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
552 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
555 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
561 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
564 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
567 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
569 case OP_LCONV_TO_R_UN:
570 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
572 case OP_LCONV_TO_OVF_I1: {
573 MonoBasicBlock *is_negative, *end_label;
575 NEW_BBLOCK (cfg, is_negative);
576 NEW_BBLOCK (cfg, end_label);
578 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
579 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
580 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
581 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
583 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
584 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
587 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
588 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
589 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
592 MONO_START_BB (cfg, is_negative);
593 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
594 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
596 MONO_START_BB (cfg, end_label);
598 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
601 case OP_LCONV_TO_OVF_I1_UN:
602 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
603 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
605 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
606 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
607 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
608 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
609 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
611 case OP_LCONV_TO_OVF_U1:
612 case OP_LCONV_TO_OVF_U1_UN:
613 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
614 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
616 /* probe value to be within 0 to 255 */
617 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
618 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
619 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
621 case OP_LCONV_TO_OVF_I2: {
622 MonoBasicBlock *is_negative, *end_label;
624 NEW_BBLOCK (cfg, is_negative);
625 NEW_BBLOCK (cfg, end_label);
627 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
628 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
629 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
630 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
632 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
633 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
636 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
637 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
638 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
641 MONO_START_BB (cfg, is_negative);
642 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
643 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
644 MONO_START_BB (cfg, end_label);
646 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
649 case OP_LCONV_TO_OVF_I2_UN:
650 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
651 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
653 /* Probe value to be within -32768 and 32767 */
654 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
655 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
656 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
657 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
658 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
660 case OP_LCONV_TO_OVF_U2:
661 case OP_LCONV_TO_OVF_U2_UN:
662 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
663 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
665 /* Probe value to be within 0 and 65535 */
666 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
667 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
668 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
670 case OP_LCONV_TO_OVF_I4:
671 case OP_LCONV_TO_OVF_I:
672 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
674 case OP_LCONV_TO_OVF_U4:
675 case OP_LCONV_TO_OVF_U:
676 case OP_LCONV_TO_OVF_U4_UN:
677 case OP_LCONV_TO_OVF_U_UN:
678 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
679 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
680 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
682 case OP_LCONV_TO_OVF_I_UN:
683 case OP_LCONV_TO_OVF_I4_UN:
684 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
685 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
686 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
687 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
688 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
690 case OP_LCONV_TO_OVF_U8:
691 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
692 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
694 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
695 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
697 case OP_LCONV_TO_OVF_I8_UN:
698 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
699 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
701 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
702 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
706 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
707 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
710 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
711 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
714 #if defined(__ppc__) || defined(__powerpc__)
716 /* ADC sets the condition code */
717 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
718 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
721 /* ADC sets the condition code */
722 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
723 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
726 /* SBB sets the condition code */
727 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
728 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
731 /* SBB sets the condition code */
732 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
733 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
737 /* ADC sets the condition code */
738 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
739 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
740 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
743 /* ADC sets the condition code */
744 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
745 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
746 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
749 /* SBB sets the condition code */
750 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
751 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
752 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
755 /* SBB sets the condition code */
756 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
757 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
758 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
762 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
763 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
766 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
767 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
770 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
771 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
774 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
775 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
779 * FIXME: The original version in inssel-long32.brg does not work
780 * on x86, and the x86 version might not work on other archs ?
782 /* FIXME: Move these to mono_arch_decompose_long_opts () */
783 #if defined(__i386__)
784 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
785 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
786 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
787 #elif defined(__sparc__)
788 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
789 MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
790 #elif defined(__arm__)
791 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
792 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
793 #elif defined(__ppc__) || defined(__powerpc__)
794 /* This is the old version from inssel-long32.brg */
795 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
796 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
797 /* ADC sets the condition codes */
798 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 1, tree->dreg + 1, 1);
799 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->dreg + 2, 0);
806 /* FIXME: Add OP_BIGMUL optimization */
810 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
811 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
814 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
815 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
818 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
819 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
822 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
823 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
826 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
827 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
830 if (tree->inst_c1 == 32) {
832 /* The original code had this comment: */
833 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
834 * later apply the speedup to the left shift as well
837 /* FIXME: Move this to the strength reduction pass */
838 /* just move the upper half to the lower and zero the high word */
839 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
840 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
844 if (tree->inst_c1 == 32) {
845 /* just move the lower half to the upper and zero the lower word */
846 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
847 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
852 MonoInst *next = tree->next;
856 switch (next->opcode) {
861 /* Branchless version based on gcc code */
862 d1 = alloc_ireg (cfg);
863 d2 = alloc_ireg (cfg);
864 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
865 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
866 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
867 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
868 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
869 next->opcode = OP_NOP;
880 /* Convert into three comparisons + branches */
881 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
882 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
883 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
884 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
885 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
886 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
887 next->opcode = OP_NOP;
892 /* Branchless version based on gcc code */
893 d1 = alloc_ireg (cfg);
894 d2 = alloc_ireg (cfg);
895 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
896 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
897 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
899 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
900 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
901 next->opcode = OP_NOP;
908 MonoBasicBlock *set_to_0, *set_to_1;
910 NEW_BBLOCK (cfg, set_to_0);
911 NEW_BBLOCK (cfg, set_to_1);
913 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
914 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
915 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
916 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
917 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
918 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
919 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
920 MONO_START_BB (cfg, set_to_1);
921 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
922 MONO_START_BB (cfg, set_to_0);
923 next->opcode = OP_NOP;
927 g_assert_not_reached ();
932 /* Not yet used, since lcompare is decomposed before local cprop */
933 case OP_LCOMPARE_IMM: {
934 MonoInst *next = tree->next;
935 guint32 low_imm = tree->inst_ls_word;
936 guint32 high_imm = tree->inst_ms_word;
937 int low_reg = tree->sreg1 + 1;
938 int high_reg = tree->sreg1 + 2;
942 switch (next->opcode) {
947 /* Branchless version based on gcc code */
948 d1 = alloc_ireg (cfg);
949 d2 = alloc_ireg (cfg);
950 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
951 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
952 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
953 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
954 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
955 next->opcode = OP_NOP;
967 /* Convert into three comparisons + branches */
968 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
969 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
970 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
971 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
972 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
973 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
974 next->opcode = OP_NOP;
979 /* Branchless version based on gcc code */
980 d1 = alloc_ireg (cfg);
981 d2 = alloc_ireg (cfg);
982 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
983 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
984 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
986 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
987 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
988 next->opcode = OP_NOP;
995 MonoBasicBlock *set_to_0, *set_to_1;
997 NEW_BBLOCK (cfg, set_to_0);
998 NEW_BBLOCK (cfg, set_to_1);
1000 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1001 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1002 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1003 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1004 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1005 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1006 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1007 MONO_START_BB (cfg, set_to_1);
1008 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1009 MONO_START_BB (cfg, set_to_0);
1010 next->opcode = OP_NOP;
1014 g_assert_not_reached ();
1023 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1026 /* Replace the original instruction with the new code sequence */
1028 /* Ignore the new value of prev */
1030 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1032 /* Process the newly added ops again since they can be long ops too */
1038 first_bb->code = first_bb->last_ins = NULL;
1039 first_bb->in_count = first_bb->out_count = 0;
1040 cfg->cbb = first_bb;
1051 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1052 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1057 * mono_decompose_vtype_opts:
1059 * Decompose valuetype opcodes.
1062 mono_decompose_vtype_opts (MonoCompile *cfg)
1064 MonoBasicBlock *bb, *first_bb;
1067 * Using OP_V opcodes and decomposing them later have two main benefits:
1068 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1070 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1071 * enabling optimizations to work on vtypes too.
1072 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1073 * can be executed anytime. It should be executed as late as possible so vtype
1074 * opcodes can be optimized by the other passes.
1075 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1076 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1078 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1079 * when OP_VMOVE opcodes are decomposed.
1083 * Vregs have no associated type information, so we store the type of the vregs
1088 * Create a dummy bblock and emit code into it so we can use the normal
1089 * code generation macros.
1091 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1092 first_bb = cfg->cbb;
1094 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1096 MonoInst *prev = NULL;
1097 MonoInst *src_var, *dest_var, *src, *dest;
1101 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1103 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1109 for (ins = bb->code; ins; ins = ins->next) {
1110 switch (ins->opcode) {
1112 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1113 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1115 g_assert (ins->klass);
1118 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1121 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1124 if (src_var->backend.is_pinvoke)
1125 dest_var->backend.is_pinvoke = 1;
1127 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1128 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1130 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1134 g_assert (ins->klass);
1136 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1137 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1139 case OP_STOREV_MEMBASE: {
1140 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1143 g_assert (ins->klass);
1144 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1147 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1149 dreg = alloc_preg (cfg);
1150 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1151 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1154 case OP_LOADV_MEMBASE: {
1155 g_assert (ins->klass);
1157 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1160 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1162 dreg = alloc_preg (cfg);
1163 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1164 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1165 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1168 case OP_OUTARG_VT: {
1169 g_assert (ins->klass);
1171 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1173 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1174 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1176 mono_arch_emit_outarg_vt (cfg, ins, src);
1178 /* This might be decomposed into other vtype opcodes */
1182 case OP_OUTARG_VTRETADDR: {
1183 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1185 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1187 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1188 // FIXME: src_var->backend.is_pinvoke ?
1190 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1191 src->dreg = ins->dreg;
1196 case OP_VCALL_MEMBASE: {
1197 MonoCallInst *call = (MonoCallInst*)ins;
1200 if (call->vret_in_reg) {
1201 MonoCallInst *call2;
1203 /* Replace the vcall with an integer call */
1204 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1205 memcpy (call2, call, sizeof (MonoCallInst));
1206 switch (ins->opcode) {
1208 call2->inst.opcode = OP_CALL;
1211 call2->inst.opcode = OP_CALL_REG;
1213 case OP_VCALL_MEMBASE:
1214 call2->inst.opcode = OP_CALL_MEMBASE;
1217 call2->inst.dreg = alloc_preg (cfg);
1218 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1220 /* Compute the vtype location */
1221 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1223 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1224 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1226 /* Save the result */
1227 if (dest_var->backend.is_pinvoke)
1228 size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
1230 size = mono_type_size (dest_var->inst_vtype, NULL);
1233 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1236 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1239 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1242 #if SIZEOF_REGISTER == 4
1244 FIXME It would be nice to fix the operding of OP_CALL to make it possible to use numbering voodoo
1245 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1247 switch (call2->inst.opcode) {
1249 call2->inst.opcode = OP_LCALL;
1252 call2->inst.opcode = OP_LCALL_REG;
1254 case OP_CALL_MEMBASE:
1255 call2->inst.opcode = OP_LCALL_MEMBASE;
1258 call2->inst.dreg = alloc_lreg (cfg);
1259 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1260 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1262 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1266 /* This assumes the vtype is sizeof (gpointer) long */
1267 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1271 switch (ins->opcode) {
1273 ins->opcode = OP_VCALL2;
1276 ins->opcode = OP_VCALL2_REG;
1278 case OP_VCALL_MEMBASE:
1279 ins->opcode = OP_VCALL2_MEMBASE;
1290 g_assert (cfg->cbb == first_bb);
1292 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1293 /* Replace the original instruction with the new code sequence */
1295 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1296 first_bb->code = first_bb->last_ins = NULL;
1297 first_bb->in_count = first_bb->out_count = 0;
1298 cfg->cbb = first_bb;
1305 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1309 #endif /* DISABLE_JIT */