2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
13 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
14 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
15 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
16 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
19 * mono_decompose_opcode:
21 * Decompose complex opcodes into ones closer to opcodes supported by
22 * the given architecture.
25 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
27 /* FIXME: Instead of = NOP, don't emit the original ins at all */
29 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
30 mono_arch_decompose_opts (cfg, ins);
34 * The code below assumes that we are called immediately after emitting
35 * ins. This means we can emit code using the normal code generation
38 switch (ins->opcode) {
39 /* this doesn't make sense on ppc and other architectures */
40 #if !defined(MONO_ARCH_NO_IOV_CHECK)
42 ins->opcode = OP_IADDCC;
43 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
46 ins->opcode = OP_IADDCC;
47 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
50 ins->opcode = OP_ISUBCC;
51 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
54 ins->opcode = OP_ISUBCC;
55 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
58 case OP_ICONV_TO_OVF_I1:
59 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
60 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
61 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
62 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
63 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
66 case OP_ICONV_TO_OVF_I1_UN:
67 /* probe values between 0 to 127 */
68 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
69 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
70 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
73 case OP_ICONV_TO_OVF_U1:
74 case OP_ICONV_TO_OVF_U1_UN:
75 /* probe value to be within 0 to 255 */
76 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
77 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
78 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
81 case OP_ICONV_TO_OVF_I2:
82 /* Probe value to be within -32768 and 32767 */
83 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
84 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
85 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
86 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
87 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
90 case OP_ICONV_TO_OVF_I2_UN:
91 /* Convert uint value into short, value within 0 and 32767 */
92 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
93 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
94 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
97 case OP_ICONV_TO_OVF_U2:
98 case OP_ICONV_TO_OVF_U2_UN:
99 /* Probe value to be within 0 and 65535 */
100 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
101 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
102 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
103 ins->opcode = OP_NOP;
105 case OP_ICONV_TO_OVF_U4:
106 case OP_ICONV_TO_OVF_I4_UN:
107 #if SIZEOF_VOID_P == 4
108 case OP_ICONV_TO_OVF_U:
109 case OP_ICONV_TO_OVF_I_UN:
111 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
112 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
113 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
114 ins->opcode = OP_NOP;
118 case OP_ICONV_TO_OVF_I4:
119 #if SIZEOF_VOID_P == 4
120 case OP_ICONV_TO_OVF_I:
121 case OP_ICONV_TO_OVF_U_UN:
123 ins->opcode = OP_MOVE;
126 #if SIZEOF_VOID_P == 8
127 ins->opcode = OP_SEXT_I4;
129 ins->opcode = OP_MOVE;
133 #if SIZEOF_VOID_P == 8
134 ins->opcode = OP_ZEXT_I4;
136 ins->opcode = OP_MOVE;
141 ins->opcode = OP_FMOVE;
144 /* Long opcodes on 64 bit machines */
145 #if SIZEOF_VOID_P == 8
147 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
148 ins->opcode = OP_NOP;
154 ins->opcode = OP_MOVE;
157 ins->opcode = OP_SEXT_I4;
160 ins->opcode = OP_ZEXT_I4;
163 /* Clean out the upper word */
164 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
165 ins->opcode = OP_NOP;
169 /* ADC sets the condition code */
170 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
171 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
172 ins->opcode = OP_NOP;
173 g_assert_not_reached ();
176 /* ADC sets the condition code */
177 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
178 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
179 ins->opcode = OP_NOP;
180 g_assert_not_reached ();
183 /* SBB sets the condition code */
184 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
185 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
186 ins->opcode = OP_NOP;
187 g_assert_not_reached ();
190 /* SBB sets the condition code */
191 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
192 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
193 ins->opcode = OP_NOP;
194 g_assert_not_reached ();
198 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
199 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
200 ins->opcode = OP_NOP;
203 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
204 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
205 ins->opcode = OP_NOP;
208 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
209 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
210 ins->opcode = OP_NOP;
213 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
214 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
215 ins->opcode = OP_NOP;
219 case OP_ICONV_TO_OVF_I8:
220 case OP_ICONV_TO_OVF_I:
221 ins->opcode = OP_SEXT_I4;
223 case OP_ICONV_TO_OVF_U8:
224 case OP_ICONV_TO_OVF_U:
225 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
226 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
227 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
228 ins->opcode = OP_NOP;
230 case OP_ICONV_TO_OVF_I8_UN:
231 case OP_ICONV_TO_OVF_U8_UN:
232 case OP_ICONV_TO_OVF_I_UN:
233 case OP_ICONV_TO_OVF_U_UN:
234 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
235 /* Clean out the upper word */
236 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
237 ins->opcode = OP_NOP;
239 case OP_LCONV_TO_OVF_I1:
240 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
241 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
242 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
243 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
244 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
245 ins->opcode = OP_NOP;
247 case OP_LCONV_TO_OVF_I1_UN:
248 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
249 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
250 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
251 ins->opcode = OP_NOP;
253 case OP_LCONV_TO_OVF_U1:
254 /* probe value to be within 0 to 255 */
255 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
256 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
257 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
258 ins->opcode = OP_NOP;
260 case OP_LCONV_TO_OVF_U1_UN:
261 /* probe value to be within 0 to 255 */
262 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
263 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
264 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
265 ins->opcode = OP_NOP;
267 case OP_LCONV_TO_OVF_I2:
268 /* Probe value to be within -32768 and 32767 */
269 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
270 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
271 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
272 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
273 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
274 ins->opcode = OP_NOP;
276 case OP_LCONV_TO_OVF_I2_UN:
277 /* Probe value to be within 0 and 32767 */
278 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
279 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
280 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
281 ins->opcode = OP_NOP;
283 case OP_LCONV_TO_OVF_U2:
284 /* Probe value to be within 0 and 65535 */
285 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
286 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
287 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
288 ins->opcode = OP_NOP;
290 case OP_LCONV_TO_OVF_U2_UN:
291 /* Probe value to be within 0 and 65535 */
292 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
293 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
294 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
295 ins->opcode = OP_NOP;
297 case OP_LCONV_TO_OVF_I4:
298 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
299 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
300 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
301 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
302 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
303 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
304 ins->opcode = OP_NOP;
306 case OP_LCONV_TO_OVF_I4_UN:
307 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
308 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
309 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
310 ins->opcode = OP_NOP;
312 case OP_LCONV_TO_OVF_U4:
313 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
314 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
315 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
316 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
317 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
318 ins->opcode = OP_NOP;
320 case OP_LCONV_TO_OVF_U4_UN:
321 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
322 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
323 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
324 ins->opcode = OP_NOP;
326 case OP_LCONV_TO_OVF_I:
327 case OP_LCONV_TO_OVF_U_UN:
328 case OP_LCONV_TO_OVF_U8_UN:
329 ins->opcode = OP_MOVE;
331 case OP_LCONV_TO_OVF_I_UN:
332 case OP_LCONV_TO_OVF_I8_UN:
333 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
334 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
335 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
336 ins->opcode = OP_NOP;
338 case OP_LCONV_TO_OVF_U8:
339 case OP_LCONV_TO_OVF_U:
340 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
341 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
342 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
343 ins->opcode = OP_NOP;
348 MonoJitICallInfo *info;
350 info = mono_find_jit_opcode_emulation (ins->opcode);
355 /* Create dummy MonoInst's for the arguments */
356 g_assert (!info->sig->hasthis);
357 g_assert (info->sig->param_count <= 2);
359 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
360 if (info->sig->param_count > 0) {
361 MONO_INST_NEW (cfg, args [0], OP_ARG);
362 args [0]->dreg = ins->sreg1;
364 if (info->sig->param_count > 1) {
365 MONO_INST_NEW (cfg, args [1], OP_ARG);
366 args [1]->dreg = ins->sreg2;
369 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
370 call->dreg = ins->dreg;
372 ins->opcode = OP_NOP;
379 #if SIZEOF_VOID_P == 4
380 static int lbr_decomp [][2] = {
382 {OP_IBGT, OP_IBGE_UN}, /* BGE */
383 {OP_IBGT, OP_IBGT_UN}, /* BGT */
384 {OP_IBLT, OP_IBLE_UN}, /* BLE */
385 {OP_IBLT, OP_IBLT_UN}, /* BLT */
387 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
388 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
389 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
390 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
393 static int lcset_decomp [][2] = {
395 {OP_IBLT, OP_IBLE_UN}, /* CGT */
396 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
397 {OP_IBGT, OP_IBGE_UN}, /* CLT */
398 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
403 * mono_decompose_long_opts:
405 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
408 mono_decompose_long_opts (MonoCompile *cfg)
410 #if SIZEOF_VOID_P == 4
411 MonoBasicBlock *bb, *first_bb;
414 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
415 * needs to be able to handle long vregs.
418 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
421 * Create a dummy bblock and emit code into it so we can use the normal
422 * code generation macros.
424 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
427 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
428 MonoInst *tree = bb->code;
429 MonoInst *prev = NULL;
432 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
436 cfg->cbb->code = cfg->cbb->last_ins = NULL;
440 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
441 mono_arch_decompose_long_opts (cfg, tree);
444 switch (tree->opcode) {
446 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
447 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
452 case OP_LCONV_TO_OVF_U8_UN:
453 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
454 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
456 case OP_STOREI8_MEMBASE_REG:
457 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
458 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
460 case OP_LOADI8_MEMBASE:
461 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
462 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
465 case OP_ICONV_TO_I8: {
466 guint32 tmpreg = alloc_ireg (cfg);
470 * tmp = low > -1 ? 1: 0;
471 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
473 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
474 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
475 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
476 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
480 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
481 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
483 case OP_ICONV_TO_OVF_I8:
484 /* a signed 32 bit num always fits in a signed 64 bit one */
485 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
486 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
488 case OP_ICONV_TO_OVF_U8:
489 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
490 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
491 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
492 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
494 case OP_ICONV_TO_OVF_I8_UN:
495 case OP_ICONV_TO_OVF_U8_UN:
496 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
497 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
498 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
501 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
504 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
507 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
510 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
516 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
519 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
522 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
524 case OP_LCONV_TO_R_UN:
525 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
527 case OP_LCONV_TO_OVF_I1: {
528 MonoBasicBlock *is_negative, *end_label;
530 NEW_BBLOCK (cfg, is_negative);
531 NEW_BBLOCK (cfg, end_label);
533 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
534 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
535 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
536 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
538 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
539 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
542 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
543 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
544 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
547 MONO_START_BB (cfg, is_negative);
548 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
549 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
551 MONO_START_BB (cfg, end_label);
553 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
556 case OP_LCONV_TO_OVF_I1_UN:
557 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
558 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
560 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
561 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
562 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
563 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
564 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
566 case OP_LCONV_TO_OVF_U1:
567 case OP_LCONV_TO_OVF_U1_UN:
568 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
569 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
571 /* probe value to be within 0 to 255 */
572 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
573 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
574 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
576 case OP_LCONV_TO_OVF_I2: {
577 MonoBasicBlock *is_negative, *end_label;
579 NEW_BBLOCK (cfg, is_negative);
580 NEW_BBLOCK (cfg, end_label);
582 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
583 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
584 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
585 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
587 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
588 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
591 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
592 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
593 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
596 MONO_START_BB (cfg, is_negative);
597 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
598 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
599 MONO_START_BB (cfg, end_label);
601 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
604 case OP_LCONV_TO_OVF_I2_UN:
605 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
606 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
608 /* Probe value to be within -32768 and 32767 */
609 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
610 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
611 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
612 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
613 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
615 case OP_LCONV_TO_OVF_U2:
616 case OP_LCONV_TO_OVF_U2_UN:
617 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
618 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
620 /* Probe value to be within 0 and 65535 */
621 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
622 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
623 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
625 case OP_LCONV_TO_OVF_I4:
626 case OP_LCONV_TO_OVF_I:
627 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
629 case OP_LCONV_TO_OVF_U4:
630 case OP_LCONV_TO_OVF_U:
631 case OP_LCONV_TO_OVF_U4_UN:
632 case OP_LCONV_TO_OVF_U_UN:
633 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
634 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
635 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
637 case OP_LCONV_TO_OVF_I_UN:
638 case OP_LCONV_TO_OVF_I4_UN:
639 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
640 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
641 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
642 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
643 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
645 case OP_LCONV_TO_OVF_U8:
646 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
647 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
649 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
650 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
652 case OP_LCONV_TO_OVF_I8_UN:
653 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
654 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
656 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
657 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
661 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
662 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
665 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
666 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
671 /* ADC sets the condition code */
672 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
673 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
676 /* ADC sets the condition code */
677 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
678 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
681 /* SBB sets the condition code */
682 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
683 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
686 /* SBB sets the condition code */
687 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
688 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
692 /* ADC sets the condition code */
693 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
694 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
695 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
698 /* ADC sets the condition code */
699 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
700 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
701 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
704 /* SBB sets the condition code */
705 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
706 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
707 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
710 /* SBB sets the condition code */
711 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
712 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
713 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
717 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
718 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
721 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
722 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
725 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
726 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
729 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
730 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
734 * FIXME: The original version in inssel-long32.brg does not work
735 * on x86, and the x86 version might not work on other archs ?
737 /* FIXME: Move these to mono_arch_decompose_long_opts () */
738 #if defined(__i386__)
739 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
740 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
741 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
742 #elif defined(__sparc__)
743 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
744 MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
745 #elif defined(__arm__)
746 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
747 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
748 #elif defined(__ppc__)
749 /* This is the old version from inssel-long32.brg */
750 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
751 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
752 /* ADC sets the condition codes */
753 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 1, tree->dreg + 1, 1);
754 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->dreg + 2, 0);
761 /* FIXME: Add OP_BIGMUL optimization */
765 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
766 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
769 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
770 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
773 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
774 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
777 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
778 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
785 if (tree->inst_c1 == 32) {
787 /* The original code had this comment: */
788 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
789 * later apply the speedup to the left shift as well
792 /* FIXME: Move this to the strength reduction pass */
793 /* just move the upper half to the lower and zero the high word */
794 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
795 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
799 if (tree->inst_c1 == 32) {
800 /* just move the lower half to the upper and zero the lower word */
801 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
802 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
807 MonoInst *next = tree->next;
811 switch (next->opcode) {
816 /* Branchless version based on gcc code */
817 d1 = alloc_ireg (cfg);
818 d2 = alloc_ireg (cfg);
819 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
820 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
821 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_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
824 next->opcode = OP_NOP;
835 /* Convert into three comparisons + branches */
836 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
837 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
838 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
839 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
840 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
841 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
842 next->opcode = OP_NOP;
847 /* Branchless version based on gcc code */
848 d1 = alloc_ireg (cfg);
849 d2 = alloc_ireg (cfg);
850 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
851 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
852 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
854 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
855 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
856 next->opcode = OP_NOP;
863 MonoBasicBlock *set_to_0, *set_to_1;
865 NEW_BBLOCK (cfg, set_to_0);
866 NEW_BBLOCK (cfg, set_to_1);
868 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
869 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
870 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
871 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
872 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
873 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
874 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
875 MONO_START_BB (cfg, set_to_1);
876 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
877 MONO_START_BB (cfg, set_to_0);
878 next->opcode = OP_NOP;
882 g_assert_not_reached ();
887 /* Not yet used, since lcompare is decomposed before local cprop */
888 case OP_LCOMPARE_IMM: {
889 MonoInst *next = tree->next;
890 guint32 low_imm = tree->inst_ls_word;
891 guint32 high_imm = tree->inst_ms_word;
892 int low_reg = tree->sreg1 + 1;
893 int high_reg = tree->sreg1 + 2;
897 switch (next->opcode) {
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);
908 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
909 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
910 next->opcode = OP_NOP;
922 /* Convert into three comparisons + branches */
923 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
924 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
926 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
928 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
929 next->opcode = OP_NOP;
934 /* Branchless version based on gcc code */
935 d1 = alloc_ireg (cfg);
936 d2 = alloc_ireg (cfg);
937 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
938 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
939 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
942 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
943 next->opcode = OP_NOP;
950 MonoBasicBlock *set_to_0, *set_to_1;
952 NEW_BBLOCK (cfg, set_to_0);
953 NEW_BBLOCK (cfg, set_to_1);
955 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
956 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
957 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
958 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
959 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
960 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
961 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
962 MONO_START_BB (cfg, set_to_1);
963 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
964 MONO_START_BB (cfg, set_to_0);
965 next->opcode = OP_NOP;
969 g_assert_not_reached ();
978 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
981 /* Replace the original instruction with the new code sequence */
983 /* Ignore the new value of prev */
985 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
987 /* Process the newly added ops again since they can be long ops too */
993 first_bb->code = first_bb->last_ins = NULL;
994 first_bb->in_count = first_bb->out_count = 0;
1006 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1007 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1012 * mono_decompose_vtype_opts:
1014 * Decompose valuetype opcodes.
1017 mono_decompose_vtype_opts (MonoCompile *cfg)
1019 MonoBasicBlock *bb, *first_bb;
1022 * Using OP_V opcodes and decomposing them later have two main benefits:
1023 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1025 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1026 * enabling optimizations to work on vtypes too.
1027 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1028 * can be executed anytime. It should be executed as late as possible so vtype
1029 * opcodes can be optimized by the other passes.
1030 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1031 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1033 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1034 * when OP_VMOVE opcodes are decomposed.
1038 * Vregs have no associated type information, so we store the type of the vregs
1043 * Create a dummy bblock and emit code into it so we can use the normal
1044 * code generation macros.
1046 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1047 first_bb = cfg->cbb;
1049 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1051 MonoInst *prev = NULL;
1052 MonoInst *src_var, *dest_var, *src, *dest;
1056 if (cfg->verbose_level > 1) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1058 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1064 for (ins = bb->code; ins; ins = ins->next) {
1065 switch (ins->opcode) {
1067 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1068 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1070 g_assert (ins->klass);
1073 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1076 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1079 if (src_var->backend.is_pinvoke)
1080 dest_var->backend.is_pinvoke = 1;
1082 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1083 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1085 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1089 g_assert (ins->klass);
1091 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1092 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1094 case OP_STOREV_MEMBASE: {
1095 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1098 g_assert (ins->klass);
1099 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1102 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1104 dreg = alloc_preg (cfg);
1105 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1106 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1109 case OP_LOADV_MEMBASE: {
1110 g_assert (ins->klass);
1112 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1115 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1117 dreg = alloc_preg (cfg);
1118 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1119 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1120 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1123 case OP_OUTARG_VT: {
1124 g_assert (ins->klass);
1126 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1128 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1129 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1131 mono_arch_emit_outarg_vt (cfg, ins, src);
1133 /* This might be decomposed into other vtype opcodes */
1137 case OP_OUTARG_VTRETADDR: {
1138 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1140 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1142 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1143 // FIXME: src_var->backend.is_pinvoke ?
1145 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1146 src->dreg = ins->dreg;
1151 case OP_VCALL_MEMBASE: {
1152 MonoCallInst *call = (MonoCallInst*)ins;
1155 if (call->vret_in_reg) {
1156 MonoCallInst *call2;
1158 /* Replace the vcall with an integer call */
1159 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1160 memcpy (call2, call, sizeof (MonoCallInst));
1161 switch (ins->opcode) {
1163 call2->inst.opcode = OP_CALL;
1166 call2->inst.opcode = OP_CALL_REG;
1168 case OP_VCALL_MEMBASE:
1169 call2->inst.opcode = OP_CALL_MEMBASE;
1172 call2->inst.dreg = alloc_preg (cfg);
1173 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1175 /* Compute the vtype location */
1176 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1178 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1179 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1181 /* Save the result */
1182 if (dest_var->backend.is_pinvoke)
1183 size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
1185 size = mono_type_size (dest_var->inst_vtype, NULL);
1188 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1191 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1194 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1197 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1200 /* This assumes the vtype is sizeof (gpointer) long */
1201 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1205 switch (ins->opcode) {
1207 ins->opcode = OP_VCALL2;
1210 ins->opcode = OP_VCALL2_REG;
1212 case OP_VCALL_MEMBASE:
1213 ins->opcode = OP_VCALL2_MEMBASE;
1224 g_assert (cfg->cbb == first_bb);
1226 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1227 /* Replace the original instruction with the new code sequence */
1229 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1230 first_bb->code = first_bb->last_ins = NULL;
1231 first_bb->in_count = first_bb->out_count = 0;
1232 cfg->cbb = first_bb;
1239 if (cfg->verbose_level > 1) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");