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_REGISTER == 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_REGISTER == 4
122 case OP_ICONV_TO_OVF_I:
123 case OP_ICONV_TO_OVF_U_UN:
125 ins->opcode = OP_MOVE;
128 #if SIZEOF_REGISTER == 8
129 ins->opcode = OP_SEXT_I4;
131 ins->opcode = OP_MOVE;
135 #if SIZEOF_REGISTER == 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_REGISTER == 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 <= MONO_MAX_SRC_REGS);
363 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
364 if (info->sig->param_count > 0) {
365 int sregs [MONO_MAX_SRC_REGS];
367 num_sregs = mono_inst_get_src_registers (ins, sregs);
368 g_assert (num_sregs == info->sig->param_count);
369 for (i = 0; i < num_sregs; ++i) {
370 MONO_INST_NEW (cfg, args [i], OP_ARG);
371 args [i]->dreg = sregs [i];
375 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
376 call->dreg = ins->dreg;
378 ins->opcode = OP_NOP;
385 #if SIZEOF_REGISTER == 4
386 static int lbr_decomp [][2] = {
388 {OP_IBGT, OP_IBGE_UN}, /* BGE */
389 {OP_IBGT, OP_IBGT_UN}, /* BGT */
390 {OP_IBLT, OP_IBLE_UN}, /* BLE */
391 {OP_IBLT, OP_IBLT_UN}, /* BLT */
393 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
394 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
395 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
396 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
399 static int lcset_decomp [][2] = {
401 {OP_IBLT, OP_IBLE_UN}, /* CGT */
402 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
403 {OP_IBGT, OP_IBGE_UN}, /* CLT */
404 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
409 * mono_decompose_long_opts:
411 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
414 mono_decompose_long_opts (MonoCompile *cfg)
416 #if SIZEOF_REGISTER == 4
417 MonoBasicBlock *bb, *first_bb;
420 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
421 * needs to be able to handle long vregs.
424 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
427 * Create a dummy bblock and emit code into it so we can use the normal
428 * code generation macros.
430 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
433 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
434 MonoInst *tree = bb->code;
435 MonoInst *prev = NULL;
438 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
442 cfg->cbb->code = cfg->cbb->last_ins = NULL;
446 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
447 mono_arch_decompose_long_opts (cfg, tree);
450 switch (tree->opcode) {
452 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
453 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
458 case OP_LCONV_TO_OVF_U8_UN:
459 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
460 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
462 case OP_STOREI8_MEMBASE_REG:
463 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
464 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
466 case OP_LOADI8_MEMBASE:
467 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
468 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
471 case OP_ICONV_TO_I8: {
472 guint32 tmpreg = alloc_ireg (cfg);
476 * tmp = low > -1 ? 1: 0;
477 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
479 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
480 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
481 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
482 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
486 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
487 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
489 case OP_ICONV_TO_OVF_I8:
490 /* a signed 32 bit num always fits in a signed 64 bit one */
491 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
492 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
494 case OP_ICONV_TO_OVF_U8:
495 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
496 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
497 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
498 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
500 case OP_ICONV_TO_OVF_I8_UN:
501 case OP_ICONV_TO_OVF_U8_UN:
502 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
503 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
504 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
507 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
510 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
513 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
516 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
522 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
525 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
528 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
530 case OP_LCONV_TO_R_UN:
531 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
533 case OP_LCONV_TO_OVF_I1: {
534 MonoBasicBlock *is_negative, *end_label;
536 NEW_BBLOCK (cfg, is_negative);
537 NEW_BBLOCK (cfg, end_label);
539 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
540 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
541 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
542 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
544 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
545 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
548 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
549 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
550 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
553 MONO_START_BB (cfg, is_negative);
554 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
555 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
557 MONO_START_BB (cfg, end_label);
559 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
562 case OP_LCONV_TO_OVF_I1_UN:
563 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
564 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
566 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
567 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
568 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
569 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
570 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
572 case OP_LCONV_TO_OVF_U1:
573 case OP_LCONV_TO_OVF_U1_UN:
574 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
575 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
577 /* probe value to be within 0 to 255 */
578 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
579 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
580 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
582 case OP_LCONV_TO_OVF_I2: {
583 MonoBasicBlock *is_negative, *end_label;
585 NEW_BBLOCK (cfg, is_negative);
586 NEW_BBLOCK (cfg, end_label);
588 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
589 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
590 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
591 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
593 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
594 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
597 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
598 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
599 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
602 MONO_START_BB (cfg, is_negative);
603 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
604 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
605 MONO_START_BB (cfg, end_label);
607 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
610 case OP_LCONV_TO_OVF_I2_UN:
611 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
612 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
614 /* Probe value to be within -32768 and 32767 */
615 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
616 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
617 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
618 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
619 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
621 case OP_LCONV_TO_OVF_U2:
622 case OP_LCONV_TO_OVF_U2_UN:
623 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
624 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
626 /* Probe value to be within 0 and 65535 */
627 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
628 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
629 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
631 case OP_LCONV_TO_OVF_I4:
632 case OP_LCONV_TO_OVF_I:
633 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
635 case OP_LCONV_TO_OVF_U4:
636 case OP_LCONV_TO_OVF_U:
637 case OP_LCONV_TO_OVF_U4_UN:
638 case OP_LCONV_TO_OVF_U_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_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
643 case OP_LCONV_TO_OVF_I_UN:
644 case OP_LCONV_TO_OVF_I4_UN:
645 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
646 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
647 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
648 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
649 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
651 case OP_LCONV_TO_OVF_U8:
652 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
653 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
655 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
656 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
658 case OP_LCONV_TO_OVF_I8_UN:
659 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
660 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
662 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
663 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
667 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
668 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
671 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
672 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
675 #if defined(__ppc__) || defined(__powerpc__)
677 /* ADC sets the condition code */
678 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
679 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
682 /* ADC sets the condition code */
683 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
684 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
687 /* SBB sets the condition code */
688 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
689 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
692 /* SBB sets the condition code */
693 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
694 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
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, OV, "OverflowException");
704 /* ADC sets the condition code */
705 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
706 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
707 MONO_EMIT_NEW_COND_EXC (cfg, C, "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, OV, "OverflowException");
716 /* SBB sets the condition code */
717 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
718 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
719 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
723 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
724 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
727 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
728 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
731 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
732 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
735 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
736 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
740 * FIXME: The original version in inssel-long32.brg does not work
741 * on x86, and the x86 version might not work on other archs ?
743 /* FIXME: Move these to mono_arch_decompose_long_opts () */
744 #if defined(__i386__)
745 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
746 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
747 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
748 #elif defined(__sparc__)
749 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
750 MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
751 #elif defined(__arm__)
752 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
753 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
754 #elif defined(__ppc__) || defined(__powerpc__)
755 /* This is the old version from inssel-long32.brg */
756 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
757 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
758 /* ADC sets the condition codes */
759 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 1, tree->dreg + 1, 1);
760 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->dreg + 2, 0);
767 /* FIXME: Add OP_BIGMUL optimization */
771 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
772 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
775 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
776 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
779 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
780 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
783 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
784 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
787 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
788 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
791 if (tree->inst_c1 == 32) {
793 /* The original code had this comment: */
794 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
795 * later apply the speedup to the left shift as well
798 /* FIXME: Move this to the strength reduction pass */
799 /* just move the upper half to the lower and zero the high word */
800 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
801 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
805 if (tree->inst_c1 == 32) {
806 /* just move the lower half to the upper and zero the lower word */
807 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
808 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
813 MonoInst *next = tree->next;
817 switch (next->opcode) {
822 /* Branchless version based on gcc code */
823 d1 = alloc_ireg (cfg);
824 d2 = alloc_ireg (cfg);
825 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
826 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
827 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
828 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
829 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
830 next->opcode = OP_NOP;
841 /* Convert into three comparisons + branches */
842 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
843 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
844 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
845 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
846 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
847 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
848 next->opcode = OP_NOP;
853 /* Branchless version based on gcc code */
854 d1 = alloc_ireg (cfg);
855 d2 = alloc_ireg (cfg);
856 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
857 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
858 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
860 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
861 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
862 next->opcode = OP_NOP;
869 MonoBasicBlock *set_to_0, *set_to_1;
871 NEW_BBLOCK (cfg, set_to_0);
872 NEW_BBLOCK (cfg, set_to_1);
874 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
875 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
876 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
877 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
878 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
879 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
880 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
881 MONO_START_BB (cfg, set_to_1);
882 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
883 MONO_START_BB (cfg, set_to_0);
884 next->opcode = OP_NOP;
888 g_assert_not_reached ();
893 /* Not yet used, since lcompare is decomposed before local cprop */
894 case OP_LCOMPARE_IMM: {
895 MonoInst *next = tree->next;
896 guint32 low_imm = tree->inst_ls_word;
897 guint32 high_imm = tree->inst_ms_word;
898 int low_reg = tree->sreg1 + 1;
899 int high_reg = tree->sreg1 + 2;
903 switch (next->opcode) {
908 /* Branchless version based on gcc code */
909 d1 = alloc_ireg (cfg);
910 d2 = alloc_ireg (cfg);
911 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
912 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
913 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
914 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
915 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
916 next->opcode = OP_NOP;
928 /* Convert into three comparisons + branches */
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
930 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
932 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
934 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
935 next->opcode = OP_NOP;
940 /* Branchless version based on gcc code */
941 d1 = alloc_ireg (cfg);
942 d2 = alloc_ireg (cfg);
943 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
944 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
945 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
947 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
948 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
949 next->opcode = OP_NOP;
956 MonoBasicBlock *set_to_0, *set_to_1;
958 NEW_BBLOCK (cfg, set_to_0);
959 NEW_BBLOCK (cfg, set_to_1);
961 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
962 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
963 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
964 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
965 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
966 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
967 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
968 MONO_START_BB (cfg, set_to_1);
969 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
970 MONO_START_BB (cfg, set_to_0);
971 next->opcode = OP_NOP;
975 g_assert_not_reached ();
984 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
987 /* Replace the original instruction with the new code sequence */
989 /* Ignore the new value of prev */
991 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
993 /* Process the newly added ops again since they can be long ops too */
999 first_bb->code = first_bb->last_ins = NULL;
1000 first_bb->in_count = first_bb->out_count = 0;
1001 cfg->cbb = first_bb;
1012 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1013 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1018 * mono_decompose_vtype_opts:
1020 * Decompose valuetype opcodes.
1023 mono_decompose_vtype_opts (MonoCompile *cfg)
1025 MonoBasicBlock *bb, *first_bb;
1028 * Using OP_V opcodes and decomposing them later have two main benefits:
1029 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1031 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1032 * enabling optimizations to work on vtypes too.
1033 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1034 * can be executed anytime. It should be executed as late as possible so vtype
1035 * opcodes can be optimized by the other passes.
1036 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1037 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1039 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1040 * when OP_VMOVE opcodes are decomposed.
1044 * Vregs have no associated type information, so we store the type of the vregs
1049 * Create a dummy bblock and emit code into it so we can use the normal
1050 * code generation macros.
1052 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1053 first_bb = cfg->cbb;
1055 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1057 MonoInst *prev = NULL;
1058 MonoInst *src_var, *dest_var, *src, *dest;
1062 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1064 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1070 for (ins = bb->code; ins; ins = ins->next) {
1071 switch (ins->opcode) {
1073 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1074 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1076 g_assert (ins->klass);
1079 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1082 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1085 if (src_var->backend.is_pinvoke)
1086 dest_var->backend.is_pinvoke = 1;
1088 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1089 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1091 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1095 g_assert (ins->klass);
1097 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1098 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1100 case OP_STOREV_MEMBASE: {
1101 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1104 g_assert (ins->klass);
1105 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1108 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1110 dreg = alloc_preg (cfg);
1111 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1112 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1115 case OP_LOADV_MEMBASE: {
1116 g_assert (ins->klass);
1118 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1121 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1123 dreg = alloc_preg (cfg);
1124 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1125 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1126 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1129 case OP_OUTARG_VT: {
1130 g_assert (ins->klass);
1132 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1134 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1135 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1137 mono_arch_emit_outarg_vt (cfg, ins, src);
1139 /* This might be decomposed into other vtype opcodes */
1143 case OP_OUTARG_VTRETADDR: {
1144 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1146 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1148 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1149 // FIXME: src_var->backend.is_pinvoke ?
1151 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1152 src->dreg = ins->dreg;
1157 case OP_VCALL_MEMBASE: {
1158 MonoCallInst *call = (MonoCallInst*)ins;
1161 if (call->vret_in_reg) {
1162 MonoCallInst *call2;
1164 /* Replace the vcall with an integer call */
1165 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1166 memcpy (call2, call, sizeof (MonoCallInst));
1167 switch (ins->opcode) {
1169 call2->inst.opcode = OP_CALL;
1172 call2->inst.opcode = OP_CALL_REG;
1174 case OP_VCALL_MEMBASE:
1175 call2->inst.opcode = OP_CALL_MEMBASE;
1178 call2->inst.dreg = alloc_preg (cfg);
1179 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1181 /* Compute the vtype location */
1182 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1184 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1185 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1187 /* Save the result */
1188 if (dest_var->backend.is_pinvoke)
1189 size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
1191 size = mono_type_size (dest_var->inst_vtype, NULL);
1194 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1197 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1200 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1203 #if SIZEOF_REGISTER == 4
1205 FIXME It would be nice to fix the operding of OP_CALL to make it possible to use numbering voodoo
1206 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1208 switch (call2->inst.opcode) {
1210 call2->inst.opcode = OP_LCALL;
1213 call2->inst.opcode = OP_LCALL_REG;
1215 case OP_CALL_MEMBASE:
1216 call2->inst.opcode = OP_LCALL_MEMBASE;
1219 call2->inst.dreg = alloc_lreg (cfg);
1220 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1221 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1223 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1227 /* This assumes the vtype is sizeof (gpointer) long */
1228 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1232 switch (ins->opcode) {
1234 ins->opcode = OP_VCALL2;
1237 ins->opcode = OP_VCALL2_REG;
1239 case OP_VCALL_MEMBASE:
1240 ins->opcode = OP_VCALL2_MEMBASE;
1251 g_assert (cfg->cbb == first_bb);
1253 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1254 /* Replace the original instruction with the new code sequence */
1256 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1257 first_bb->code = first_bb->last_ins = NULL;
1258 first_bb->in_count = first_bb->out_count = 0;
1259 cfg->cbb = first_bb;
1266 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1270 #endif /* DISABLE_JIT */