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;
168 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
169 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
170 ins->opcode = OP_NOP;
173 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
174 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
175 ins->opcode = OP_NOP;
178 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
179 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
180 ins->opcode = OP_NOP;
183 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
184 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
185 ins->opcode = OP_NOP;
188 case OP_ICONV_TO_OVF_I8:
189 case OP_ICONV_TO_OVF_I:
190 ins->opcode = OP_SEXT_I4;
192 case OP_ICONV_TO_OVF_U8:
193 case OP_ICONV_TO_OVF_U:
194 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
195 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
196 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
197 ins->opcode = OP_NOP;
199 case OP_ICONV_TO_OVF_I8_UN:
200 case OP_ICONV_TO_OVF_U8_UN:
201 case OP_ICONV_TO_OVF_I_UN:
202 case OP_ICONV_TO_OVF_U_UN:
203 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
204 /* Clean out the upper word */
205 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
206 ins->opcode = OP_NOP;
208 case OP_LCONV_TO_OVF_I1:
209 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
210 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
211 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
212 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
213 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
214 ins->opcode = OP_NOP;
216 case OP_LCONV_TO_OVF_I1_UN:
217 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
218 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
219 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
220 ins->opcode = OP_NOP;
222 case OP_LCONV_TO_OVF_U1:
223 /* probe value to be within 0 to 255 */
224 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
225 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
226 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
227 ins->opcode = OP_NOP;
229 case OP_LCONV_TO_OVF_U1_UN:
230 /* probe value to be within 0 to 255 */
231 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
232 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
233 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
234 ins->opcode = OP_NOP;
236 case OP_LCONV_TO_OVF_I2:
237 /* Probe value to be within -32768 and 32767 */
238 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
239 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
240 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
241 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
242 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
243 ins->opcode = OP_NOP;
245 case OP_LCONV_TO_OVF_I2_UN:
246 /* Probe value to be within 0 and 32767 */
247 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
248 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
249 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
250 ins->opcode = OP_NOP;
252 case OP_LCONV_TO_OVF_U2:
253 /* Probe value to be within 0 and 65535 */
254 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
255 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
256 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
257 ins->opcode = OP_NOP;
259 case OP_LCONV_TO_OVF_U2_UN:
260 /* Probe value to be within 0 and 65535 */
261 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
262 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
263 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
264 ins->opcode = OP_NOP;
266 case OP_LCONV_TO_OVF_I4:
267 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
268 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
269 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
270 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
271 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
272 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
273 ins->opcode = OP_NOP;
275 case OP_LCONV_TO_OVF_I4_UN:
276 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
277 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
278 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
279 ins->opcode = OP_NOP;
281 case OP_LCONV_TO_OVF_U4:
282 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
283 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
284 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
285 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
286 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
287 ins->opcode = OP_NOP;
289 case OP_LCONV_TO_OVF_U4_UN:
290 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
291 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
292 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
293 ins->opcode = OP_NOP;
295 case OP_LCONV_TO_OVF_I:
296 case OP_LCONV_TO_OVF_U_UN:
297 case OP_LCONV_TO_OVF_U8_UN:
298 ins->opcode = OP_MOVE;
300 case OP_LCONV_TO_OVF_I_UN:
301 case OP_LCONV_TO_OVF_I8_UN:
302 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
303 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
304 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
305 ins->opcode = OP_NOP;
307 case OP_LCONV_TO_OVF_U8:
308 case OP_LCONV_TO_OVF_U:
309 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
310 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
311 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
312 ins->opcode = OP_NOP;
317 MonoJitICallInfo *info;
319 info = mono_find_jit_opcode_emulation (ins->opcode);
324 /* Create dummy MonoInst's for the arguments */
325 g_assert (!info->sig->hasthis);
326 g_assert (info->sig->param_count <= 2);
328 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
329 if (info->sig->param_count > 0) {
330 MONO_INST_NEW (cfg, args [0], OP_ARG);
331 args [0]->dreg = ins->sreg1;
333 if (info->sig->param_count > 1) {
334 MONO_INST_NEW (cfg, args [1], OP_ARG);
335 args [1]->dreg = ins->sreg2;
338 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
339 call->dreg = ins->dreg;
341 ins->opcode = OP_NOP;
348 #if SIZEOF_VOID_P == 4
349 static int lbr_decomp [][2] = {
351 {OP_IBGT, OP_IBGE_UN}, /* BGE */
352 {OP_IBGT, OP_IBGT_UN}, /* BGT */
353 {OP_IBLT, OP_IBLE_UN}, /* BLE */
354 {OP_IBLT, OP_IBLT_UN}, /* BLT */
356 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
357 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
358 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
359 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
362 static int lcset_decomp [][2] = {
364 {OP_IBLT, OP_IBLE_UN}, /* CGT */
365 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
366 {OP_IBGT, OP_IBGE_UN}, /* CLT */
367 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
372 * mono_decompose_long_opts:
374 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
377 mono_decompose_long_opts (MonoCompile *cfg)
379 #if SIZEOF_VOID_P == 4
380 MonoBasicBlock *bb, *first_bb;
383 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
384 * needs to be able to handle long vregs.
387 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
390 * Create a dummy bblock and emit code into it so we can use the normal
391 * code generation macros.
393 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
396 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
397 MonoInst *tree = bb->code;
398 MonoInst *prev = NULL;
401 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
405 cfg->cbb->code = cfg->cbb->last_ins = NULL;
409 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
410 mono_arch_decompose_long_opts (cfg, tree);
413 switch (tree->opcode) {
415 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
416 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
421 case OP_LCONV_TO_OVF_U8_UN:
422 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
423 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
425 case OP_STOREI8_MEMBASE_REG:
426 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
427 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
429 case OP_LOADI8_MEMBASE:
430 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
431 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
434 case OP_ICONV_TO_I8: {
435 guint32 tmpreg = alloc_ireg (cfg);
439 * tmp = low > -1 ? 1: 0;
440 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
442 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
443 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
444 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
445 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
449 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
450 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
452 case OP_ICONV_TO_OVF_I8:
453 /* a signed 32 bit num always fits in a signed 64 bit one */
454 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
455 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
457 case OP_ICONV_TO_OVF_U8:
458 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
459 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
460 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
461 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
463 case OP_ICONV_TO_OVF_I8_UN:
464 case OP_ICONV_TO_OVF_U8_UN:
465 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
466 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
467 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
470 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
473 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
476 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
479 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
485 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
488 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
491 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
493 case OP_LCONV_TO_R_UN:
494 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
496 case OP_LCONV_TO_OVF_I1: {
497 MonoBasicBlock *is_negative, *end_label;
499 NEW_BBLOCK (cfg, is_negative);
500 NEW_BBLOCK (cfg, end_label);
502 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
503 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
504 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
505 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
507 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
508 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
511 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
512 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
513 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
516 MONO_START_BB (cfg, is_negative);
517 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
518 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
520 MONO_START_BB (cfg, end_label);
522 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
525 case OP_LCONV_TO_OVF_I1_UN:
526 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
527 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
529 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
530 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
531 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
532 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
533 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
535 case OP_LCONV_TO_OVF_U1:
536 case OP_LCONV_TO_OVF_U1_UN:
537 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
538 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
540 /* probe value to be within 0 to 255 */
541 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
542 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
543 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
545 case OP_LCONV_TO_OVF_I2: {
546 MonoBasicBlock *is_negative, *end_label;
548 NEW_BBLOCK (cfg, is_negative);
549 NEW_BBLOCK (cfg, end_label);
551 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
552 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
553 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
554 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
556 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
557 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
560 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
561 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
562 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
565 MONO_START_BB (cfg, is_negative);
566 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
567 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
568 MONO_START_BB (cfg, end_label);
570 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
573 case OP_LCONV_TO_OVF_I2_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 -32768 and 32767 */
578 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
579 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
580 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
581 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
582 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
584 case OP_LCONV_TO_OVF_U2:
585 case OP_LCONV_TO_OVF_U2_UN:
586 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
587 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
589 /* Probe value to be within 0 and 65535 */
590 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
591 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
592 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
594 case OP_LCONV_TO_OVF_I4:
595 case OP_LCONV_TO_OVF_I:
596 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
598 case OP_LCONV_TO_OVF_U4:
599 case OP_LCONV_TO_OVF_U:
600 case OP_LCONV_TO_OVF_U4_UN:
601 case OP_LCONV_TO_OVF_U_UN:
602 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
603 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
604 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
606 case OP_LCONV_TO_OVF_I_UN:
607 case OP_LCONV_TO_OVF_I4_UN:
608 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
609 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
610 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
611 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
612 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
614 case OP_LCONV_TO_OVF_U8:
615 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
616 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
618 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
619 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
621 case OP_LCONV_TO_OVF_I8_UN:
622 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
623 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
625 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
626 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
630 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
631 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
634 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
635 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
638 /* ADC sets the condition code */
639 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
640 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
641 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
644 /* ADC sets the condition code */
645 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
646 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
647 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
650 /* SBB sets the condition code */
651 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
652 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
653 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
656 /* SBB sets the condition code */
657 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
658 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
659 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
662 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
663 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
666 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
667 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
670 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
671 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
674 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
675 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
679 * FIXME: The original version in inssel-long32.brg does not work
680 * on x86, and the x86 version might not work on other archs ?
682 /* FIXME: Move these to mono_arch_decompose_long_opts () */
683 #if defined(__i386__)
684 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
685 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
686 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
687 #elif defined(__sparc__)
688 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
689 MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
690 #elif defined(__arm__)
691 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
692 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
699 /* FIXME: Add OP_BIGMUL optimization */
703 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
704 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
707 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
708 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
711 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
712 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
715 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
716 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
719 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
720 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
723 if (tree->inst_c1 == 32) {
725 /* The original code had this comment: */
726 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
727 * later apply the speedup to the left shift as well
730 /* FIXME: Move this to the strength reduction pass */
731 /* just move the upper half to the lower and zero the high word */
732 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
733 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
737 if (tree->inst_c1 == 32) {
738 /* just move the lower half to the upper and zero the lower word */
739 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
740 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
745 MonoInst *next = tree->next;
749 switch (next->opcode) {
754 /* Branchless version based on gcc code */
755 d1 = alloc_ireg (cfg);
756 d2 = alloc_ireg (cfg);
757 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
758 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
759 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
760 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
761 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
762 next->opcode = OP_NOP;
773 /* Convert into three comparisons + branches */
774 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
775 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
776 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
777 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
778 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
779 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
780 next->opcode = OP_NOP;
785 /* Branchless version based on gcc code */
786 d1 = alloc_ireg (cfg);
787 d2 = alloc_ireg (cfg);
788 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
789 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
790 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
792 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
793 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
794 next->opcode = OP_NOP;
801 MonoBasicBlock *set_to_0, *set_to_1;
803 NEW_BBLOCK (cfg, set_to_0);
804 NEW_BBLOCK (cfg, set_to_1);
806 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
807 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
808 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
809 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
810 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
811 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
812 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
813 MONO_START_BB (cfg, set_to_1);
814 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
815 MONO_START_BB (cfg, set_to_0);
816 next->opcode = OP_NOP;
820 g_assert_not_reached ();
825 /* Not yet used, since lcompare is decomposed before local cprop */
826 case OP_LCOMPARE_IMM: {
827 MonoInst *next = tree->next;
828 guint32 low_imm = tree->inst_ls_word;
829 guint32 high_imm = tree->inst_ms_word;
830 int low_reg = tree->sreg1 + 1;
831 int high_reg = tree->sreg1 + 2;
835 switch (next->opcode) {
840 /* Branchless version based on gcc code */
841 d1 = alloc_ireg (cfg);
842 d2 = alloc_ireg (cfg);
843 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
844 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
845 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
846 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
847 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
848 next->opcode = OP_NOP;
860 /* Convert into three comparisons + branches */
861 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
862 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
863 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
864 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
865 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
866 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
867 next->opcode = OP_NOP;
872 /* Branchless version based on gcc code */
873 d1 = alloc_ireg (cfg);
874 d2 = alloc_ireg (cfg);
875 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
876 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
877 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
879 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
880 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
881 next->opcode = OP_NOP;
888 MonoBasicBlock *set_to_0, *set_to_1;
890 NEW_BBLOCK (cfg, set_to_0);
891 NEW_BBLOCK (cfg, set_to_1);
893 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
894 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
895 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
896 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
897 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
898 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
899 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
900 MONO_START_BB (cfg, set_to_1);
901 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
902 MONO_START_BB (cfg, set_to_0);
903 next->opcode = OP_NOP;
907 g_assert_not_reached ();
916 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
919 /* Replace the original instruction with the new code sequence */
921 /* Ignore the new value of prev */
923 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
925 /* Process the newly added ops again since they can be long ops too */
931 first_bb->code = first_bb->last_ins = NULL;
932 first_bb->in_count = first_bb->out_count = 0;
944 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
945 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
950 * mono_decompose_vtype_opts:
952 * Decompose valuetype opcodes.
955 mono_decompose_vtype_opts (MonoCompile *cfg)
957 MonoBasicBlock *bb, *first_bb;
960 * Using OP_V opcodes and decomposing them later have two main benefits:
961 * - it simplifies method_to_ir () since there is no need to special-case vtypes
963 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
964 * enabling optimizations to work on vtypes too.
965 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
966 * can be executed anytime. It should be executed as late as possible so vtype
967 * opcodes can be optimized by the other passes.
968 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
969 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
971 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
972 * when OP_VMOVE opcodes are decomposed.
976 * Vregs have no associated type information, so we store the type of the vregs
981 * Create a dummy bblock and emit code into it so we can use the normal
982 * code generation macros.
984 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
987 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
989 MonoInst *prev = NULL;
990 MonoInst *src_var, *dest_var, *src, *dest;
994 if (cfg->verbose_level > 1) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
996 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1002 for (ins = bb->code; ins; ins = ins->next) {
1003 switch (ins->opcode) {
1005 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1006 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1008 g_assert (ins->klass);
1011 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1014 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1017 if (src_var->backend.is_pinvoke)
1018 dest_var->backend.is_pinvoke = 1;
1020 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1021 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1023 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1027 g_assert (ins->klass);
1029 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1030 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1032 case OP_STOREV_MEMBASE: {
1033 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1036 g_assert (ins->klass);
1037 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1040 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1042 dreg = alloc_preg (cfg);
1043 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1044 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1047 case OP_LOADV_MEMBASE: {
1048 g_assert (ins->klass);
1050 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1053 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1055 dreg = alloc_preg (cfg);
1056 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1057 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1058 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1061 case OP_OUTARG_VT: {
1062 g_assert (ins->klass);
1064 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1066 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1067 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1069 mono_arch_emit_outarg_vt (cfg, ins, src);
1071 /* This might be decomposed into other vtype opcodes */
1075 case OP_OUTARG_VTRETADDR: {
1076 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1078 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1080 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1081 // FIXME: src_var->backend.is_pinvoke ?
1083 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1084 src->dreg = ins->dreg;
1089 case OP_VCALL_MEMBASE: {
1090 MonoCallInst *call = (MonoCallInst*)ins;
1092 if (call->vret_in_reg) {
1093 MonoCallInst *call2;
1095 /* Replace the vcall with an integer call */
1096 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1097 memcpy (call2, call, sizeof (MonoCallInst));
1098 switch (ins->opcode) {
1100 call2->inst.opcode = OP_CALL;
1103 call2->inst.opcode = OP_CALL_REG;
1105 case OP_VCALL_MEMBASE:
1106 call2->inst.opcode = OP_CALL_MEMBASE;
1109 call2->inst.dreg = alloc_preg (cfg);
1110 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1112 /* Compute the vtype location */
1113 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1114 /* This was already created when OP_OUTARG_VTRETADDR was processed */
1115 g_assert (dest_var);
1116 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1118 /* Save the result */
1119 /* This assumes the vtype is sizeof (gpointer) long */
1120 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1122 switch (ins->opcode) {
1124 ins->opcode = OP_VCALL2;
1127 ins->opcode = OP_VCALL2_REG;
1129 case OP_VCALL_MEMBASE:
1130 ins->opcode = OP_VCALL2_MEMBASE;
1141 g_assert (cfg->cbb == first_bb);
1143 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1144 /* Replace the original instruction with the new code sequence */
1146 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1147 first_bb->code = first_bb->last_ins = NULL;
1148 first_bb->in_count = first_bb->out_count = 0;
1149 cfg->cbb = first_bb;
1156 if (cfg->verbose_level > 1) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");