3 * Functions to decompose complex IR instructions into simpler ones.
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2002 Ximian, Inc.
9 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include "mini-runtime.h"
16 #include "jit-icalls.h"
18 #include <mono/metadata/gc-internals.h>
19 #include <mono/metadata/abi-details.h>
20 #include <mono/utils/mono-compiler.h>
25 * Decompose complex long opcodes on 64 bit machines.
26 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
29 decompose_long_opcode (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
**repl_ins
)
31 MonoInst
*repl
= NULL
;
35 switch (ins
->opcode
) {
37 ins
->opcode
= OP_SEXT_I4
;
41 if (SIZEOF_VOID_P
== 4)
42 ins
->opcode
= OP_LMOVE
;
44 ins
->opcode
= OP_MOVE
;
47 if (SIZEOF_VOID_P
== 4)
49 ins
->opcode
= OP_SEXT_I4
;
51 ins
->opcode
= OP_MOVE
;
54 if (SIZEOF_VOID_P
== 4) {
56 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
59 ins
->opcode
= OP_MOVE
;
63 ins
->opcode
= OP_SEXT_I4
;
66 ins
->opcode
= OP_ZEXT_I4
;
69 /* Clean out the upper word */
70 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
76 if (COMPILE_LLVM (cfg
))
78 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
82 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
83 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
87 case OP_LADD_OVF_UN
: {
90 if (COMPILE_LLVM (cfg
))
92 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
96 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
97 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
101 #ifndef __mono_ppc64__
105 if (COMPILE_LLVM (cfg
))
107 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
111 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
112 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
116 case OP_LSUB_OVF_UN
: {
119 if (COMPILE_LLVM (cfg
))
121 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
125 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
126 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
132 case OP_ICONV_TO_OVF_I8
:
133 case OP_ICONV_TO_OVF_I
:
134 ins
->opcode
= OP_SEXT_I4
;
136 case OP_ICONV_TO_OVF_U8
:
137 case OP_ICONV_TO_OVF_U
:
138 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
,ins
->sreg1
, 0);
139 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
140 MONO_EMIT_NEW_UNALU (cfg
, OP_ZEXT_I4
, ins
->dreg
, ins
->sreg1
);
143 case OP_ICONV_TO_OVF_I8_UN
:
144 case OP_ICONV_TO_OVF_U8_UN
:
145 case OP_ICONV_TO_OVF_I_UN
:
146 case OP_ICONV_TO_OVF_U_UN
:
147 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
148 /* Clean out the upper word */
149 MONO_EMIT_NEW_UNALU (cfg
, OP_ZEXT_I4
, ins
->dreg
, ins
->sreg1
);
152 case OP_LCONV_TO_OVF_I1
:
153 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 127);
154 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
155 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -128);
156 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
157 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
160 case OP_LCONV_TO_OVF_I1_UN
:
161 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 127);
162 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
163 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
166 case OP_LCONV_TO_OVF_U1
:
167 /* probe value to be within 0 to 255 */
168 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 255);
169 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
170 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
173 case OP_LCONV_TO_OVF_U1_UN
:
174 /* probe value to be within 0 to 255 */
175 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 255);
176 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
177 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
180 case OP_LCONV_TO_OVF_I2
:
181 /* Probe value to be within -32768 and 32767 */
182 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
183 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
184 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
185 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
186 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
189 case OP_LCONV_TO_OVF_I2_UN
:
190 /* Probe value to be within 0 and 32767 */
191 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
192 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
193 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
196 case OP_LCONV_TO_OVF_U2
:
197 /* Probe value to be within 0 and 65535 */
198 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
199 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
200 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
203 case OP_LCONV_TO_OVF_U2_UN
:
204 /* Probe value to be within 0 and 65535 */
205 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
206 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
207 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
210 case OP_LCONV_TO_OVF_I4
:
211 #if SIZEOF_VOID_P == 4
212 case OP_LCONV_TO_OVF_I
:
214 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
215 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
216 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
217 #if SIZEOF_REGISTER == 8
218 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, ((int)-2147483648));
220 g_assert (COMPILE_LLVM (cfg
));
221 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -2147483648LL);
223 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
224 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
227 case OP_LCONV_TO_OVF_I4_UN
:
228 #if SIZEOF_VOID_P == 4
229 case OP_LCONV_TO_OVF_I_UN
:
231 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
232 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
233 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
236 case OP_LCONV_TO_OVF_U4
:
237 #if SIZEOF_VOID_P == 4
238 case OP_LCONV_TO_OVF_U
:
240 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffffUL
);
241 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
242 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
243 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
244 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
247 case OP_LCONV_TO_OVF_U4_UN
:
248 #if SIZEOF_VOID_P == 4
249 case OP_LCONV_TO_OVF_U_UN
:
251 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffff);
252 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
253 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
256 #if SIZEOF_VOID_P == 8
257 case OP_LCONV_TO_OVF_I
:
258 case OP_LCONV_TO_OVF_U_UN
:
260 case OP_LCONV_TO_OVF_U8_UN
:
261 case OP_LCONV_TO_OVF_I8
:
262 ins
->opcode
= OP_MOVE
;
264 #if SIZEOF_VOID_P == 8
265 case OP_LCONV_TO_OVF_I_UN
:
267 case OP_LCONV_TO_OVF_I8_UN
:
268 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
269 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
270 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
273 case OP_LCONV_TO_OVF_U8
:
274 #if SIZEOF_VOID_P == 8
275 case OP_LCONV_TO_OVF_U
:
277 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
278 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
279 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
291 * mono_decompose_opcode:
293 * Decompose complex opcodes into ones closer to opcodes supported by
294 * the given architecture.
295 * Returns a MonoInst which represents the result of the decomposition, and can
296 * be pushed on the IL stack. This is needed because the original instruction is
298 * Sets the cfg exception if an opcode is not supported.
301 mono_decompose_opcode (MonoCompile
*cfg
, MonoInst
*ins
)
303 MonoInst
*repl
= NULL
;
304 int type
= ins
->type
;
305 int dreg
= ins
->dreg
;
306 gboolean emulate
= FALSE
;
308 /* FIXME: Instead of = NOP, don't emit the original ins at all */
309 mono_arch_decompose_opts (cfg
, ins
);
312 * The code below assumes that we are called immediately after emitting
313 * ins. This means we can emit code using the normal code generation
316 switch (ins
->opcode
) {
317 /* this doesn't make sense on ppc and other architectures */
318 #if !defined(MONO_ARCH_NO_IOV_CHECK)
320 if (COMPILE_LLVM (cfg
))
322 ins
->opcode
= OP_IADDCC
;
323 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
326 if (COMPILE_LLVM (cfg
))
328 ins
->opcode
= OP_IADDCC
;
329 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
332 if (COMPILE_LLVM (cfg
))
334 ins
->opcode
= OP_ISUBCC
;
335 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
338 if (COMPILE_LLVM (cfg
))
340 ins
->opcode
= OP_ISUBCC
;
341 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
344 case OP_ICONV_TO_OVF_I1
:
345 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
346 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
347 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -128);
348 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
349 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
352 case OP_ICONV_TO_OVF_I1_UN
:
353 /* probe values between 0 to 127 */
354 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
355 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
356 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
359 case OP_ICONV_TO_OVF_U1
:
360 case OP_ICONV_TO_OVF_U1_UN
:
361 /* probe value to be within 0 to 255 */
362 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 255);
363 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
364 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
367 case OP_ICONV_TO_OVF_I2
:
368 /* Probe value to be within -32768 and 32767 */
369 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
370 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
371 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
372 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
373 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
376 case OP_ICONV_TO_OVF_I2_UN
:
377 /* Convert uint value into short, value within 0 and 32767 */
378 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
379 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
380 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
383 case OP_ICONV_TO_OVF_U2
:
384 case OP_ICONV_TO_OVF_U2_UN
:
385 /* Probe value to be within 0 and 65535 */
386 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
387 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
388 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
391 case OP_ICONV_TO_OVF_U4
:
392 case OP_ICONV_TO_OVF_I4_UN
:
393 #if SIZEOF_VOID_P == 4
394 case OP_ICONV_TO_OVF_U
:
395 case OP_ICONV_TO_OVF_I_UN
:
397 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0);
398 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
399 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
404 case OP_ICONV_TO_OVF_I4
:
405 case OP_ICONV_TO_OVF_U4_UN
:
406 #if SIZEOF_VOID_P == 4
407 case OP_ICONV_TO_OVF_I
:
408 case OP_ICONV_TO_OVF_U_UN
:
410 ins
->opcode
= OP_MOVE
;
413 #if SIZEOF_VOID_P == 8
414 ins
->opcode
= OP_SEXT_I4
;
416 ins
->opcode
= OP_MOVE
;
420 #if SIZEOF_VOID_P == 8
421 ins
->opcode
= OP_ZEXT_I4
;
423 ins
->opcode
= OP_MOVE
;
428 ins
->opcode
= OP_FMOVE
;
431 case OP_FCONV_TO_OVF_I1_UN
:
432 case OP_FCONV_TO_OVF_I2_UN
:
433 case OP_FCONV_TO_OVF_I4_UN
:
434 case OP_FCONV_TO_OVF_I8_UN
:
435 case OP_FCONV_TO_OVF_U1_UN
:
436 case OP_FCONV_TO_OVF_U2_UN
:
437 case OP_FCONV_TO_OVF_U4_UN
:
438 case OP_FCONV_TO_OVF_U8_UN
:
439 case OP_FCONV_TO_OVF_I_UN
:
440 case OP_FCONV_TO_OVF_U_UN
:
441 mono_cfg_set_exception_invalid_program (cfg
, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
448 if (cfg
->backend
->emulate_div
&& mono_arch_opcode_needs_emulation (cfg
, ins
->opcode
))
451 if (cfg
->backend
->need_div_check
) {
452 int reg1
= alloc_ireg (cfg
);
453 int reg2
= alloc_ireg (cfg
);
455 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg2
, 0);
456 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
457 if (ins
->opcode
== OP_IDIV
|| ins
->opcode
== OP_IREM
) {
458 /* b == -1 && a == 0x80000000 */
459 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg2
, -1);
460 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, reg1
, -1);
461 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0x80000000);
462 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, reg2
, -1);
463 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, reg1
, reg1
, reg2
);
464 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 1);
465 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
468 MONO_EMIT_NEW_BIALU (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
473 #if SIZEOF_VOID_P == 8
478 if (cfg
->backend
->emulate_div
&& mono_arch_opcode_needs_emulation (cfg
, ins
->opcode
))
481 if (cfg
->backend
->need_div_check
) {
482 int reg1
= alloc_ireg (cfg
);
483 int reg2
= alloc_ireg (cfg
);
484 int reg3
= alloc_ireg (cfg
);
486 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg2
, 0);
487 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
488 if (ins
->opcode
== OP_LDIV
|| ins
->opcode
== OP_LREM
) {
489 /* b == -1 && a == 0x80000000 */
490 MONO_EMIT_NEW_I8CONST (cfg
, reg3
, -1);
491 MONO_EMIT_NEW_BIALU (cfg
, OP_LCOMPARE
, -1, ins
->sreg2
, reg3
);
492 MONO_EMIT_NEW_UNALU (cfg
, OP_LCEQ
, reg1
, -1);
493 MONO_EMIT_NEW_I8CONST (cfg
, reg3
, 0x8000000000000000L
);
494 MONO_EMIT_NEW_BIALU (cfg
, OP_LCOMPARE
, -1, ins
->sreg1
, reg3
);
495 MONO_EMIT_NEW_UNALU (cfg
, OP_LCEQ
, reg2
, -1);
496 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, reg1
, reg1
, reg2
);
497 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 1);
498 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
501 MONO_EMIT_NEW_BIALU (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
513 if (cfg
->backend
->need_div_check
) {
514 int reg1
= alloc_ireg (cfg
);
516 if (ins
->inst_imm
== 0) {
517 // FIXME: Optimize this
518 MONO_EMIT_NEW_ICONST (cfg
, reg1
, 0);
519 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 0);
520 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
522 if ((ins
->opcode
== OP_DIV_IMM
|| ins
->opcode
== OP_IDIV_IMM
|| ins
->opcode
== OP_REM_IMM
|| ins
->opcode
== OP_IREM_IMM
) &&
523 (ins
->inst_imm
== -1)) {
524 /* b == -1 && a == 0x80000000 */
525 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0x80000000);
526 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
528 MONO_EMIT_NEW_BIALU_IMM (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
534 case OP_ICONV_TO_R_UN
:
535 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
536 if (!COMPILE_LLVM (cfg
))
546 #if SIZEOF_REGISTER == 8
547 if (decompose_long_opcode (cfg
, ins
, &repl
))
550 if (COMPILE_LLVM (cfg
) && decompose_long_opcode (cfg
, ins
, &repl
))
554 if (emulate
&& mono_find_jit_opcode_emulation (ins
->opcode
))
555 cfg
->has_emulated_ops
= TRUE
;
558 if (ins
->opcode
== OP_NOP
) {
563 /* Use the last emitted instruction */
564 ins
= cfg
->cbb
->last_ins
;
567 g_assert (ins
->dreg
== dreg
);
575 #if SIZEOF_REGISTER == 4
576 static int lbr_decomp
[][2] = {
578 {OP_IBGT
, OP_IBGE_UN
}, /* BGE */
579 {OP_IBGT
, OP_IBGT_UN
}, /* BGT */
580 {OP_IBLT
, OP_IBLE_UN
}, /* BLE */
581 {OP_IBLT
, OP_IBLT_UN
}, /* BLT */
583 {OP_IBGT_UN
, OP_IBGE_UN
}, /* BGE_UN */
584 {OP_IBGT_UN
, OP_IBGT_UN
}, /* BGT_UN */
585 {OP_IBLT_UN
, OP_IBLE_UN
}, /* BLE_UN */
586 {OP_IBLT_UN
, OP_IBLT_UN
}, /* BLT_UN */
589 static int lcset_decomp
[][2] = {
591 {OP_IBLT
, OP_IBLE_UN
}, /* CGT */
592 {OP_IBLT_UN
, OP_IBLE_UN
}, /* CGT_UN */
593 {OP_IBGT
, OP_IBGE_UN
}, /* CLT */
594 {OP_IBGT_UN
, OP_IBGE_UN
}, /* CLT_UN */
599 * mono_decompose_long_opts:
601 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
604 mono_decompose_long_opts (MonoCompile
*cfg
)
606 #if SIZEOF_REGISTER == 4
607 MonoBasicBlock
*bb
, *first_bb
;
610 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
611 * needs to be able to handle long vregs.
615 * Create a dummy bblock and emit code into it so we can use the normal
616 * code generation macros.
618 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
621 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
622 MonoInst
*tree
= mono_bb_first_inst(bb
, FILTER_IL_SEQ_POINT
);
623 MonoInst
*prev
= NULL
;
626 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
629 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
632 mono_arch_decompose_long_opts (cfg
, tree
);
634 switch (tree
->opcode
) {
636 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_LS (tree
->dreg
), tree
->inst_ls_word
);
637 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), tree
->inst_ms_word
);
639 case OP_DUMMY_I8CONST
:
640 MONO_EMIT_NEW_DUMMY_INIT (cfg
, MONO_LVREG_LS (tree
->dreg
), OP_DUMMY_ICONST
);
641 MONO_EMIT_NEW_DUMMY_INIT (cfg
, MONO_LVREG_MS (tree
->dreg
), OP_DUMMY_ICONST
);
646 case OP_LCONV_TO_OVF_U8_UN
:
647 case OP_LCONV_TO_OVF_I8
:
648 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
649 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
651 case OP_STOREI8_MEMBASE_REG
:
652 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, tree
->inst_destbasereg
, tree
->inst_offset
+ MINI_MS_WORD_OFFSET
, MONO_LVREG_MS (tree
->sreg1
));
653 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, tree
->inst_destbasereg
, tree
->inst_offset
+ MINI_LS_WORD_OFFSET
, MONO_LVREG_LS (tree
->sreg1
));
655 case OP_LOADI8_MEMBASE
:
656 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, MONO_LVREG_MS (tree
->dreg
), tree
->inst_basereg
, tree
->inst_offset
+ MINI_MS_WORD_OFFSET
);
657 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg
, OP_LOADI4_MEMBASE
, MONO_LVREG_LS (tree
->dreg
), tree
->inst_basereg
, tree
->inst_offset
+ MINI_LS_WORD_OFFSET
);
660 case OP_ICONV_TO_I8
: {
661 guint32 tmpreg
= alloc_ireg (cfg
);
665 * tmp = low > -1 ? 1: 0;
666 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
668 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
669 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, MONO_LVREG_LS (tree
->dreg
), -1);
670 MONO_EMIT_NEW_BIALU (cfg
, OP_ICGT
, tmpreg
, -1, -1);
671 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, MONO_LVREG_MS (tree
->dreg
), tmpreg
, 1);
675 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
676 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
678 case OP_ICONV_TO_OVF_I8
:
679 /* a signed 32 bit num always fits in a signed 64 bit one */
680 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, MONO_LVREG_MS (tree
->dreg
), tree
->sreg1
, 31);
681 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
683 case OP_ICONV_TO_OVF_U8
:
684 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
, 0);
685 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
686 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
687 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
689 case OP_ICONV_TO_OVF_I8_UN
:
690 case OP_ICONV_TO_OVF_U8_UN
:
691 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
692 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
693 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
696 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
699 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
702 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
705 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
711 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
713 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
715 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R8_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
718 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
720 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R4_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
723 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
724 case OP_LCONV_TO_R_UN
:
725 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R_UN_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
728 case OP_LCONV_TO_OVF_I1
: {
729 MonoBasicBlock
*is_negative
, *end_label
;
731 NEW_BBLOCK (cfg
, is_negative
);
732 NEW_BBLOCK (cfg
, end_label
);
734 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
735 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
736 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), -1);
737 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
739 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
740 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
743 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 127);
744 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
745 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
748 MONO_START_BB (cfg
, is_negative
);
749 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -128);
750 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
752 MONO_START_BB (cfg
, end_label
);
754 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
757 case OP_LCONV_TO_OVF_I1_UN
:
758 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
759 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
761 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 127);
762 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
763 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -128);
764 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
765 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
767 case OP_LCONV_TO_OVF_U1
:
768 case OP_LCONV_TO_OVF_U1_UN
:
769 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
770 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
772 /* probe value to be within 0 to 255 */
773 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 255);
774 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
775 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), 0xff);
777 case OP_LCONV_TO_OVF_I2
: {
778 MonoBasicBlock
*is_negative
, *end_label
;
780 NEW_BBLOCK (cfg
, is_negative
);
781 NEW_BBLOCK (cfg
, end_label
);
783 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
784 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
785 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), -1);
786 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
788 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
789 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
792 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 32767);
793 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
794 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
797 MONO_START_BB (cfg
, is_negative
);
798 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -32768);
799 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
800 MONO_START_BB (cfg
, end_label
);
802 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
805 case OP_LCONV_TO_OVF_I2_UN
:
806 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
807 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
809 /* Probe value to be within -32768 and 32767 */
810 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 32767);
811 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
812 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -32768);
813 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
814 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
816 case OP_LCONV_TO_OVF_U2
:
817 case OP_LCONV_TO_OVF_U2_UN
:
818 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
819 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
821 /* Probe value to be within 0 and 65535 */
822 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 0xffff);
823 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
824 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), 0xffff);
826 case OP_LCONV_TO_OVF_I4
:
827 case OP_LCONV_TO_OVF_I
:
828 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_OVF_I4_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
830 case OP_LCONV_TO_OVF_U4
:
831 case OP_LCONV_TO_OVF_U
:
832 case OP_LCONV_TO_OVF_U4_UN
:
833 case OP_LCONV_TO_OVF_U_UN
:
834 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
835 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
836 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
838 case OP_LCONV_TO_OVF_I_UN
:
839 case OP_LCONV_TO_OVF_I4_UN
:
840 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
841 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
842 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_LS (tree
->sreg1
), 0);
843 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
844 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
846 case OP_LCONV_TO_OVF_U8
:
847 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
848 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
850 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
851 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
853 case OP_LCONV_TO_OVF_I8_UN
:
854 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
855 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
857 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
858 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
862 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
863 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
866 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
867 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
871 /* ADC sets the condition code */
872 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
873 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
874 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
877 /* ADC sets the condition code */
878 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
879 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
880 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
883 /* SBB sets the condition code */
884 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
885 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
886 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
889 /* SBB sets the condition code */
890 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
891 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
892 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
895 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
896 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
899 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
900 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
903 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
904 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
907 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
908 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
911 /* Handled in mono_arch_decompose_long_opts () */
912 g_assert_not_reached ();
916 /* FIXME: Add OP_BIGMUL optimization */
920 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADDCC_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
921 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADC_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
924 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SUBCC_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
925 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SBB_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
928 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
929 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
932 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
933 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
936 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
937 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
939 #ifdef TARGET_POWERPC
940 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
942 if (tree
->inst_c1
== 32) {
944 /* The original code had this comment: */
945 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
946 * later apply the speedup to the left shift as well
949 /* just move the upper half to the lower and zero the high word */
950 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
951 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
956 MonoInst
*next
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
960 switch (next
->opcode
) {
965 /* Branchless version based on gcc code */
966 d1
= alloc_ireg (cfg
);
967 d2
= alloc_ireg (cfg
);
968 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
969 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
970 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
971 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
972 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
984 /* Convert into three comparisons + branches */
985 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
986 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
987 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
988 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
989 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
990 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
996 /* Branchless version based on gcc code */
997 d1
= alloc_ireg (cfg
);
998 d2
= alloc_ireg (cfg
);
999 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
1000 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
1001 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1003 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1004 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
1012 MonoBasicBlock
*set_to_0
, *set_to_1
;
1014 NEW_BBLOCK (cfg
, set_to_0
);
1015 NEW_BBLOCK (cfg
, set_to_1
);
1017 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
1018 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
1019 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
1020 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
1021 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
1022 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
1023 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
1024 MONO_START_BB (cfg
, set_to_1
);
1025 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
1026 MONO_START_BB (cfg
, set_to_0
);
1031 g_assert_not_reached ();
1036 /* Not yet used, since lcompare is decomposed before local cprop */
1037 case OP_LCOMPARE_IMM
: {
1038 MonoInst
*next
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
1039 guint32 low_imm
= tree
->inst_ls_word
;
1040 guint32 high_imm
= tree
->inst_ms_word
;
1041 int low_reg
= MONO_LVREG_LS (tree
->sreg1
);
1042 int high_reg
= MONO_LVREG_MS (tree
->sreg1
);
1046 switch (next
->opcode
) {
1051 /* Branchless version based on gcc code */
1052 d1
= alloc_ireg (cfg
);
1053 d2
= alloc_ireg (cfg
);
1054 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
1055 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
1056 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1057 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1058 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
1071 /* Convert into three comparisons + branches */
1072 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1073 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
1074 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1075 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
1076 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
1077 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
1083 /* Branchless version based on gcc code */
1084 d1
= alloc_ireg (cfg
);
1085 d2
= alloc_ireg (cfg
);
1086 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
1087 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
1088 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1090 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1091 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
1099 MonoBasicBlock
*set_to_0
, *set_to_1
;
1101 NEW_BBLOCK (cfg
, set_to_0
);
1102 NEW_BBLOCK (cfg
, set_to_1
);
1104 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
1105 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1106 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
1107 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1108 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
1109 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
1110 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
1111 MONO_START_BB (cfg
, set_to_1
);
1112 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
1113 MONO_START_BB (cfg
, set_to_0
);
1118 g_assert_not_reached ();
1127 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1130 /* Replace the original instruction with the new code sequence */
1132 /* Ignore the new value of prev */
1134 mono_replace_ins (cfg
, bb
, tree
, &new_prev
, first_bb
, cfg
->cbb
);
1136 /* Process the newly added ops again since they can be long ops too */
1138 tree
= mono_inst_next (prev
, FILTER_IL_SEQ_POINT
);
1140 tree
= mono_bb_first_inst (bb
, FILTER_IL_SEQ_POINT
);
1142 first_bb
->code
= first_bb
->last_ins
= NULL
;
1143 first_bb
->in_count
= first_bb
->out_count
= 0;
1144 cfg
->cbb
= first_bb
;
1148 tree
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
1155 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1156 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1161 * mono_decompose_vtype_opts:
1163 * Decompose valuetype opcodes.
1166 mono_decompose_vtype_opts (MonoCompile
*cfg
)
1168 MonoBasicBlock
*bb
, *first_bb
;
1171 * Using OP_V opcodes and decomposing them later have two main benefits:
1172 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1174 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1175 * enabling optimizations to work on vtypes too.
1176 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1177 * can be executed anytime. It should be executed as late as possible so vtype
1178 * opcodes can be optimized by the other passes.
1179 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1180 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1182 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1183 * when OP_VMOVE opcodes are decomposed.
1187 * Vregs have no associated type information, so we store the type of the vregs
1192 * Create a dummy bblock and emit code into it so we can use the normal
1193 * code generation macros.
1195 cfg
->cbb
= (MonoBasicBlock
*)mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1196 first_bb
= cfg
->cbb
;
1198 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1200 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1202 MonoInst
*prev
= NULL
;
1203 MonoInst
*src_var
, *dest_var
, *src
, *dest
;
1207 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "BEFORE LOWER-VTYPE-OPTS ");
1209 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1210 cfg
->cbb
->out_of_line
= bb
->out_of_line
;
1216 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1217 switch (ins
->opcode
) {
1219 g_assert (ins
->klass
);
1220 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1222 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1223 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1226 src_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->dreg
);
1229 dest_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->dreg
);
1232 if (src_var
->backend
.is_pinvoke
)
1233 dest_var
->backend
.is_pinvoke
= 1;
1235 EMIT_NEW_VARLOADA ((cfg
), (src
), src_var
, src_var
->inst_vtype
);
1236 EMIT_NEW_VARLOADA ((cfg
), (dest
), dest_var
, dest_var
->inst_vtype
);
1237 mini_emit_memory_copy (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
, 0);
1242 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1245 g_assert (ins
->klass
);
1247 EMIT_NEW_VARLOADA_VREG (cfg
, dest
, ins
->dreg
, m_class_get_byval_arg (ins
->klass
));
1248 mini_emit_initobj (cfg
, dest
, NULL
, ins
->klass
);
1250 if (cfg
->compute_gc_maps
) {
1254 * Tell the GC map code that the vtype is considered live after
1255 * the initialization.
1257 MONO_INST_NEW (cfg
, tmp
, OP_GC_LIVENESS_DEF
);
1258 tmp
->inst_c1
= ins
->dreg
;
1259 MONO_ADD_INS (cfg
->cbb
, tmp
);
1262 case OP_DUMMY_VZERO
:
1263 if (COMPILE_LLVM (cfg
))
1268 case OP_STOREV_MEMBASE
: {
1269 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1271 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
) && !cfg
->gen_write_barriers
)
1275 g_assert (ins
->klass
);
1276 src_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->sreg1
);
1279 EMIT_NEW_VARLOADA_VREG ((cfg
), (src
), ins
->sreg1
, m_class_get_byval_arg (ins
->klass
));
1281 dreg
= alloc_preg (cfg
);
1282 EMIT_NEW_BIALU_IMM (cfg
, dest
, OP_ADD_IMM
, dreg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1283 mini_emit_memory_copy (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
, 0);
1286 case OP_LOADV_MEMBASE
: {
1287 g_assert (ins
->klass
);
1288 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1291 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1295 dest_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->dreg
);
1297 dreg
= alloc_preg (cfg
);
1298 EMIT_NEW_BIALU_IMM (cfg
, src
, OP_ADD_IMM
, dreg
, ins
->inst_basereg
, ins
->inst_offset
);
1299 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1300 mini_emit_memory_copy (cfg
, dest
, src
, dest_var
->klass
, dest_var
->backend
.is_pinvoke
, 0);
1303 case OP_OUTARG_VT
: {
1304 if (COMPILE_LLVM (cfg
))
1307 g_assert (ins
->klass
);
1309 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1311 src_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->sreg1
);
1312 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1314 mono_arch_emit_outarg_vt (cfg
, ins
, src
);
1316 /* This might be decomposed into other vtype opcodes */
1320 case OP_OUTARG_VTRETADDR
: {
1321 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p1
;
1323 src_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1325 src_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1326 // FIXME: src_var->backend.is_pinvoke ?
1328 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1329 src
->dreg
= ins
->dreg
;
1334 case OP_VCALL_MEMBASE
: {
1335 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1338 if (COMPILE_LLVM (cfg
))
1341 if (call
->vret_in_reg
) {
1342 MonoCallInst
*call2
;
1344 /* Replace the vcall with a scalar call */
1345 MONO_INST_NEW_CALL (cfg
, call2
, OP_NOP
);
1346 memcpy (call2
, call
, sizeof (MonoCallInst
));
1347 switch (ins
->opcode
) {
1349 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL
: OP_CALL
;
1352 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL_REG
: OP_CALL_REG
;
1354 case OP_VCALL_MEMBASE
:
1355 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL_MEMBASE
: OP_CALL_MEMBASE
;
1358 call2
->inst
.dreg
= alloc_preg (cfg
);
1359 MONO_ADD_INS (cfg
->cbb
, ((MonoInst
*)call2
));
1361 /* Compute the vtype location */
1362 dest_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1364 dest_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1365 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1367 /* Save the result */
1368 if (dest_var
->backend
.is_pinvoke
)
1369 size
= mono_class_native_size (mono_class_from_mono_type (dest_var
->inst_vtype
), NULL
);
1371 size
= mono_type_size (dest_var
->inst_vtype
, NULL
);
1374 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI1_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1377 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI2_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1381 if (call
->vret_in_reg_fp
)
1382 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1384 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1390 if (call
->vret_in_reg_fp
) {
1391 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1394 #if SIZEOF_REGISTER == 4
1396 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1397 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1399 switch (call2
->inst
.opcode
) {
1401 call2
->inst
.opcode
= OP_LCALL
;
1404 call2
->inst
.opcode
= OP_LCALL_REG
;
1406 case OP_CALL_MEMBASE
:
1407 call2
->inst
.opcode
= OP_LCALL_MEMBASE
;
1410 call2
->inst
.dreg
= alloc_lreg (cfg
);
1411 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_MS_WORD_OFFSET
, MONO_LVREG_MS (call2
->inst
.dreg
));
1412 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_LS_WORD_OFFSET
, MONO_LVREG_LS (call2
->inst
.dreg
));
1414 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1418 /* This assumes the vtype is sizeof (gpointer) long */
1419 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1423 switch (ins
->opcode
) {
1425 ins
->opcode
= OP_VCALL2
;
1428 ins
->opcode
= OP_VCALL2_REG
;
1430 case OP_VCALL_MEMBASE
:
1431 ins
->opcode
= OP_VCALL2_MEMBASE
;
1439 case OP_BOX_ICONST
: {
1442 /* Temporary value required by emit_box () */
1443 if (ins
->opcode
== OP_BOX_ICONST
) {
1444 NEW_ICONST (cfg
, src
, ins
->inst_c0
);
1445 src
->klass
= ins
->klass
;
1446 MONO_ADD_INS (cfg
->cbb
, src
);
1448 MONO_INST_NEW (cfg
, src
, OP_LOCAL
);
1449 src
->type
= STACK_MP
;
1450 src
->klass
= ins
->klass
;
1451 src
->dreg
= ins
->sreg1
;
1453 MonoInst
*tmp
= mini_emit_box (cfg
, src
, ins
->klass
, mini_class_check_context_used (cfg
, ins
->klass
));
1456 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, tmp
->dreg
);
1458 /* This might be decomposed into other vtype opcodes */
1466 g_assert (cfg
->cbb
== first_bb
);
1468 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1469 /* Replace the original instruction with the new code sequence */
1471 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1472 first_bb
->code
= first_bb
->last_ins
= NULL
;
1473 first_bb
->in_count
= first_bb
->out_count
= 0;
1474 cfg
->cbb
= first_bb
;
1481 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "AFTER LOWER-VTYPE-OPTS ");
1485 inline static MonoInst
*
1486 mono_get_domainvar (MonoCompile
*cfg
)
1488 if (!cfg
->domainvar
)
1489 cfg
->domainvar
= mono_compile_create_var (cfg
, mono_get_int_type (), OP_LOCAL
);
1490 return cfg
->domainvar
;
1494 * mono_decompose_array_access_opts:
1496 * Decompose array access and other misc opcodes.
1499 mono_decompose_array_access_opts (MonoCompile
*cfg
)
1501 MonoBasicBlock
*bb
, *first_bb
;
1504 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1505 * can be executed anytime. It should be run before decompose_long
1509 * Create a dummy bblock and emit code into it so we can use the normal
1510 * code generation macros.
1512 cfg
->cbb
= (MonoBasicBlock
*)mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1513 first_bb
= cfg
->cbb
;
1515 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1517 MonoInst
*prev
= NULL
;
1519 MonoInst
*iargs
[3];
1522 if (!bb
->needs_decompose
)
1525 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1527 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1533 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1534 switch (ins
->opcode
) {
1535 case OP_TYPED_OBJREF
:
1536 ins
->opcode
= OP_MOVE
;
1539 NEW_LOAD_MEMBASE_FLAGS (cfg
, dest
, OP_LOADI4_MEMBASE
, ins
->dreg
, ins
->sreg1
,
1540 ins
->inst_imm
, ins
->flags
);
1541 MONO_ADD_INS (cfg
->cbb
, dest
);
1543 case OP_BOUNDS_CHECK
:
1544 MONO_EMIT_NULL_CHECK (cfg
, ins
->sreg1
, FALSE
);
1545 if (COMPILE_LLVM (cfg
)) {
1546 int index2_reg
= alloc_preg (cfg
);
1547 MONO_EMIT_NEW_UNALU (cfg
, OP_SEXT_I4
, index2_reg
, ins
->sreg2
);
1548 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, index2_reg
, ins
->flags
& MONO_INST_FAULT
);
1550 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, ins
->sreg2
);
1554 if (cfg
->opt
& MONO_OPT_SHARED
) {
1555 EMIT_NEW_DOMAINCONST (cfg
, iargs
[0]);
1556 EMIT_NEW_CLASSCONST (cfg
, iargs
[1], ins
->inst_newa_class
);
1557 MONO_INST_NEW (cfg
, iargs
[2], OP_MOVE
);
1558 iargs
[2]->dreg
= ins
->sreg1
;
1560 dest
= mono_emit_jit_icall (cfg
, ves_icall_array_new
, iargs
);
1561 dest
->dreg
= ins
->dreg
;
1563 MonoClass
*array_class
= mono_class_create_array (ins
->inst_newa_class
, 1);
1564 ERROR_DECL_VALUE (vt_error
);
1565 MonoVTable
*vtable
= mono_class_vtable_checked (cfg
->domain
, array_class
, &vt_error
);
1566 MonoMethod
*managed_alloc
= mono_gc_get_managed_array_allocator (array_class
);
1568 mono_error_assert_ok (&vt_error
); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1569 NEW_VTABLECONST (cfg
, iargs
[0], vtable
);
1570 MONO_ADD_INS (cfg
->cbb
, iargs
[0]);
1571 MONO_INST_NEW (cfg
, iargs
[1], OP_MOVE
);
1572 iargs
[1]->dreg
= ins
->sreg1
;
1575 dest
= mono_emit_method_call (cfg
, managed_alloc
, iargs
, NULL
);
1577 dest
= mono_emit_jit_icall (cfg
, ves_icall_array_new_specific
, iargs
);
1578 dest
->dreg
= ins
->dreg
;
1582 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg
, OP_LOADI4_MEMBASE
, ins
->dreg
,
1583 ins
->sreg1
, MONO_STRUCT_OFFSET (MonoString
, length
), ins
->flags
| MONO_INST_INVARIANT_LOAD
);
1589 g_assert (cfg
->cbb
== first_bb
);
1591 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1592 /* Replace the original instruction with the new code sequence */
1594 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1595 first_bb
->code
= first_bb
->last_ins
= NULL
;
1596 first_bb
->in_count
= first_bb
->out_count
= 0;
1597 cfg
->cbb
= first_bb
;
1604 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1614 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1617 * mono_decompose_soft_float:
1619 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1620 * similar to long support on 32 bit platforms. 32 bit float values require special
1621 * handling when used as locals, arguments, and in calls.
1622 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1625 mono_decompose_soft_float (MonoCompile
*cfg
)
1627 MonoBasicBlock
*bb
, *first_bb
;
1630 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1634 * Create a dummy bblock and emit code into it so we can use the normal
1635 * code generation macros.
1637 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1638 first_bb
= cfg
->cbb
;
1640 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1642 MonoInst
*prev
= NULL
;
1645 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE HANDLE-SOFT-FLOAT ");
1647 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1653 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1654 const char *spec
= INS_INFO (ins
->opcode
);
1656 /* Most fp operations are handled automatically by opcode emulation */
1658 switch (ins
->opcode
) {
1661 d
.vald
= *(double*)ins
->inst_p0
;
1662 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1667 /* We load the r8 value */
1668 d
.vald
= *(float*)ins
->inst_p0
;
1669 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1673 ins
->opcode
= OP_LMOVE
;
1676 ins
->opcode
= OP_MOVE
;
1677 ins
->sreg1
= MONO_LVREG_LS (ins
->sreg1
);
1680 ins
->opcode
= OP_MOVE
;
1681 ins
->sreg1
= MONO_LVREG_MS (ins
->sreg1
);
1684 int reg
= ins
->sreg1
;
1686 ins
->opcode
= OP_SETLRET
;
1688 ins
->sreg1
= MONO_LVREG_LS (reg
);
1689 ins
->sreg2
= MONO_LVREG_MS (reg
);
1692 case OP_LOADR8_MEMBASE
:
1693 ins
->opcode
= OP_LOADI8_MEMBASE
;
1695 case OP_STORER8_MEMBASE_REG
:
1696 ins
->opcode
= OP_STOREI8_MEMBASE_REG
;
1698 case OP_STORER4_MEMBASE_REG
: {
1699 MonoInst
*iargs
[2];
1702 /* Arg 1 is the double value */
1703 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1704 iargs
[0]->dreg
= ins
->sreg1
;
1706 /* Arg 2 is the address to store to */
1707 addr_reg
= mono_alloc_preg (cfg
);
1708 EMIT_NEW_BIALU_IMM (cfg
, iargs
[1], OP_PADD_IMM
, addr_reg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1709 mono_emit_jit_icall (cfg
, mono_fstore_r4
, iargs
);
1713 case OP_LOADR4_MEMBASE
: {
1714 MonoInst
*iargs
[1];
1718 addr_reg
= mono_alloc_preg (cfg
);
1719 EMIT_NEW_BIALU_IMM (cfg
, iargs
[0], OP_PADD_IMM
, addr_reg
, ins
->inst_basereg
, ins
->inst_offset
);
1720 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1721 conv
->dreg
= ins
->dreg
;
1726 case OP_FCALL_MEMBASE
: {
1727 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1728 if (call
->signature
->ret
->type
== MONO_TYPE_R4
) {
1729 MonoCallInst
*call2
;
1730 MonoInst
*iargs
[1];
1734 /* Convert the call into a call returning an int */
1735 MONO_INST_NEW_CALL (cfg
, call2
, OP_CALL
);
1736 memcpy (call2
, call
, sizeof (MonoCallInst
));
1737 switch (ins
->opcode
) {
1739 call2
->inst
.opcode
= OP_CALL
;
1742 call2
->inst
.opcode
= OP_CALL_REG
;
1744 case OP_FCALL_MEMBASE
:
1745 call2
->inst
.opcode
= OP_CALL_MEMBASE
;
1748 g_assert_not_reached ();
1750 call2
->inst
.dreg
= mono_alloc_ireg (cfg
);
1751 MONO_ADD_INS (cfg
->cbb
, (MonoInst
*)call2
);
1753 /* Remap OUTARG_VT instructions referencing this call */
1754 for (l
= call
->outarg_vts
; l
; l
= l
->next
)
1755 ((MonoInst
*)(l
->data
))->inst_p0
= call2
;
1757 /* FIXME: Optimize this */
1759 /* Emit an r4->r8 conversion */
1760 EMIT_NEW_VARLOADA_VREG (cfg
, iargs
[0], call2
->inst
.dreg
, mono_get_int32_type ());
1761 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1762 conv
->dreg
= ins
->dreg
;
1764 /* The call sequence might include fp ins */
1767 switch (ins
->opcode
) {
1769 ins
->opcode
= OP_LCALL
;
1772 ins
->opcode
= OP_LCALL_REG
;
1774 case OP_FCALL_MEMBASE
:
1775 ins
->opcode
= OP_LCALL_MEMBASE
;
1778 g_assert_not_reached ();
1784 MonoJitICallInfo
*info
;
1785 MonoInst
*iargs
[2];
1786 MonoInst
*call
, *cmp
, *br
;
1788 /* Convert fcompare+fbcc to icall+icompare+beq */
1791 /* The branch might be optimized away */
1796 info
= mono_find_jit_opcode_emulation (ins
->next
->opcode
);
1798 /* The branch might be optimized away */
1803 /* Create dummy MonoInst's for the arguments */
1804 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1805 iargs
[0]->dreg
= ins
->sreg1
;
1806 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1807 iargs
[1]->dreg
= ins
->sreg2
;
1809 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, iargs
);
1811 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1812 cmp
->sreg1
= call
->dreg
;
1814 MONO_ADD_INS (cfg
->cbb
, cmp
);
1816 MONO_INST_NEW (cfg
, br
, OP_IBNE_UN
);
1817 br
->inst_many_bb
= mono_mempool_alloc (cfg
->mempool
, sizeof (gpointer
) * 2);
1818 br
->inst_true_bb
= ins
->next
->inst_true_bb
;
1819 br
->inst_false_bb
= ins
->next
->inst_false_bb
;
1820 MONO_ADD_INS (cfg
->cbb
, br
);
1822 /* The call sequence might include fp ins */
1825 /* Skip fbcc or fccc */
1826 NULLIFY_INS (ins
->next
);
1834 MonoJitICallInfo
*info
;
1835 MonoInst
*iargs
[2];
1838 /* Convert fccc to icall+icompare+iceq */
1840 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
1843 /* Create dummy MonoInst's for the arguments */
1844 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1845 iargs
[0]->dreg
= ins
->sreg1
;
1846 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1847 iargs
[1]->dreg
= ins
->sreg2
;
1849 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, iargs
);
1851 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, call
->dreg
, 1);
1852 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, ins
->dreg
, -1);
1854 /* The call sequence might include fp ins */
1859 MonoInst
*iargs
[2];
1860 MonoInst
*call
, *cmp
;
1862 /* Convert to icall+icompare+cond_exc+move */
1864 /* Create dummy MonoInst's for the arguments */
1865 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1866 iargs
[0]->dreg
= ins
->sreg1
;
1868 call
= mono_emit_jit_icall (cfg
, mono_isfinite
, iargs
);
1870 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1871 cmp
->sreg1
= call
->dreg
;
1873 MONO_ADD_INS (cfg
->cbb
, cmp
);
1875 MONO_EMIT_NEW_COND_EXC (cfg
, INE_UN
, "ArithmeticException");
1877 /* Do the assignment if the value is finite */
1878 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, ins
->dreg
, ins
->sreg1
);
1884 if (spec
[MONO_INST_SRC1
] == 'f' || spec
[MONO_INST_SRC2
] == 'f' || spec
[MONO_INST_DEST
] == 'f') {
1885 mono_print_ins (ins
);
1886 g_assert_not_reached ();
1891 g_assert (cfg
->cbb
== first_bb
);
1893 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1894 /* Replace the original instruction with the new code sequence */
1896 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1897 first_bb
->code
= first_bb
->last_ins
= NULL
;
1898 first_bb
->in_count
= first_bb
->out_count
= 0;
1899 cfg
->cbb
= first_bb
;
1906 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER HANDLE-SOFT-FLOAT ");
1909 mono_decompose_long_opts (cfg
);
1915 mono_local_emulate_ops (MonoCompile
*cfg
)
1918 gboolean inlined_wrapper
= FALSE
;
1920 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1923 MONO_BB_FOR_EACH_INS (bb
, ins
) {
1924 int op_noimm
= mono_op_imm_to_op (ins
->opcode
);
1925 MonoJitICallInfo
*info
;
1928 * These opcodes don't have logical equivalence to the emulating native
1929 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1931 if (MONO_HAS_CUSTOM_EMULATION (ins
))
1935 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1936 * to check whether its non-imm counterpart is emulated and, if so,
1937 * decompose it back to its non-imm counterpart.
1940 info
= mono_find_jit_opcode_emulation (op_noimm
);
1942 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
1947 MonoBasicBlock
*first_bb
;
1949 /* Create dummy MonoInst's for the arguments */
1950 g_assert (!info
->sig
->hasthis
);
1951 g_assert (info
->sig
->param_count
<= MONO_MAX_SRC_REGS
);
1954 mono_decompose_op_imm (cfg
, bb
, ins
);
1956 args
= (MonoInst
**)mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
*) * info
->sig
->param_count
);
1957 if (info
->sig
->param_count
> 0) {
1958 int sregs
[MONO_MAX_SRC_REGS
];
1960 num_sregs
= mono_inst_get_src_registers (ins
, sregs
);
1961 g_assert (num_sregs
== info
->sig
->param_count
);
1962 for (i
= 0; i
< num_sregs
; ++i
) {
1963 MONO_INST_NEW (cfg
, args
[i
], OP_ARG
);
1964 args
[i
]->dreg
= sregs
[i
];
1968 /* We emit the call on a separate dummy basic block */
1969 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1970 first_bb
= cfg
->cbb
;
1972 call
= mono_emit_jit_icall_by_info (cfg
, bb
->real_offset
, info
, args
);
1973 call
->dreg
= ins
->dreg
;
1975 /* Replace ins with the emitted code and do the necessary bb linking */
1976 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1977 MonoInst
*saved_prev
= ins
->prev
;
1979 mono_replace_ins (cfg
, bb
, ins
, &ins
->prev
, first_bb
, cfg
->cbb
);
1980 first_bb
->code
= first_bb
->last_ins
= NULL
;
1981 first_bb
->in_count
= first_bb
->out_count
= 0;
1982 cfg
->cbb
= first_bb
;
1984 /* ins is hanging, continue scanning the emitted code */
1987 g_error ("Failed to emit emulation code");
1989 inlined_wrapper
= TRUE
;
1995 * Avoid rerunning these passes by emitting directly the exception checkpoint
1996 * at IR level, instead of inlining the icall wrapper. FIXME
1998 if (inlined_wrapper
) {
1999 if (!COMPILE_LLVM (cfg
))
2000 mono_decompose_long_opts (cfg
);
2001 if (cfg
->opt
& (MONO_OPT_CONSPROP
| MONO_OPT_COPYPROP
))
2002 mono_local_cprop (cfg
);
2006 #else /* !DISABLE_JIT */
2008 MONO_EMPTY_SOURCE_FILE (decompose
);
2010 #endif /* !DISABLE_JIT */