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(__mono_ppc__) && !defined(__mono_ppc64__)
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;
209 #ifndef __mono_ppc64__
211 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
212 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
213 ins->opcode = OP_NOP;
216 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
217 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
218 ins->opcode = OP_NOP;
223 case OP_ICONV_TO_OVF_I8:
224 case OP_ICONV_TO_OVF_I:
225 ins->opcode = OP_SEXT_I4;
227 case OP_ICONV_TO_OVF_U8:
228 case OP_ICONV_TO_OVF_U:
229 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
230 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
231 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
232 ins->opcode = OP_NOP;
234 case OP_ICONV_TO_OVF_I8_UN:
235 case OP_ICONV_TO_OVF_U8_UN:
236 case OP_ICONV_TO_OVF_I_UN:
237 case OP_ICONV_TO_OVF_U_UN:
238 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
239 /* Clean out the upper word */
240 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
241 ins->opcode = OP_NOP;
243 case OP_LCONV_TO_OVF_I1:
244 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
245 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
246 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
247 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
248 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
249 ins->opcode = OP_NOP;
251 case OP_LCONV_TO_OVF_I1_UN:
252 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
253 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
254 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
255 ins->opcode = OP_NOP;
257 case OP_LCONV_TO_OVF_U1:
258 /* probe value to be within 0 to 255 */
259 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
260 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
261 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
262 ins->opcode = OP_NOP;
264 case OP_LCONV_TO_OVF_U1_UN:
265 /* probe value to be within 0 to 255 */
266 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
267 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
268 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
269 ins->opcode = OP_NOP;
271 case OP_LCONV_TO_OVF_I2:
272 /* Probe value to be within -32768 and 32767 */
273 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
274 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
275 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
276 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
277 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
278 ins->opcode = OP_NOP;
280 case OP_LCONV_TO_OVF_I2_UN:
281 /* Probe value to be within 0 and 32767 */
282 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
283 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
284 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
285 ins->opcode = OP_NOP;
287 case OP_LCONV_TO_OVF_U2:
288 /* Probe value to be within 0 and 65535 */
289 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
290 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
291 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
292 ins->opcode = OP_NOP;
294 case OP_LCONV_TO_OVF_U2_UN:
295 /* Probe value to be within 0 and 65535 */
296 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
297 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
298 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
299 ins->opcode = OP_NOP;
301 case OP_LCONV_TO_OVF_I4:
302 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
303 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
304 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
305 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
306 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
307 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
308 ins->opcode = OP_NOP;
310 case OP_LCONV_TO_OVF_I4_UN:
311 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
312 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
313 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
314 ins->opcode = OP_NOP;
316 case OP_LCONV_TO_OVF_U4:
317 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
318 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
319 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
320 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
321 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
322 ins->opcode = OP_NOP;
324 case OP_LCONV_TO_OVF_U4_UN:
325 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
326 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
327 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
328 ins->opcode = OP_NOP;
330 case OP_LCONV_TO_OVF_I:
331 case OP_LCONV_TO_OVF_U_UN:
332 case OP_LCONV_TO_OVF_U8_UN:
333 ins->opcode = OP_MOVE;
335 case OP_LCONV_TO_OVF_I_UN:
336 case OP_LCONV_TO_OVF_I8_UN:
337 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
338 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
339 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
340 ins->opcode = OP_NOP;
342 case OP_LCONV_TO_OVF_U8:
343 case OP_LCONV_TO_OVF_U:
344 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
345 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
346 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
347 ins->opcode = OP_NOP;
352 MonoJitICallInfo *info;
354 info = mono_find_jit_opcode_emulation (ins->opcode);
359 /* Create dummy MonoInst's for the arguments */
360 g_assert (!info->sig->hasthis);
361 g_assert (info->sig->param_count <= 2);
363 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
364 if (info->sig->param_count > 0) {
365 MONO_INST_NEW (cfg, args [0], OP_ARG);
366 args [0]->dreg = ins->sreg1;
368 if (info->sig->param_count > 1) {
369 MONO_INST_NEW (cfg, args [1], OP_ARG);
370 args [1]->dreg = ins->sreg2;
373 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
374 call->dreg = ins->dreg;
376 ins->opcode = OP_NOP;
383 #if SIZEOF_VOID_P == 4
384 static int lbr_decomp [][2] = {
386 {OP_IBGT, OP_IBGE_UN}, /* BGE */
387 {OP_IBGT, OP_IBGT_UN}, /* BGT */
388 {OP_IBLT, OP_IBLE_UN}, /* BLE */
389 {OP_IBLT, OP_IBLT_UN}, /* BLT */
391 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
392 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
393 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
394 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
397 static int lcset_decomp [][2] = {
399 {OP_IBLT, OP_IBLE_UN}, /* CGT */
400 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
401 {OP_IBGT, OP_IBGE_UN}, /* CLT */
402 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
407 * mono_decompose_long_opts:
409 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
412 mono_decompose_long_opts (MonoCompile *cfg)
414 #if SIZEOF_VOID_P == 4
415 MonoBasicBlock *bb, *first_bb;
418 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
419 * needs to be able to handle long vregs.
422 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
425 * Create a dummy bblock and emit code into it so we can use the normal
426 * code generation macros.
428 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
431 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
432 MonoInst *tree = bb->code;
433 MonoInst *prev = NULL;
436 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
440 cfg->cbb->code = cfg->cbb->last_ins = NULL;
444 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
445 mono_arch_decompose_long_opts (cfg, tree);
448 switch (tree->opcode) {
450 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
451 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
456 case OP_LCONV_TO_OVF_U8_UN:
457 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
458 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
460 case OP_STOREI8_MEMBASE_REG:
461 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
462 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
464 case OP_LOADI8_MEMBASE:
465 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
466 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
469 case OP_ICONV_TO_I8: {
470 guint32 tmpreg = alloc_ireg (cfg);
474 * tmp = low > -1 ? 1: 0;
475 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
477 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
478 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
479 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
480 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
484 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
485 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
487 case OP_ICONV_TO_OVF_I8:
488 /* a signed 32 bit num always fits in a signed 64 bit one */
489 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
490 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
492 case OP_ICONV_TO_OVF_U8:
493 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
494 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
495 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
496 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
498 case OP_ICONV_TO_OVF_I8_UN:
499 case OP_ICONV_TO_OVF_U8_UN:
500 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
501 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
502 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
505 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
508 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
511 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
514 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
520 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
523 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
526 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
528 case OP_LCONV_TO_R_UN:
529 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
531 case OP_LCONV_TO_OVF_I1: {
532 MonoBasicBlock *is_negative, *end_label;
534 NEW_BBLOCK (cfg, is_negative);
535 NEW_BBLOCK (cfg, end_label);
537 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
538 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
539 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
540 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
542 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
543 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
546 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
547 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
548 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
551 MONO_START_BB (cfg, is_negative);
552 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
553 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
555 MONO_START_BB (cfg, end_label);
557 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
560 case OP_LCONV_TO_OVF_I1_UN:
561 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
562 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
564 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
565 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
566 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
567 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
568 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
570 case OP_LCONV_TO_OVF_U1:
571 case OP_LCONV_TO_OVF_U1_UN:
572 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
573 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
575 /* probe value to be within 0 to 255 */
576 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
577 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
578 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
580 case OP_LCONV_TO_OVF_I2: {
581 MonoBasicBlock *is_negative, *end_label;
583 NEW_BBLOCK (cfg, is_negative);
584 NEW_BBLOCK (cfg, end_label);
586 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
587 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
588 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
589 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
591 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
592 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
595 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
596 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
597 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
600 MONO_START_BB (cfg, is_negative);
601 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
602 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
603 MONO_START_BB (cfg, end_label);
605 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
608 case OP_LCONV_TO_OVF_I2_UN:
609 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
610 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
612 /* Probe value to be within -32768 and 32767 */
613 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
614 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
615 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
616 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
617 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
619 case OP_LCONV_TO_OVF_U2:
620 case OP_LCONV_TO_OVF_U2_UN:
621 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
622 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
624 /* Probe value to be within 0 and 65535 */
625 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
626 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
627 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
629 case OP_LCONV_TO_OVF_I4:
630 case OP_LCONV_TO_OVF_I:
631 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
633 case OP_LCONV_TO_OVF_U4:
634 case OP_LCONV_TO_OVF_U:
635 case OP_LCONV_TO_OVF_U4_UN:
636 case OP_LCONV_TO_OVF_U_UN:
637 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
638 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
639 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
641 case OP_LCONV_TO_OVF_I_UN:
642 case OP_LCONV_TO_OVF_I4_UN:
643 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
644 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
645 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
646 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
647 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
649 case OP_LCONV_TO_OVF_U8:
650 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
651 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
653 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
654 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
656 case OP_LCONV_TO_OVF_I8_UN:
657 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
658 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
660 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
661 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
665 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
666 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
669 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
670 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
673 #if defined(__ppc__) || defined(__powerpc__)
675 /* ADC sets the condition code */
676 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
677 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
680 /* ADC sets the condition code */
681 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
682 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
685 /* SBB sets the condition code */
686 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
687 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
690 /* SBB sets the condition code */
691 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
692 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
696 /* ADC sets the condition code */
697 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
698 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
699 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
702 /* ADC sets the condition code */
703 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
704 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
705 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
708 /* SBB sets the condition code */
709 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
710 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
711 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
714 /* SBB sets the condition code */
715 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
716 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
717 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
721 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
722 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
725 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
726 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
729 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
730 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
733 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
734 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
738 * FIXME: The original version in inssel-long32.brg does not work
739 * on x86, and the x86 version might not work on other archs ?
741 /* FIXME: Move these to mono_arch_decompose_long_opts () */
742 #if defined(__i386__)
743 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
744 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
745 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
746 #elif defined(__sparc__)
747 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
748 MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
749 #elif defined(__arm__)
750 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
751 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
752 #elif defined(__ppc__) || defined(__powerpc__)
753 /* This is the old version from inssel-long32.brg */
754 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
755 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
756 /* ADC sets the condition codes */
757 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 1, tree->dreg + 1, 1);
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->dreg + 2, 0);
765 /* FIXME: Add OP_BIGMUL optimization */
769 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
770 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
773 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
774 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
777 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
778 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
785 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
786 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
789 if (tree->inst_c1 == 32) {
791 /* The original code had this comment: */
792 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
793 * later apply the speedup to the left shift as well
796 /* FIXME: Move this to the strength reduction pass */
797 /* just move the upper half to the lower and zero the high word */
798 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
799 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
803 if (tree->inst_c1 == 32) {
804 /* just move the lower half to the upper and zero the lower word */
805 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
806 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
811 MonoInst *next = tree->next;
815 switch (next->opcode) {
820 /* Branchless version based on gcc code */
821 d1 = alloc_ireg (cfg);
822 d2 = alloc_ireg (cfg);
823 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
824 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
825 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
826 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
827 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
828 next->opcode = OP_NOP;
839 /* Convert into three comparisons + branches */
840 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
841 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
842 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
843 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
844 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
845 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
846 next->opcode = OP_NOP;
851 /* Branchless version based on gcc code */
852 d1 = alloc_ireg (cfg);
853 d2 = alloc_ireg (cfg);
854 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
855 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
856 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
858 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
859 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
860 next->opcode = OP_NOP;
867 MonoBasicBlock *set_to_0, *set_to_1;
869 NEW_BBLOCK (cfg, set_to_0);
870 NEW_BBLOCK (cfg, set_to_1);
872 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
873 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
874 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
875 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
876 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
877 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
878 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
879 MONO_START_BB (cfg, set_to_1);
880 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
881 MONO_START_BB (cfg, set_to_0);
882 next->opcode = OP_NOP;
886 g_assert_not_reached ();
891 /* Not yet used, since lcompare is decomposed before local cprop */
892 case OP_LCOMPARE_IMM: {
893 MonoInst *next = tree->next;
894 guint32 low_imm = tree->inst_ls_word;
895 guint32 high_imm = tree->inst_ms_word;
896 int low_reg = tree->sreg1 + 1;
897 int high_reg = tree->sreg1 + 2;
901 switch (next->opcode) {
906 /* Branchless version based on gcc code */
907 d1 = alloc_ireg (cfg);
908 d2 = alloc_ireg (cfg);
909 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
910 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
911 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
912 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
913 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
914 next->opcode = OP_NOP;
926 /* Convert into three comparisons + branches */
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
928 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
930 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
932 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
933 next->opcode = OP_NOP;
938 /* Branchless version based on gcc code */
939 d1 = alloc_ireg (cfg);
940 d2 = alloc_ireg (cfg);
941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
942 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
943 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
945 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
946 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
947 next->opcode = OP_NOP;
954 MonoBasicBlock *set_to_0, *set_to_1;
956 NEW_BBLOCK (cfg, set_to_0);
957 NEW_BBLOCK (cfg, set_to_1);
959 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
960 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
961 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
962 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
963 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
964 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
965 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
966 MONO_START_BB (cfg, set_to_1);
967 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
968 MONO_START_BB (cfg, set_to_0);
969 next->opcode = OP_NOP;
973 g_assert_not_reached ();
982 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
985 /* Replace the original instruction with the new code sequence */
987 /* Ignore the new value of prev */
989 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
991 /* Process the newly added ops again since they can be long ops too */
997 first_bb->code = first_bb->last_ins = NULL;
998 first_bb->in_count = first_bb->out_count = 0;
1010 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1011 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1016 * mono_decompose_vtype_opts:
1018 * Decompose valuetype opcodes.
1021 mono_decompose_vtype_opts (MonoCompile *cfg)
1023 MonoBasicBlock *bb, *first_bb;
1026 * Using OP_V opcodes and decomposing them later have two main benefits:
1027 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1029 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1030 * enabling optimizations to work on vtypes too.
1031 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1032 * can be executed anytime. It should be executed as late as possible so vtype
1033 * opcodes can be optimized by the other passes.
1034 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1035 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1037 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1038 * when OP_VMOVE opcodes are decomposed.
1042 * Vregs have no associated type information, so we store the type of the vregs
1047 * Create a dummy bblock and emit code into it so we can use the normal
1048 * code generation macros.
1050 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1051 first_bb = cfg->cbb;
1053 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1055 MonoInst *prev = NULL;
1056 MonoInst *src_var, *dest_var, *src, *dest;
1060 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1062 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1068 for (ins = bb->code; ins; ins = ins->next) {
1069 switch (ins->opcode) {
1071 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1072 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1074 g_assert (ins->klass);
1077 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1080 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1083 if (src_var->backend.is_pinvoke)
1084 dest_var->backend.is_pinvoke = 1;
1086 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1087 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1089 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1093 g_assert (ins->klass);
1095 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1096 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1098 case OP_STOREV_MEMBASE: {
1099 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1102 g_assert (ins->klass);
1103 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1106 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1108 dreg = alloc_preg (cfg);
1109 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1110 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1113 case OP_LOADV_MEMBASE: {
1114 g_assert (ins->klass);
1116 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1119 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1121 dreg = alloc_preg (cfg);
1122 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1123 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1124 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1127 case OP_OUTARG_VT: {
1128 g_assert (ins->klass);
1130 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1132 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1133 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1135 mono_arch_emit_outarg_vt (cfg, ins, src);
1137 /* This might be decomposed into other vtype opcodes */
1141 case OP_OUTARG_VTRETADDR: {
1142 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1144 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1146 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1147 // FIXME: src_var->backend.is_pinvoke ?
1149 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1150 src->dreg = ins->dreg;
1155 case OP_VCALL_MEMBASE: {
1156 MonoCallInst *call = (MonoCallInst*)ins;
1159 if (call->vret_in_reg) {
1160 MonoCallInst *call2;
1162 /* Replace the vcall with an integer call */
1163 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1164 memcpy (call2, call, sizeof (MonoCallInst));
1165 switch (ins->opcode) {
1167 call2->inst.opcode = OP_CALL;
1170 call2->inst.opcode = OP_CALL_REG;
1172 case OP_VCALL_MEMBASE:
1173 call2->inst.opcode = OP_CALL_MEMBASE;
1176 call2->inst.dreg = alloc_preg (cfg);
1177 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1179 /* Compute the vtype location */
1180 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1182 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1183 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1185 /* Save the result */
1186 if (dest_var->backend.is_pinvoke)
1187 size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
1189 size = mono_type_size (dest_var->inst_vtype, NULL);
1192 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1195 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1198 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1201 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1204 /* This assumes the vtype is sizeof (gpointer) long */
1205 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1209 switch (ins->opcode) {
1211 ins->opcode = OP_VCALL2;
1214 ins->opcode = OP_VCALL2_REG;
1216 case OP_VCALL_MEMBASE:
1217 ins->opcode = OP_VCALL2_MEMBASE;
1228 g_assert (cfg->cbb == first_bb);
1230 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1231 /* Replace the original instruction with the new code sequence */
1233 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1234 first_bb->code = first_bb->last_ins = NULL;
1235 first_bb->in_count = first_bb->out_count = 0;
1236 cfg->cbb = first_bb;
1243 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1247 #endif /* DISABLE_JIT */