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.
27 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
29 /* FIXME: Instead of = NOP, don't emit the original ins at all */
31 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
32 mono_arch_decompose_opts (cfg, ins);
36 * The code below assumes that we are called immediately after emitting
37 * ins. This means we can emit code using the normal code generation
40 switch (ins->opcode) {
41 /* this doesn't make sense on ppc and other architectures */
42 #if !defined(MONO_ARCH_NO_IOV_CHECK)
44 ins->opcode = OP_IADDCC;
45 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
48 ins->opcode = OP_IADDCC;
49 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
52 ins->opcode = OP_ISUBCC;
53 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
56 ins->opcode = OP_ISUBCC;
57 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
60 case OP_ICONV_TO_OVF_I1:
61 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
62 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
63 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
64 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
65 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
68 case OP_ICONV_TO_OVF_I1_UN:
69 /* probe values between 0 to 127 */
70 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
71 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
72 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
75 case OP_ICONV_TO_OVF_U1:
76 case OP_ICONV_TO_OVF_U1_UN:
77 /* probe value to be within 0 to 255 */
78 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
79 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
80 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
83 case OP_ICONV_TO_OVF_I2:
84 /* Probe value to be within -32768 and 32767 */
85 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
86 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
87 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
88 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
89 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
92 case OP_ICONV_TO_OVF_I2_UN:
93 /* Convert uint value into short, value within 0 and 32767 */
94 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
95 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
96 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
99 case OP_ICONV_TO_OVF_U2:
100 case OP_ICONV_TO_OVF_U2_UN:
101 /* Probe value to be within 0 and 65535 */
102 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
103 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
104 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
105 ins->opcode = OP_NOP;
107 case OP_ICONV_TO_OVF_U4:
108 case OP_ICONV_TO_OVF_I4_UN:
109 #if SIZEOF_VOID_P == 4
110 case OP_ICONV_TO_OVF_U:
111 case OP_ICONV_TO_OVF_I_UN:
113 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
114 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
115 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
116 ins->opcode = OP_NOP;
120 case OP_ICONV_TO_OVF_I4:
121 #if SIZEOF_VOID_P == 4
122 case OP_ICONV_TO_OVF_I:
123 case OP_ICONV_TO_OVF_U_UN:
125 ins->opcode = OP_MOVE;
128 #if SIZEOF_VOID_P == 8
129 ins->opcode = OP_SEXT_I4;
131 ins->opcode = OP_MOVE;
135 #if SIZEOF_VOID_P == 8
136 ins->opcode = OP_ZEXT_I4;
138 ins->opcode = OP_MOVE;
143 ins->opcode = OP_FMOVE;
146 /* Long opcodes on 64 bit machines */
147 #if SIZEOF_VOID_P == 8
149 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
150 ins->opcode = OP_NOP;
156 ins->opcode = OP_MOVE;
159 ins->opcode = OP_SEXT_I4;
162 ins->opcode = OP_ZEXT_I4;
165 /* Clean out the upper word */
166 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
167 ins->opcode = OP_NOP;
169 #if defined(__ppc__) || defined(__powerpc__)
171 /* ADC sets the condition code */
172 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
173 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
174 ins->opcode = OP_NOP;
175 g_assert_not_reached ();
178 /* ADC sets the condition code */
179 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
180 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
181 ins->opcode = OP_NOP;
182 g_assert_not_reached ();
185 /* SBB sets the condition code */
186 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
187 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
188 ins->opcode = OP_NOP;
189 g_assert_not_reached ();
192 /* SBB sets the condition code */
193 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
194 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
195 ins->opcode = OP_NOP;
196 g_assert_not_reached ();
200 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
201 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
202 ins->opcode = OP_NOP;
205 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
206 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
207 ins->opcode = OP_NOP;
210 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
211 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
212 ins->opcode = OP_NOP;
215 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
216 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
217 ins->opcode = OP_NOP;
221 case OP_ICONV_TO_OVF_I8:
222 case OP_ICONV_TO_OVF_I:
223 ins->opcode = OP_SEXT_I4;
225 case OP_ICONV_TO_OVF_U8:
226 case OP_ICONV_TO_OVF_U:
227 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
228 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
229 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
230 ins->opcode = OP_NOP;
232 case OP_ICONV_TO_OVF_I8_UN:
233 case OP_ICONV_TO_OVF_U8_UN:
234 case OP_ICONV_TO_OVF_I_UN:
235 case OP_ICONV_TO_OVF_U_UN:
236 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
237 /* Clean out the upper word */
238 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
239 ins->opcode = OP_NOP;
241 case OP_LCONV_TO_OVF_I1:
242 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
243 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
244 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
245 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
246 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
247 ins->opcode = OP_NOP;
249 case OP_LCONV_TO_OVF_I1_UN:
250 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
251 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
252 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
253 ins->opcode = OP_NOP;
255 case OP_LCONV_TO_OVF_U1:
256 /* probe value to be within 0 to 255 */
257 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
258 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
259 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
260 ins->opcode = OP_NOP;
262 case OP_LCONV_TO_OVF_U1_UN:
263 /* probe value to be within 0 to 255 */
264 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
265 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
266 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
267 ins->opcode = OP_NOP;
269 case OP_LCONV_TO_OVF_I2:
270 /* Probe value to be within -32768 and 32767 */
271 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
272 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
273 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
274 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
275 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
276 ins->opcode = OP_NOP;
278 case OP_LCONV_TO_OVF_I2_UN:
279 /* Probe value to be within 0 and 32767 */
280 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
281 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
282 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
283 ins->opcode = OP_NOP;
285 case OP_LCONV_TO_OVF_U2:
286 /* Probe value to be within 0 and 65535 */
287 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
288 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
289 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
290 ins->opcode = OP_NOP;
292 case OP_LCONV_TO_OVF_U2_UN:
293 /* Probe value to be within 0 and 65535 */
294 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
295 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
296 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
297 ins->opcode = OP_NOP;
299 case OP_LCONV_TO_OVF_I4:
300 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
301 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
302 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
303 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
304 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
305 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
306 ins->opcode = OP_NOP;
308 case OP_LCONV_TO_OVF_I4_UN:
309 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
310 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
311 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
312 ins->opcode = OP_NOP;
314 case OP_LCONV_TO_OVF_U4:
315 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
316 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
317 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
318 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
319 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
320 ins->opcode = OP_NOP;
322 case OP_LCONV_TO_OVF_U4_UN:
323 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
324 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
325 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
326 ins->opcode = OP_NOP;
328 case OP_LCONV_TO_OVF_I:
329 case OP_LCONV_TO_OVF_U_UN:
330 case OP_LCONV_TO_OVF_U8_UN:
331 ins->opcode = OP_MOVE;
333 case OP_LCONV_TO_OVF_I_UN:
334 case OP_LCONV_TO_OVF_I8_UN:
335 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
336 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
337 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
338 ins->opcode = OP_NOP;
340 case OP_LCONV_TO_OVF_U8:
341 case OP_LCONV_TO_OVF_U:
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);
345 ins->opcode = OP_NOP;
350 MonoJitICallInfo *info;
352 info = mono_find_jit_opcode_emulation (ins->opcode);
357 /* Create dummy MonoInst's for the arguments */
358 g_assert (!info->sig->hasthis);
359 g_assert (info->sig->param_count <= 2);
361 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
362 if (info->sig->param_count > 0) {
363 MONO_INST_NEW (cfg, args [0], OP_ARG);
364 args [0]->dreg = ins->sreg1;
366 if (info->sig->param_count > 1) {
367 MONO_INST_NEW (cfg, args [1], OP_ARG);
368 args [1]->dreg = ins->sreg2;
371 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
372 call->dreg = ins->dreg;
374 ins->opcode = OP_NOP;
381 #if SIZEOF_VOID_P == 4
382 static int lbr_decomp [][2] = {
384 {OP_IBGT, OP_IBGE_UN}, /* BGE */
385 {OP_IBGT, OP_IBGT_UN}, /* BGT */
386 {OP_IBLT, OP_IBLE_UN}, /* BLE */
387 {OP_IBLT, OP_IBLT_UN}, /* BLT */
389 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
390 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
391 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
392 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
395 static int lcset_decomp [][2] = {
397 {OP_IBLT, OP_IBLE_UN}, /* CGT */
398 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
399 {OP_IBGT, OP_IBGE_UN}, /* CLT */
400 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
405 * mono_decompose_long_opts:
407 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
410 mono_decompose_long_opts (MonoCompile *cfg)
412 #if SIZEOF_VOID_P == 4
413 MonoBasicBlock *bb, *first_bb;
416 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
417 * needs to be able to handle long vregs.
420 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
423 * Create a dummy bblock and emit code into it so we can use the normal
424 * code generation macros.
426 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
429 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
430 MonoInst *tree = bb->code;
431 MonoInst *prev = NULL;
434 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
438 cfg->cbb->code = cfg->cbb->last_ins = NULL;
442 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
443 mono_arch_decompose_long_opts (cfg, tree);
446 switch (tree->opcode) {
448 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
449 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
454 case OP_LCONV_TO_OVF_U8_UN:
455 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
456 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
458 case OP_STOREI8_MEMBASE_REG:
459 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
460 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
462 case OP_LOADI8_MEMBASE:
463 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
464 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
467 case OP_ICONV_TO_I8: {
468 guint32 tmpreg = alloc_ireg (cfg);
472 * tmp = low > -1 ? 1: 0;
473 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
475 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
476 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
477 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
478 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
482 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
483 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
485 case OP_ICONV_TO_OVF_I8:
486 /* a signed 32 bit num always fits in a signed 64 bit one */
487 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
488 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
490 case OP_ICONV_TO_OVF_U8:
491 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
492 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
493 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
494 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
496 case OP_ICONV_TO_OVF_I8_UN:
497 case OP_ICONV_TO_OVF_U8_UN:
498 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
499 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
500 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
503 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
506 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
509 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
512 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
518 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
521 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
524 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
526 case OP_LCONV_TO_R_UN:
527 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
529 case OP_LCONV_TO_OVF_I1: {
530 MonoBasicBlock *is_negative, *end_label;
532 NEW_BBLOCK (cfg, is_negative);
533 NEW_BBLOCK (cfg, end_label);
535 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
536 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
537 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
538 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
540 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
541 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
544 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
545 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
546 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
549 MONO_START_BB (cfg, is_negative);
550 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
551 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
553 MONO_START_BB (cfg, end_label);
555 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
558 case OP_LCONV_TO_OVF_I1_UN:
559 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
560 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
562 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
563 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
564 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
565 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
566 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
568 case OP_LCONV_TO_OVF_U1:
569 case OP_LCONV_TO_OVF_U1_UN:
570 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
571 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
573 /* probe value to be within 0 to 255 */
574 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
575 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
576 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
578 case OP_LCONV_TO_OVF_I2: {
579 MonoBasicBlock *is_negative, *end_label;
581 NEW_BBLOCK (cfg, is_negative);
582 NEW_BBLOCK (cfg, end_label);
584 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
585 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
586 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
587 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
589 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
590 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
593 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
594 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
595 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
598 MONO_START_BB (cfg, is_negative);
599 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
600 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
601 MONO_START_BB (cfg, end_label);
603 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
606 case OP_LCONV_TO_OVF_I2_UN:
607 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
608 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
610 /* Probe value to be within -32768 and 32767 */
611 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
612 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
613 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
614 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
615 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
617 case OP_LCONV_TO_OVF_U2:
618 case OP_LCONV_TO_OVF_U2_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 0 and 65535 */
623 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
624 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
625 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
627 case OP_LCONV_TO_OVF_I4:
628 case OP_LCONV_TO_OVF_I:
629 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
631 case OP_LCONV_TO_OVF_U4:
632 case OP_LCONV_TO_OVF_U:
633 case OP_LCONV_TO_OVF_U4_UN:
634 case OP_LCONV_TO_OVF_U_UN:
635 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
636 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
637 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
639 case OP_LCONV_TO_OVF_I_UN:
640 case OP_LCONV_TO_OVF_I4_UN:
641 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
642 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
643 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
644 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
645 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
647 case OP_LCONV_TO_OVF_U8:
648 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
649 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
651 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
652 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
654 case OP_LCONV_TO_OVF_I8_UN:
655 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
656 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
658 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
659 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
663 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
664 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
667 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
668 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
671 #if defined(__ppc__) || defined(__powerpc__)
673 /* ADC sets the condition code */
674 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
675 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
678 /* ADC sets the condition code */
679 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
680 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
683 /* SBB sets the condition code */
684 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
685 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
688 /* SBB sets the condition code */
689 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
690 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
694 /* ADC sets the condition code */
695 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
696 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
697 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
700 /* ADC sets the condition code */
701 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
702 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
703 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
706 /* SBB sets the condition code */
707 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
708 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
709 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
712 /* SBB sets the condition code */
713 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
714 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
715 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
719 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
720 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
723 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
724 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
727 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
728 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
731 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
732 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
736 * FIXME: The original version in inssel-long32.brg does not work
737 * on x86, and the x86 version might not work on other archs ?
739 /* FIXME: Move these to mono_arch_decompose_long_opts () */
740 #if defined(__i386__)
741 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
742 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
743 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
744 #elif defined(__sparc__)
745 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
746 MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
747 #elif defined(__arm__)
748 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
749 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
750 #elif defined(__ppc__) || defined(__powerpc__)
751 /* This is the old version from inssel-long32.brg */
752 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
753 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
754 /* ADC sets the condition codes */
755 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 1, tree->dreg + 1, 1);
756 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->dreg + 2, 0);
763 /* FIXME: Add OP_BIGMUL optimization */
767 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
768 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
771 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
772 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
775 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
776 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
779 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
780 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
783 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
784 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
787 if (tree->inst_c1 == 32) {
789 /* The original code had this comment: */
790 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
791 * later apply the speedup to the left shift as well
794 /* FIXME: Move this to the strength reduction pass */
795 /* just move the upper half to the lower and zero the high word */
796 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
797 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
801 if (tree->inst_c1 == 32) {
802 /* just move the lower half to the upper and zero the lower word */
803 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
804 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
809 MonoInst *next = tree->next;
813 switch (next->opcode) {
818 /* Branchless version based on gcc code */
819 d1 = alloc_ireg (cfg);
820 d2 = alloc_ireg (cfg);
821 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
822 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
823 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
824 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
825 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
826 next->opcode = OP_NOP;
837 /* Convert into three comparisons + branches */
838 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
839 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
840 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
841 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
842 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
843 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
844 next->opcode = OP_NOP;
849 /* Branchless version based on gcc code */
850 d1 = alloc_ireg (cfg);
851 d2 = alloc_ireg (cfg);
852 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
853 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
854 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
856 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
857 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
858 next->opcode = OP_NOP;
865 MonoBasicBlock *set_to_0, *set_to_1;
867 NEW_BBLOCK (cfg, set_to_0);
868 NEW_BBLOCK (cfg, set_to_1);
870 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
871 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
872 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
873 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
874 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
875 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
876 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
877 MONO_START_BB (cfg, set_to_1);
878 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
879 MONO_START_BB (cfg, set_to_0);
880 next->opcode = OP_NOP;
884 g_assert_not_reached ();
889 /* Not yet used, since lcompare is decomposed before local cprop */
890 case OP_LCOMPARE_IMM: {
891 MonoInst *next = tree->next;
892 guint32 low_imm = tree->inst_ls_word;
893 guint32 high_imm = tree->inst_ms_word;
894 int low_reg = tree->sreg1 + 1;
895 int high_reg = tree->sreg1 + 2;
899 switch (next->opcode) {
904 /* Branchless version based on gcc code */
905 d1 = alloc_ireg (cfg);
906 d2 = alloc_ireg (cfg);
907 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
908 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
909 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
910 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
911 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
912 next->opcode = OP_NOP;
924 /* Convert into three comparisons + branches */
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
926 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
928 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
930 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
931 next->opcode = OP_NOP;
936 /* Branchless version based on gcc code */
937 d1 = alloc_ireg (cfg);
938 d2 = alloc_ireg (cfg);
939 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
940 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
941 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
943 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
944 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
945 next->opcode = OP_NOP;
952 MonoBasicBlock *set_to_0, *set_to_1;
954 NEW_BBLOCK (cfg, set_to_0);
955 NEW_BBLOCK (cfg, set_to_1);
957 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
958 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
959 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
960 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
961 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
962 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
963 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
964 MONO_START_BB (cfg, set_to_1);
965 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
966 MONO_START_BB (cfg, set_to_0);
967 next->opcode = OP_NOP;
971 g_assert_not_reached ();
980 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
983 /* Replace the original instruction with the new code sequence */
985 /* Ignore the new value of prev */
987 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
989 /* Process the newly added ops again since they can be long ops too */
995 first_bb->code = first_bb->last_ins = NULL;
996 first_bb->in_count = first_bb->out_count = 0;
1008 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1009 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1014 * mono_decompose_vtype_opts:
1016 * Decompose valuetype opcodes.
1019 mono_decompose_vtype_opts (MonoCompile *cfg)
1021 MonoBasicBlock *bb, *first_bb;
1024 * Using OP_V opcodes and decomposing them later have two main benefits:
1025 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1027 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1028 * enabling optimizations to work on vtypes too.
1029 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1030 * can be executed anytime. It should be executed as late as possible so vtype
1031 * opcodes can be optimized by the other passes.
1032 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1033 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1035 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1036 * when OP_VMOVE opcodes are decomposed.
1040 * Vregs have no associated type information, so we store the type of the vregs
1045 * Create a dummy bblock and emit code into it so we can use the normal
1046 * code generation macros.
1048 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1049 first_bb = cfg->cbb;
1051 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1053 MonoInst *prev = NULL;
1054 MonoInst *src_var, *dest_var, *src, *dest;
1058 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1060 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1066 for (ins = bb->code; ins; ins = ins->next) {
1067 switch (ins->opcode) {
1069 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1070 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1072 g_assert (ins->klass);
1075 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1078 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1081 if (src_var->backend.is_pinvoke)
1082 dest_var->backend.is_pinvoke = 1;
1084 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1085 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1087 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1091 g_assert (ins->klass);
1093 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1094 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1096 case OP_STOREV_MEMBASE: {
1097 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1100 g_assert (ins->klass);
1101 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1104 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1106 dreg = alloc_preg (cfg);
1107 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1108 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1111 case OP_LOADV_MEMBASE: {
1112 g_assert (ins->klass);
1114 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1117 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1119 dreg = alloc_preg (cfg);
1120 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1121 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1122 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1125 case OP_OUTARG_VT: {
1126 g_assert (ins->klass);
1128 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1130 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1131 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1133 mono_arch_emit_outarg_vt (cfg, ins, src);
1135 /* This might be decomposed into other vtype opcodes */
1139 case OP_OUTARG_VTRETADDR: {
1140 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1142 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1144 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1145 // FIXME: src_var->backend.is_pinvoke ?
1147 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1148 src->dreg = ins->dreg;
1153 case OP_VCALL_MEMBASE: {
1154 MonoCallInst *call = (MonoCallInst*)ins;
1157 if (call->vret_in_reg) {
1158 MonoCallInst *call2;
1160 /* Replace the vcall with an integer call */
1161 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1162 memcpy (call2, call, sizeof (MonoCallInst));
1163 switch (ins->opcode) {
1165 call2->inst.opcode = OP_CALL;
1168 call2->inst.opcode = OP_CALL_REG;
1170 case OP_VCALL_MEMBASE:
1171 call2->inst.opcode = OP_CALL_MEMBASE;
1174 call2->inst.dreg = alloc_preg (cfg);
1175 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1177 /* Compute the vtype location */
1178 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1180 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1181 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1183 /* Save the result */
1184 if (dest_var->backend.is_pinvoke)
1185 size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
1187 size = mono_type_size (dest_var->inst_vtype, NULL);
1190 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1193 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1196 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1199 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1202 /* This assumes the vtype is sizeof (gpointer) long */
1203 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1207 switch (ins->opcode) {
1209 ins->opcode = OP_VCALL2;
1212 ins->opcode = OP_VCALL2_REG;
1214 case OP_VCALL_MEMBASE:
1215 ins->opcode = OP_VCALL2_MEMBASE;
1226 g_assert (cfg->cbb == first_bb);
1228 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1229 /* Replace the original instruction with the new code sequence */
1231 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1232 first_bb->code = first_bb->last_ins = NULL;
1233 first_bb->in_count = first_bb->out_count = 0;
1234 cfg->cbb = first_bb;
1241 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1245 #endif /* DISABLE_JIT */