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
<= 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_REGISTER == 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_REGISTER == 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 #if SIZEOF_REGISTER == 4
1203 FIXME It would be nice to fix the operding of OP_CALL to make it possible to use numbering voodoo
1204 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1206 switch (call2
->inst
.opcode
) {
1208 call2
->inst
.opcode
= OP_LCALL
;
1211 call2
->inst
.opcode
= OP_LCALL_REG
;
1213 case OP_CALL_MEMBASE
:
1214 call2
->inst
.opcode
= OP_LCALL_MEMBASE
;
1217 call2
->inst
.dreg
= alloc_lreg (cfg
);
1218 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_MS_WORD_OFFSET
, call2
->inst
.dreg
+ 2);
1219 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_LS_WORD_OFFSET
, call2
->inst
.dreg
+ 1);
1221 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1225 /* This assumes the vtype is sizeof (gpointer) long */
1226 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1230 switch (ins
->opcode
) {
1232 ins
->opcode
= OP_VCALL2
;
1235 ins
->opcode
= OP_VCALL2_REG
;
1237 case OP_VCALL_MEMBASE
:
1238 ins
->opcode
= OP_VCALL2_MEMBASE
;
1249 g_assert (cfg
->cbb
== first_bb
);
1251 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1252 /* Replace the original instruction with the new code sequence */
1254 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1255 first_bb
->code
= first_bb
->last_ins
= NULL
;
1256 first_bb
->in_count
= first_bb
->out_count
= 0;
1257 cfg
->cbb
= first_bb
;
1264 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "AFTER LOWER-VTYPE-OPTS ");
1268 #endif /* DISABLE_JIT */