2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 #include "jit-icalls.h"
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/metadata/abi-details.h>
18 #include <mono/utils/mono-compiler.h>
22 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
23 MONO_API MonoInst
* mono_emit_native_call (MonoCompile
*cfg
, gconstpointer func
, MonoMethodSignature
*sig
, MonoInst
**args
);
24 void mini_emit_stobj (MonoCompile
*cfg
, MonoInst
*dest
, MonoInst
*src
, MonoClass
*klass
, gboolean native
);
25 void mini_emit_initobj (MonoCompile
*cfg
, MonoInst
*dest
, const guchar
*ip
, MonoClass
*klass
);
28 * Decompose complex long opcodes on 64 bit machines.
29 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
32 decompose_long_opcode (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
**repl_ins
)
34 MonoInst
*repl
= NULL
;
38 switch (ins
->opcode
) {
40 ins
->opcode
= OP_SEXT_I4
;
44 if (SIZEOF_VOID_P
== 4)
45 ins
->opcode
= OP_LMOVE
;
47 ins
->opcode
= OP_MOVE
;
50 if (SIZEOF_VOID_P
== 4)
52 ins
->opcode
= OP_SEXT_I4
;
54 ins
->opcode
= OP_MOVE
;
57 if (SIZEOF_VOID_P
== 4) {
59 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
62 ins
->opcode
= OP_MOVE
;
66 ins
->opcode
= OP_SEXT_I4
;
69 ins
->opcode
= OP_ZEXT_I4
;
72 /* Clean out the upper word */
73 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
79 if (COMPILE_LLVM (cfg
))
81 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
85 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
86 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
90 case OP_LADD_OVF_UN
: {
93 if (COMPILE_LLVM (cfg
))
95 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
99 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
100 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
104 #ifndef __mono_ppc64__
108 if (COMPILE_LLVM (cfg
))
110 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
114 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
115 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
119 case OP_LSUB_OVF_UN
: {
122 if (COMPILE_LLVM (cfg
))
124 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
128 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
129 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
135 case OP_ICONV_TO_OVF_I8
:
136 case OP_ICONV_TO_OVF_I
:
137 ins
->opcode
= OP_SEXT_I4
;
139 case OP_ICONV_TO_OVF_U8
:
140 case OP_ICONV_TO_OVF_U
:
141 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
,ins
->sreg1
, 0);
142 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
143 MONO_EMIT_NEW_UNALU (cfg
, OP_ZEXT_I4
, ins
->dreg
, ins
->sreg1
);
146 case OP_ICONV_TO_OVF_I8_UN
:
147 case OP_ICONV_TO_OVF_U8_UN
:
148 case OP_ICONV_TO_OVF_I_UN
:
149 case OP_ICONV_TO_OVF_U_UN
:
150 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
151 /* Clean out the upper word */
152 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
155 case OP_LCONV_TO_OVF_I1
:
156 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 127);
157 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
158 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -128);
159 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
160 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
163 case OP_LCONV_TO_OVF_I1_UN
:
164 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 127);
165 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
166 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
169 case OP_LCONV_TO_OVF_U1
:
170 /* probe value to be within 0 to 255 */
171 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 255);
172 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
173 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
176 case OP_LCONV_TO_OVF_U1_UN
:
177 /* probe value to be within 0 to 255 */
178 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 255);
179 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
180 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
183 case OP_LCONV_TO_OVF_I2
:
184 /* Probe value to be within -32768 and 32767 */
185 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
186 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
187 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
188 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
189 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
192 case OP_LCONV_TO_OVF_I2_UN
:
193 /* Probe value to be within 0 and 32767 */
194 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
195 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
196 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
199 case OP_LCONV_TO_OVF_U2
:
200 /* Probe value to be within 0 and 65535 */
201 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
202 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
203 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
206 case OP_LCONV_TO_OVF_U2_UN
:
207 /* Probe value to be within 0 and 65535 */
208 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
209 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
210 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
213 case OP_LCONV_TO_OVF_I4
:
214 #if SIZEOF_VOID_P == 4
215 case OP_LCONV_TO_OVF_I
:
217 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
218 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
219 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
220 #if SIZEOF_REGISTER == 8
221 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, ((int)-2147483648));
223 g_assert (COMPILE_LLVM (cfg
));
224 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -2147483648LL);
226 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
227 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
230 case OP_LCONV_TO_OVF_I4_UN
:
231 #if SIZEOF_VOID_P == 4
232 case OP_LCONV_TO_OVF_I_UN
:
234 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
235 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
236 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
239 case OP_LCONV_TO_OVF_U4
:
240 #if SIZEOF_VOID_P == 4
241 case OP_LCONV_TO_OVF_U
:
243 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffffUL
);
244 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
245 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
246 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
247 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
250 case OP_LCONV_TO_OVF_U4_UN
:
251 #if SIZEOF_VOID_P == 4
252 case OP_LCONV_TO_OVF_U_UN
:
254 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffff);
255 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
256 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
259 #if SIZEOF_VOID_P == 8
260 case OP_LCONV_TO_OVF_I
:
261 case OP_LCONV_TO_OVF_U_UN
:
263 case OP_LCONV_TO_OVF_U8_UN
:
264 case OP_LCONV_TO_OVF_I8
:
265 ins
->opcode
= OP_MOVE
;
267 #if SIZEOF_VOID_P == 8
268 case OP_LCONV_TO_OVF_I_UN
:
270 case OP_LCONV_TO_OVF_I8_UN
:
271 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
272 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
273 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
276 case OP_LCONV_TO_OVF_U8
:
277 #if SIZEOF_VOID_P == 8
278 case OP_LCONV_TO_OVF_U
:
280 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
281 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
282 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
294 * mono_decompose_opcode:
296 * Decompose complex opcodes into ones closer to opcodes supported by
297 * the given architecture.
298 * Returns a MonoInst which represents the result of the decomposition, and can
299 * be pushed on the IL stack. This is needed because the original instruction is
301 * Sets the cfg exception if an opcode is not supported.
304 mono_decompose_opcode (MonoCompile
*cfg
, MonoInst
*ins
)
306 MonoInst
*repl
= NULL
;
307 int type
= ins
->type
;
308 int dreg
= ins
->dreg
;
309 gboolean emulate
= FALSE
;
311 /* FIXME: Instead of = NOP, don't emit the original ins at all */
312 mono_arch_decompose_opts (cfg
, ins
);
315 * The code below assumes that we are called immediately after emitting
316 * ins. This means we can emit code using the normal code generation
319 switch (ins
->opcode
) {
320 /* this doesn't make sense on ppc and other architectures */
321 #if !defined(MONO_ARCH_NO_IOV_CHECK)
323 if (COMPILE_LLVM (cfg
))
325 ins
->opcode
= OP_IADDCC
;
326 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
329 if (COMPILE_LLVM (cfg
))
331 ins
->opcode
= OP_IADDCC
;
332 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
335 if (COMPILE_LLVM (cfg
))
337 ins
->opcode
= OP_ISUBCC
;
338 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
341 if (COMPILE_LLVM (cfg
))
343 ins
->opcode
= OP_ISUBCC
;
344 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
347 case OP_ICONV_TO_OVF_I1
:
348 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
349 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
350 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -128);
351 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
352 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
355 case OP_ICONV_TO_OVF_I1_UN
:
356 /* probe values between 0 to 127 */
357 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
358 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
359 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
362 case OP_ICONV_TO_OVF_U1
:
363 case OP_ICONV_TO_OVF_U1_UN
:
364 /* probe value to be within 0 to 255 */
365 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 255);
366 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
367 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
370 case OP_ICONV_TO_OVF_I2
:
371 /* Probe value to be within -32768 and 32767 */
372 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
373 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
374 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
375 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
376 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
379 case OP_ICONV_TO_OVF_I2_UN
:
380 /* Convert uint value into short, value within 0 and 32767 */
381 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
382 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
383 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
386 case OP_ICONV_TO_OVF_U2
:
387 case OP_ICONV_TO_OVF_U2_UN
:
388 /* Probe value to be within 0 and 65535 */
389 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
390 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
391 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
394 case OP_ICONV_TO_OVF_U4
:
395 case OP_ICONV_TO_OVF_I4_UN
:
396 #if SIZEOF_VOID_P == 4
397 case OP_ICONV_TO_OVF_U
:
398 case OP_ICONV_TO_OVF_I_UN
:
400 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0);
401 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
402 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
407 case OP_ICONV_TO_OVF_I4
:
408 case OP_ICONV_TO_OVF_U4_UN
:
409 #if SIZEOF_VOID_P == 4
410 case OP_ICONV_TO_OVF_I
:
411 case OP_ICONV_TO_OVF_U_UN
:
413 ins
->opcode
= OP_MOVE
;
416 #if SIZEOF_VOID_P == 8
417 ins
->opcode
= OP_SEXT_I4
;
419 ins
->opcode
= OP_MOVE
;
423 #if SIZEOF_VOID_P == 8
424 ins
->opcode
= OP_ZEXT_I4
;
426 ins
->opcode
= OP_MOVE
;
431 ins
->opcode
= OP_FMOVE
;
434 case OP_FCONV_TO_OVF_I1_UN
:
435 case OP_FCONV_TO_OVF_I2_UN
:
436 case OP_FCONV_TO_OVF_I4_UN
:
437 case OP_FCONV_TO_OVF_I8_UN
:
438 case OP_FCONV_TO_OVF_U1_UN
:
439 case OP_FCONV_TO_OVF_U2_UN
:
440 case OP_FCONV_TO_OVF_U4_UN
:
441 case OP_FCONV_TO_OVF_U8_UN
:
442 case OP_FCONV_TO_OVF_I_UN
:
443 case OP_FCONV_TO_OVF_U_UN
:
444 mono_cfg_set_exception_invalid_program (cfg
, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
451 if (cfg
->backend
->emulate_div
&& mono_arch_opcode_needs_emulation (cfg
, ins
->opcode
))
454 if (cfg
->backend
->need_div_check
) {
455 int reg1
= alloc_ireg (cfg
);
456 int reg2
= alloc_ireg (cfg
);
458 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg2
, 0);
459 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
460 if (ins
->opcode
== OP_IDIV
|| ins
->opcode
== OP_IREM
) {
461 /* b == -1 && a == 0x80000000 */
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg2
, -1);
463 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, reg1
, -1);
464 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0x80000000);
465 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, reg2
, -1);
466 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, reg1
, reg1
, reg2
);
467 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 1);
468 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
471 MONO_EMIT_NEW_BIALU (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
476 #if SIZEOF_VOID_P == 8
481 if (cfg
->backend
->emulate_div
&& mono_arch_opcode_needs_emulation (cfg
, ins
->opcode
))
484 if (cfg
->backend
->need_div_check
) {
485 int reg1
= alloc_ireg (cfg
);
486 int reg2
= alloc_ireg (cfg
);
487 int reg3
= alloc_ireg (cfg
);
489 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg2
, 0);
490 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
491 if (ins
->opcode
== OP_LDIV
|| ins
->opcode
== OP_LREM
) {
492 /* b == -1 && a == 0x80000000 */
493 MONO_EMIT_NEW_I8CONST (cfg
, reg3
, -1);
494 MONO_EMIT_NEW_BIALU (cfg
, OP_LCOMPARE
, -1, ins
->sreg2
, reg3
);
495 MONO_EMIT_NEW_UNALU (cfg
, OP_LCEQ
, reg1
, -1);
496 MONO_EMIT_NEW_I8CONST (cfg
, reg3
, 0x8000000000000000L
);
497 MONO_EMIT_NEW_BIALU (cfg
, OP_LCOMPARE
, -1, ins
->sreg1
, reg3
);
498 MONO_EMIT_NEW_UNALU (cfg
, OP_LCEQ
, reg2
, -1);
499 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, reg1
, reg1
, reg2
);
500 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 1);
501 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
504 MONO_EMIT_NEW_BIALU (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
516 if (cfg
->backend
->need_div_check
) {
517 int reg1
= alloc_ireg (cfg
);
519 if (ins
->inst_imm
== 0) {
520 // FIXME: Optimize this
521 MONO_EMIT_NEW_ICONST (cfg
, reg1
, 0);
522 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 0);
523 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
525 if ((ins
->opcode
== OP_DIV_IMM
|| ins
->opcode
== OP_IDIV_IMM
|| ins
->opcode
== OP_REM_IMM
|| ins
->opcode
== OP_IREM_IMM
) &&
526 (ins
->inst_imm
== -1)) {
527 /* b == -1 && a == 0x80000000 */
528 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0x80000000);
529 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
531 MONO_EMIT_NEW_BIALU_IMM (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
544 #if SIZEOF_REGISTER == 8
545 if (decompose_long_opcode (cfg
, ins
, &repl
))
548 if (COMPILE_LLVM (cfg
) && decompose_long_opcode (cfg
, ins
, &repl
))
552 if (emulate
&& mono_find_jit_opcode_emulation (ins
->opcode
))
553 cfg
->has_emulated_ops
= TRUE
;
556 if (ins
->opcode
== OP_NOP
) {
561 /* Use the last emitted instruction */
562 ins
= cfg
->cbb
->last_ins
;
565 g_assert (ins
->dreg
== dreg
);
573 #if SIZEOF_REGISTER == 4
574 static int lbr_decomp
[][2] = {
576 {OP_IBGT
, OP_IBGE_UN
}, /* BGE */
577 {OP_IBGT
, OP_IBGT_UN
}, /* BGT */
578 {OP_IBLT
, OP_IBLE_UN
}, /* BLE */
579 {OP_IBLT
, OP_IBLT_UN
}, /* BLT */
581 {OP_IBGT_UN
, OP_IBGE_UN
}, /* BGE_UN */
582 {OP_IBGT_UN
, OP_IBGT_UN
}, /* BGT_UN */
583 {OP_IBLT_UN
, OP_IBLE_UN
}, /* BLE_UN */
584 {OP_IBLT_UN
, OP_IBLT_UN
}, /* BLT_UN */
587 static int lcset_decomp
[][2] = {
589 {OP_IBLT
, OP_IBLE_UN
}, /* CGT */
590 {OP_IBLT_UN
, OP_IBLE_UN
}, /* CGT_UN */
591 {OP_IBGT
, OP_IBGE_UN
}, /* CLT */
592 {OP_IBGT_UN
, OP_IBGE_UN
}, /* CLT_UN */
597 * mono_decompose_long_opts:
599 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
602 mono_decompose_long_opts (MonoCompile
*cfg
)
604 #if SIZEOF_REGISTER == 4
605 MonoBasicBlock
*bb
, *first_bb
;
608 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
609 * needs to be able to handle long vregs.
613 * Create a dummy bblock and emit code into it so we can use the normal
614 * code generation macros.
616 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
619 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
620 MonoInst
*tree
= mono_bb_first_inst(bb
, FILTER_IL_SEQ_POINT
);
621 MonoInst
*prev
= NULL
;
624 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
627 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
630 mono_arch_decompose_long_opts (cfg
, tree
);
632 switch (tree
->opcode
) {
634 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_LS (tree
->dreg
), tree
->inst_ls_word
);
635 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), tree
->inst_ms_word
);
637 case OP_DUMMY_I8CONST
:
638 MONO_EMIT_NEW_DUMMY_INIT (cfg
, MONO_LVREG_LS (tree
->dreg
), OP_DUMMY_ICONST
);
639 MONO_EMIT_NEW_DUMMY_INIT (cfg
, MONO_LVREG_MS (tree
->dreg
), OP_DUMMY_ICONST
);
644 case OP_LCONV_TO_OVF_U8_UN
:
645 case OP_LCONV_TO_OVF_I8
:
646 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
647 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
649 case OP_STOREI8_MEMBASE_REG
:
650 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
));
651 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
));
653 case OP_LOADI8_MEMBASE
:
654 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
);
655 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
);
658 case OP_ICONV_TO_I8
: {
659 guint32 tmpreg
= alloc_ireg (cfg
);
663 * tmp = low > -1 ? 1: 0;
664 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
666 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
667 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, MONO_LVREG_LS (tree
->dreg
), -1);
668 MONO_EMIT_NEW_BIALU (cfg
, OP_ICGT
, tmpreg
, -1, -1);
669 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, MONO_LVREG_MS (tree
->dreg
), tmpreg
, 1);
673 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
674 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
676 case OP_ICONV_TO_OVF_I8
:
677 /* a signed 32 bit num always fits in a signed 64 bit one */
678 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, MONO_LVREG_MS (tree
->dreg
), tree
->sreg1
, 31);
679 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
681 case OP_ICONV_TO_OVF_U8
:
682 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
, 0);
683 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
684 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
685 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
687 case OP_ICONV_TO_OVF_I8_UN
:
688 case OP_ICONV_TO_OVF_U8_UN
:
689 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
690 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
691 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
694 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
697 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
700 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
703 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
709 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
711 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
713 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R8_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
716 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
718 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R4_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
721 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
722 case OP_LCONV_TO_R_UN
:
723 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R_UN_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
726 case OP_LCONV_TO_OVF_I1
: {
727 MonoBasicBlock
*is_negative
, *end_label
;
729 NEW_BBLOCK (cfg
, is_negative
);
730 NEW_BBLOCK (cfg
, end_label
);
732 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
733 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
734 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), -1);
735 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
737 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
738 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
741 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 127);
742 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
743 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
746 MONO_START_BB (cfg
, is_negative
);
747 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -128);
748 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
750 MONO_START_BB (cfg
, end_label
);
752 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
755 case OP_LCONV_TO_OVF_I1_UN
:
756 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
757 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
759 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 127);
760 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
761 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -128);
762 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
763 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
765 case OP_LCONV_TO_OVF_U1
:
766 case OP_LCONV_TO_OVF_U1_UN
:
767 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
768 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
770 /* probe value to be within 0 to 255 */
771 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 255);
772 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
773 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), 0xff);
775 case OP_LCONV_TO_OVF_I2
: {
776 MonoBasicBlock
*is_negative
, *end_label
;
778 NEW_BBLOCK (cfg
, is_negative
);
779 NEW_BBLOCK (cfg
, end_label
);
781 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
782 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
783 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), -1);
784 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
786 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
787 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
790 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 32767);
791 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
792 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
795 MONO_START_BB (cfg
, is_negative
);
796 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -32768);
797 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
798 MONO_START_BB (cfg
, end_label
);
800 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
803 case OP_LCONV_TO_OVF_I2_UN
:
804 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
805 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
807 /* Probe value to be within -32768 and 32767 */
808 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 32767);
809 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
810 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -32768);
811 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
812 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
814 case OP_LCONV_TO_OVF_U2
:
815 case OP_LCONV_TO_OVF_U2_UN
:
816 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
817 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
819 /* Probe value to be within 0 and 65535 */
820 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 0xffff);
821 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
822 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), 0xffff);
824 case OP_LCONV_TO_OVF_I4
:
825 case OP_LCONV_TO_OVF_I
:
826 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_OVF_I4_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
828 case OP_LCONV_TO_OVF_U4
:
829 case OP_LCONV_TO_OVF_U
:
830 case OP_LCONV_TO_OVF_U4_UN
:
831 case OP_LCONV_TO_OVF_U_UN
:
832 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
833 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
834 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
836 case OP_LCONV_TO_OVF_I_UN
:
837 case OP_LCONV_TO_OVF_I4_UN
:
838 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
839 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
840 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_LS (tree
->sreg1
), 0);
841 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
842 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
844 case OP_LCONV_TO_OVF_U8
:
845 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
846 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
848 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
849 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
851 case OP_LCONV_TO_OVF_I8_UN
:
852 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
853 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
855 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
856 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
860 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
861 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
864 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
865 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
869 /* ADC sets the condition code */
870 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
871 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
872 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
875 /* ADC sets the condition code */
876 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
877 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
878 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
881 /* SBB sets the condition code */
882 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
883 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
884 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
887 /* SBB sets the condition code */
888 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
889 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
890 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
893 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
894 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
897 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
898 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
901 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
902 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
905 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
906 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
909 /* Handled in mono_arch_decompose_long_opts () */
910 g_assert_not_reached ();
914 /* FIXME: Add OP_BIGMUL optimization */
918 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADDCC_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
919 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADC_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
922 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SUBCC_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
923 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SBB_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
926 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
927 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
930 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
931 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
934 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), tree
->inst_ls_word
);
935 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), tree
->inst_ms_word
);
937 #ifdef TARGET_POWERPC
938 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
940 if (tree
->inst_c1
== 32) {
942 /* The original code had this comment: */
943 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
944 * later apply the speedup to the left shift as well
947 /* just move the upper half to the lower and zero the high word */
948 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
949 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
954 MonoInst
*next
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
958 switch (next
->opcode
) {
963 /* Branchless version based on gcc code */
964 d1
= alloc_ireg (cfg
);
965 d2
= alloc_ireg (cfg
);
966 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
967 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
968 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
969 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
970 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
982 /* Convert into three comparisons + branches */
983 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
984 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
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
, OP_IBNE_UN
, next
->inst_false_bb
);
987 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
988 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
994 /* Branchless version based on gcc code */
995 d1
= alloc_ireg (cfg
);
996 d2
= alloc_ireg (cfg
);
997 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
998 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
999 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1001 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1002 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
1010 MonoBasicBlock
*set_to_0
, *set_to_1
;
1012 NEW_BBLOCK (cfg
, set_to_0
);
1013 NEW_BBLOCK (cfg
, set_to_1
);
1015 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
1016 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
1017 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_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
, OP_IBNE_UN
, set_to_1
);
1020 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
1021 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
1022 MONO_START_BB (cfg
, set_to_1
);
1023 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
1024 MONO_START_BB (cfg
, set_to_0
);
1029 g_assert_not_reached ();
1034 /* Not yet used, since lcompare is decomposed before local cprop */
1035 case OP_LCOMPARE_IMM
: {
1036 MonoInst
*next
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
1037 guint32 low_imm
= tree
->inst_ls_word
;
1038 guint32 high_imm
= tree
->inst_ms_word
;
1039 int low_reg
= MONO_LVREG_LS (tree
->sreg1
);
1040 int high_reg
= MONO_LVREG_MS (tree
->sreg1
);
1044 switch (next
->opcode
) {
1049 /* Branchless version based on gcc code */
1050 d1
= alloc_ireg (cfg
);
1051 d2
= alloc_ireg (cfg
);
1052 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
1053 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
1054 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1055 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1056 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
1069 /* Convert into three comparisons + branches */
1070 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1071 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
1072 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1073 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
1074 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
1075 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
1081 /* Branchless version based on gcc code */
1082 d1
= alloc_ireg (cfg
);
1083 d2
= alloc_ireg (cfg
);
1084 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
1085 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
1086 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1088 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1089 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
1097 MonoBasicBlock
*set_to_0
, *set_to_1
;
1099 NEW_BBLOCK (cfg
, set_to_0
);
1100 NEW_BBLOCK (cfg
, set_to_1
);
1102 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
1103 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1104 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
1105 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1106 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
1107 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
1108 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
1109 MONO_START_BB (cfg
, set_to_1
);
1110 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
1111 MONO_START_BB (cfg
, set_to_0
);
1116 g_assert_not_reached ();
1125 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1128 /* Replace the original instruction with the new code sequence */
1130 /* Ignore the new value of prev */
1132 mono_replace_ins (cfg
, bb
, tree
, &new_prev
, first_bb
, cfg
->cbb
);
1134 /* Process the newly added ops again since they can be long ops too */
1136 tree
= mono_inst_next (prev
, FILTER_IL_SEQ_POINT
);
1138 tree
= mono_bb_first_inst (bb
, FILTER_IL_SEQ_POINT
);
1140 first_bb
->code
= first_bb
->last_ins
= NULL
;
1141 first_bb
->in_count
= first_bb
->out_count
= 0;
1142 cfg
->cbb
= first_bb
;
1146 tree
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
1153 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1154 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1159 * mono_decompose_vtype_opts:
1161 * Decompose valuetype opcodes.
1164 mono_decompose_vtype_opts (MonoCompile
*cfg
)
1166 MonoBasicBlock
*bb
, *first_bb
;
1169 * Using OP_V opcodes and decomposing them later have two main benefits:
1170 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1172 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1173 * enabling optimizations to work on vtypes too.
1174 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1175 * can be executed anytime. It should be executed as late as possible so vtype
1176 * opcodes can be optimized by the other passes.
1177 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1178 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1180 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1181 * when OP_VMOVE opcodes are decomposed.
1185 * Vregs have no associated type information, so we store the type of the vregs
1190 * Create a dummy bblock and emit code into it so we can use the normal
1191 * code generation macros.
1193 cfg
->cbb
= (MonoBasicBlock
*)mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1194 first_bb
= cfg
->cbb
;
1196 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1198 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1200 MonoInst
*prev
= NULL
;
1201 MonoInst
*src_var
, *dest_var
, *src
, *dest
;
1205 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "BEFORE LOWER-VTYPE-OPTS ");
1207 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1213 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1214 switch (ins
->opcode
) {
1216 g_assert (ins
->klass
);
1217 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1219 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1220 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1223 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1226 dest_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1229 if (src_var
->backend
.is_pinvoke
)
1230 dest_var
->backend
.is_pinvoke
= 1;
1232 EMIT_NEW_VARLOADA ((cfg
), (src
), src_var
, src_var
->inst_vtype
);
1233 EMIT_NEW_VARLOADA ((cfg
), (dest
), dest_var
, dest_var
->inst_vtype
);
1235 mini_emit_stobj (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
);
1239 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1242 g_assert (ins
->klass
);
1244 EMIT_NEW_VARLOADA_VREG (cfg
, dest
, ins
->dreg
, &ins
->klass
->byval_arg
);
1245 mini_emit_initobj (cfg
, dest
, NULL
, ins
->klass
);
1247 if (cfg
->compute_gc_maps
) {
1251 * Tell the GC map code that the vtype is considered live after
1252 * the initialization.
1254 MONO_INST_NEW (cfg
, tmp
, OP_GC_LIVENESS_DEF
);
1255 tmp
->inst_c1
= ins
->dreg
;
1256 MONO_ADD_INS (cfg
->cbb
, tmp
);
1259 case OP_DUMMY_VZERO
:
1260 if (COMPILE_LLVM (cfg
))
1265 case OP_STOREV_MEMBASE
: {
1266 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1268 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
) && !cfg
->gen_write_barriers
)
1272 g_assert (ins
->klass
);
1273 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->sreg1
);
1276 EMIT_NEW_VARLOADA_VREG ((cfg
), (src
), ins
->sreg1
, &ins
->klass
->byval_arg
);
1278 dreg
= alloc_preg (cfg
);
1279 EMIT_NEW_BIALU_IMM (cfg
, dest
, OP_ADD_IMM
, dreg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1280 mini_emit_stobj (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
);
1283 case OP_LOADV_MEMBASE
: {
1284 g_assert (ins
->klass
);
1285 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1288 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1292 dest_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->dreg
);
1294 dreg
= alloc_preg (cfg
);
1295 EMIT_NEW_BIALU_IMM (cfg
, src
, OP_ADD_IMM
, dreg
, ins
->inst_basereg
, ins
->inst_offset
);
1296 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1297 mini_emit_stobj (cfg
, dest
, src
, dest_var
->klass
, dest_var
->backend
.is_pinvoke
);
1300 case OP_OUTARG_VT
: {
1301 if (COMPILE_LLVM (cfg
))
1304 g_assert (ins
->klass
);
1306 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1308 src_var
= mono_compile_create_var_for_vreg (cfg
, &ins
->klass
->byval_arg
, OP_LOCAL
, ins
->sreg1
);
1309 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1311 mono_arch_emit_outarg_vt (cfg
, ins
, src
);
1313 /* This might be decomposed into other vtype opcodes */
1317 case OP_OUTARG_VTRETADDR
: {
1318 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p1
;
1320 src_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1322 src_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1323 // FIXME: src_var->backend.is_pinvoke ?
1325 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1326 src
->dreg
= ins
->dreg
;
1331 case OP_VCALL_MEMBASE
: {
1332 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1335 if (COMPILE_LLVM (cfg
))
1338 if (call
->vret_in_reg
) {
1339 MonoCallInst
*call2
;
1341 /* Replace the vcall with a scalar call */
1342 MONO_INST_NEW_CALL (cfg
, call2
, OP_NOP
);
1343 memcpy (call2
, call
, sizeof (MonoCallInst
));
1344 switch (ins
->opcode
) {
1346 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL
: OP_CALL
;
1349 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL_REG
: OP_CALL_REG
;
1351 case OP_VCALL_MEMBASE
:
1352 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL_MEMBASE
: OP_CALL_MEMBASE
;
1355 call2
->inst
.dreg
= alloc_preg (cfg
);
1356 MONO_ADD_INS (cfg
->cbb
, ((MonoInst
*)call2
));
1358 /* Compute the vtype location */
1359 dest_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1361 dest_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1362 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1364 /* Save the result */
1365 if (dest_var
->backend
.is_pinvoke
)
1366 size
= mono_class_native_size (mono_class_from_mono_type (dest_var
->inst_vtype
), NULL
);
1368 size
= mono_type_size (dest_var
->inst_vtype
, NULL
);
1371 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI1_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1374 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI2_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1378 if (call
->vret_in_reg_fp
)
1379 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1381 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1387 if (call
->vret_in_reg_fp
) {
1388 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1391 #if SIZEOF_REGISTER == 4
1393 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1394 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1396 switch (call2
->inst
.opcode
) {
1398 call2
->inst
.opcode
= OP_LCALL
;
1401 call2
->inst
.opcode
= OP_LCALL_REG
;
1403 case OP_CALL_MEMBASE
:
1404 call2
->inst
.opcode
= OP_LCALL_MEMBASE
;
1407 call2
->inst
.dreg
= alloc_lreg (cfg
);
1408 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_MS_WORD_OFFSET
, MONO_LVREG_MS (call2
->inst
.dreg
));
1409 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_LS_WORD_OFFSET
, MONO_LVREG_LS (call2
->inst
.dreg
));
1411 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1415 /* This assumes the vtype is sizeof (gpointer) long */
1416 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1420 switch (ins
->opcode
) {
1422 ins
->opcode
= OP_VCALL2
;
1425 ins
->opcode
= OP_VCALL2_REG
;
1427 case OP_VCALL_MEMBASE
:
1428 ins
->opcode
= OP_VCALL2_MEMBASE
;
1439 g_assert (cfg
->cbb
== first_bb
);
1441 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1442 /* Replace the original instruction with the new code sequence */
1444 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1445 first_bb
->code
= first_bb
->last_ins
= NULL
;
1446 first_bb
->in_count
= first_bb
->out_count
= 0;
1447 cfg
->cbb
= first_bb
;
1454 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "AFTER LOWER-VTYPE-OPTS ");
1458 inline static MonoInst
*
1459 mono_get_domainvar (MonoCompile
*cfg
)
1461 if (!cfg
->domainvar
)
1462 cfg
->domainvar
= mono_compile_create_var (cfg
, &mono_defaults
.int_class
->byval_arg
, OP_LOCAL
);
1463 return cfg
->domainvar
;
1467 * mono_decompose_array_access_opts:
1469 * Decompose array access opcodes.
1472 mono_decompose_array_access_opts (MonoCompile
*cfg
)
1474 MonoBasicBlock
*bb
, *first_bb
;
1477 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1478 * can be executed anytime. It should be run before decompose_long
1482 * Create a dummy bblock and emit code into it so we can use the normal
1483 * code generation macros.
1485 cfg
->cbb
= (MonoBasicBlock
*)mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1486 first_bb
= cfg
->cbb
;
1488 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1490 MonoInst
*prev
= NULL
;
1492 MonoInst
*iargs
[3];
1495 if (!bb
->has_array_access
)
1498 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1500 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1506 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1507 switch (ins
->opcode
) {
1509 NEW_LOAD_MEMBASE_FLAGS (cfg
, dest
, OP_LOADI4_MEMBASE
, ins
->dreg
, ins
->sreg1
,
1510 MONO_STRUCT_OFFSET (MonoArray
, max_length
), ins
->flags
| MONO_INST_INVARIANT_LOAD
);
1511 MONO_ADD_INS (cfg
->cbb
, dest
);
1513 case OP_BOUNDS_CHECK
:
1514 MONO_EMIT_NULL_CHECK (cfg
, ins
->sreg1
);
1515 if (COMPILE_LLVM (cfg
))
1516 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, ins
->sreg2
, ins
->flags
& MONO_INST_FAULT
);
1518 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, ins
->sreg2
);
1521 if (cfg
->opt
& MONO_OPT_SHARED
) {
1522 EMIT_NEW_DOMAINCONST (cfg
, iargs
[0]);
1523 EMIT_NEW_CLASSCONST (cfg
, iargs
[1], ins
->inst_newa_class
);
1524 MONO_INST_NEW (cfg
, iargs
[2], OP_MOVE
);
1525 iargs
[2]->dreg
= ins
->sreg1
;
1527 dest
= mono_emit_jit_icall (cfg
, ves_icall_array_new
, iargs
);
1528 dest
->dreg
= ins
->dreg
;
1530 MonoClass
*array_class
= mono_array_class_get (ins
->inst_newa_class
, 1);
1531 MonoVTable
*vtable
= mono_class_vtable (cfg
->domain
, array_class
);
1532 MonoMethod
*managed_alloc
= mono_gc_get_managed_array_allocator (array_class
);
1534 g_assert (vtable
); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1535 NEW_VTABLECONST (cfg
, iargs
[0], vtable
);
1536 MONO_ADD_INS (cfg
->cbb
, iargs
[0]);
1537 MONO_INST_NEW (cfg
, iargs
[1], OP_MOVE
);
1538 iargs
[1]->dreg
= ins
->sreg1
;
1541 dest
= mono_emit_method_call (cfg
, managed_alloc
, iargs
, NULL
);
1543 dest
= mono_emit_jit_icall (cfg
, ves_icall_array_new_specific
, iargs
);
1544 dest
->dreg
= ins
->dreg
;
1548 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg
, OP_LOADI4_MEMBASE
, ins
->dreg
,
1549 ins
->sreg1
, MONO_STRUCT_OFFSET (MonoString
, length
), ins
->flags
| MONO_INST_INVARIANT_LOAD
);
1555 g_assert (cfg
->cbb
== first_bb
);
1557 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1558 /* Replace the original instruction with the new code sequence */
1560 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1561 first_bb
->code
= first_bb
->last_ins
= NULL
;
1562 first_bb
->in_count
= first_bb
->out_count
= 0;
1563 cfg
->cbb
= first_bb
;
1570 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1580 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1583 * mono_decompose_soft_float:
1585 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1586 * similar to long support on 32 bit platforms. 32 bit float values require special
1587 * handling when used as locals, arguments, and in calls.
1588 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1591 mono_decompose_soft_float (MonoCompile
*cfg
)
1593 MonoBasicBlock
*bb
, *first_bb
;
1596 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1600 * Create a dummy bblock and emit code into it so we can use the normal
1601 * code generation macros.
1603 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1604 first_bb
= cfg
->cbb
;
1606 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1608 MonoInst
*prev
= NULL
;
1611 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE HANDLE-SOFT-FLOAT ");
1613 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1619 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1620 const char *spec
= INS_INFO (ins
->opcode
);
1622 /* Most fp operations are handled automatically by opcode emulation */
1624 switch (ins
->opcode
) {
1627 d
.vald
= *(double*)ins
->inst_p0
;
1628 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1633 /* We load the r8 value */
1634 d
.vald
= *(float*)ins
->inst_p0
;
1635 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1639 ins
->opcode
= OP_LMOVE
;
1642 ins
->opcode
= OP_MOVE
;
1643 ins
->sreg1
= MONO_LVREG_LS (ins
->sreg1
);
1646 ins
->opcode
= OP_MOVE
;
1647 ins
->sreg1
= MONO_LVREG_MS (ins
->sreg1
);
1650 int reg
= ins
->sreg1
;
1652 ins
->opcode
= OP_SETLRET
;
1654 ins
->sreg1
= MONO_LVREG_LS (reg
);
1655 ins
->sreg2
= MONO_LVREG_MS (reg
);
1658 case OP_LOADR8_MEMBASE
:
1659 ins
->opcode
= OP_LOADI8_MEMBASE
;
1661 case OP_STORER8_MEMBASE_REG
:
1662 ins
->opcode
= OP_STOREI8_MEMBASE_REG
;
1664 case OP_STORER4_MEMBASE_REG
: {
1665 MonoInst
*iargs
[2];
1668 /* Arg 1 is the double value */
1669 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1670 iargs
[0]->dreg
= ins
->sreg1
;
1672 /* Arg 2 is the address to store to */
1673 addr_reg
= mono_alloc_preg (cfg
);
1674 EMIT_NEW_BIALU_IMM (cfg
, iargs
[1], OP_PADD_IMM
, addr_reg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1675 mono_emit_jit_icall (cfg
, mono_fstore_r4
, iargs
);
1679 case OP_LOADR4_MEMBASE
: {
1680 MonoInst
*iargs
[1];
1684 addr_reg
= mono_alloc_preg (cfg
);
1685 EMIT_NEW_BIALU_IMM (cfg
, iargs
[0], OP_PADD_IMM
, addr_reg
, ins
->inst_basereg
, ins
->inst_offset
);
1686 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1687 conv
->dreg
= ins
->dreg
;
1692 case OP_FCALL_MEMBASE
: {
1693 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1694 if (call
->signature
->ret
->type
== MONO_TYPE_R4
) {
1695 MonoCallInst
*call2
;
1696 MonoInst
*iargs
[1];
1700 /* Convert the call into a call returning an int */
1701 MONO_INST_NEW_CALL (cfg
, call2
, OP_CALL
);
1702 memcpy (call2
, call
, sizeof (MonoCallInst
));
1703 switch (ins
->opcode
) {
1705 call2
->inst
.opcode
= OP_CALL
;
1708 call2
->inst
.opcode
= OP_CALL_REG
;
1710 case OP_FCALL_MEMBASE
:
1711 call2
->inst
.opcode
= OP_CALL_MEMBASE
;
1714 g_assert_not_reached ();
1716 call2
->inst
.dreg
= mono_alloc_ireg (cfg
);
1717 MONO_ADD_INS (cfg
->cbb
, (MonoInst
*)call2
);
1719 /* Remap OUTARG_VT instructions referencing this call */
1720 for (l
= call
->outarg_vts
; l
; l
= l
->next
)
1721 ((MonoInst
*)(l
->data
))->inst_p0
= call2
;
1723 /* FIXME: Optimize this */
1725 /* Emit an r4->r8 conversion */
1726 EMIT_NEW_VARLOADA_VREG (cfg
, iargs
[0], call2
->inst
.dreg
, &mono_defaults
.int32_class
->byval_arg
);
1727 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1728 conv
->dreg
= ins
->dreg
;
1730 /* The call sequence might include fp ins */
1733 switch (ins
->opcode
) {
1735 ins
->opcode
= OP_LCALL
;
1738 ins
->opcode
= OP_LCALL_REG
;
1740 case OP_FCALL_MEMBASE
:
1741 ins
->opcode
= OP_LCALL_MEMBASE
;
1744 g_assert_not_reached ();
1750 MonoJitICallInfo
*info
;
1751 MonoInst
*iargs
[2];
1752 MonoInst
*call
, *cmp
, *br
;
1754 /* Convert fcompare+fbcc to icall+icompare+beq */
1757 /* The branch might be optimized away */
1762 info
= mono_find_jit_opcode_emulation (ins
->next
->opcode
);
1764 /* The branch might be optimized away */
1769 /* Create dummy MonoInst's for the arguments */
1770 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1771 iargs
[0]->dreg
= ins
->sreg1
;
1772 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1773 iargs
[1]->dreg
= ins
->sreg2
;
1775 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, iargs
);
1777 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1778 cmp
->sreg1
= call
->dreg
;
1780 MONO_ADD_INS (cfg
->cbb
, cmp
);
1782 MONO_INST_NEW (cfg
, br
, OP_IBNE_UN
);
1783 br
->inst_many_bb
= mono_mempool_alloc (cfg
->mempool
, sizeof (gpointer
) * 2);
1784 br
->inst_true_bb
= ins
->next
->inst_true_bb
;
1785 br
->inst_false_bb
= ins
->next
->inst_false_bb
;
1786 MONO_ADD_INS (cfg
->cbb
, br
);
1788 /* The call sequence might include fp ins */
1791 /* Skip fbcc or fccc */
1792 NULLIFY_INS (ins
->next
);
1800 MonoJitICallInfo
*info
;
1801 MonoInst
*iargs
[2];
1804 /* Convert fccc to icall+icompare+iceq */
1806 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
1809 /* Create dummy MonoInst's for the arguments */
1810 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1811 iargs
[0]->dreg
= ins
->sreg1
;
1812 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1813 iargs
[1]->dreg
= ins
->sreg2
;
1815 call
= mono_emit_native_call (cfg
, mono_icall_get_wrapper (info
), info
->sig
, iargs
);
1817 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, call
->dreg
, 1);
1818 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, ins
->dreg
, -1);
1820 /* The call sequence might include fp ins */
1825 MonoInst
*iargs
[2];
1826 MonoInst
*call
, *cmp
;
1828 /* Convert to icall+icompare+cond_exc+move */
1830 /* Create dummy MonoInst's for the arguments */
1831 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1832 iargs
[0]->dreg
= ins
->sreg1
;
1834 call
= mono_emit_jit_icall (cfg
, mono_isfinite
, iargs
);
1836 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1837 cmp
->sreg1
= call
->dreg
;
1839 MONO_ADD_INS (cfg
->cbb
, cmp
);
1841 MONO_EMIT_NEW_COND_EXC (cfg
, INE_UN
, "ArithmeticException");
1843 /* Do the assignment if the value is finite */
1844 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, ins
->dreg
, ins
->sreg1
);
1850 if (spec
[MONO_INST_SRC1
] == 'f' || spec
[MONO_INST_SRC2
] == 'f' || spec
[MONO_INST_DEST
] == 'f') {
1851 mono_print_ins (ins
);
1852 g_assert_not_reached ();
1857 g_assert (cfg
->cbb
== first_bb
);
1859 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1860 /* Replace the original instruction with the new code sequence */
1862 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1863 first_bb
->code
= first_bb
->last_ins
= NULL
;
1864 first_bb
->in_count
= first_bb
->out_count
= 0;
1865 cfg
->cbb
= first_bb
;
1872 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER HANDLE-SOFT-FLOAT ");
1875 mono_decompose_long_opts (cfg
);
1881 mono_local_emulate_ops (MonoCompile
*cfg
)
1884 gboolean inlined_wrapper
= FALSE
;
1886 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1889 MONO_BB_FOR_EACH_INS (bb
, ins
) {
1890 int op_noimm
= mono_op_imm_to_op (ins
->opcode
);
1891 MonoJitICallInfo
*info
;
1894 * These opcodes don't have logical equivalence to the emulating native
1895 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1897 if (MONO_HAS_CUSTOM_EMULATION (ins
))
1901 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1902 * to check whether its non-imm counterpart is emulated and, if so,
1903 * decompose it back to its non-imm counterpart.
1906 info
= mono_find_jit_opcode_emulation (op_noimm
);
1908 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
1913 MonoBasicBlock
*first_bb
;
1915 /* Create dummy MonoInst's for the arguments */
1916 g_assert (!info
->sig
->hasthis
);
1917 g_assert (info
->sig
->param_count
<= MONO_MAX_SRC_REGS
);
1920 mono_decompose_op_imm (cfg
, bb
, ins
);
1922 args
= (MonoInst
**)mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
*) * info
->sig
->param_count
);
1923 if (info
->sig
->param_count
> 0) {
1924 int sregs
[MONO_MAX_SRC_REGS
];
1926 num_sregs
= mono_inst_get_src_registers (ins
, sregs
);
1927 g_assert (num_sregs
== info
->sig
->param_count
);
1928 for (i
= 0; i
< num_sregs
; ++i
) {
1929 MONO_INST_NEW (cfg
, args
[i
], OP_ARG
);
1930 args
[i
]->dreg
= sregs
[i
];
1934 /* We emit the call on a separate dummy basic block */
1935 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1936 first_bb
= cfg
->cbb
;
1938 call
= mono_emit_jit_icall_by_info (cfg
, bb
->real_offset
, info
, args
);
1939 call
->dreg
= ins
->dreg
;
1941 /* Replace ins with the emitted code and do the necessary bb linking */
1942 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1943 MonoInst
*saved_prev
= ins
->prev
;
1945 mono_replace_ins (cfg
, bb
, ins
, &ins
->prev
, first_bb
, cfg
->cbb
);
1946 first_bb
->code
= first_bb
->last_ins
= NULL
;
1947 first_bb
->in_count
= first_bb
->out_count
= 0;
1948 cfg
->cbb
= first_bb
;
1950 /* ins is hanging, continue scanning the emitted code */
1953 g_error ("Failed to emit emulation code");
1955 inlined_wrapper
= TRUE
;
1961 * Avoid rerunning these passes by emitting directly the exception checkpoint
1962 * at IR level, instead of inlining the icall wrapper. FIXME
1964 if (inlined_wrapper
) {
1965 if (!COMPILE_LLVM (cfg
))
1966 mono_decompose_long_opts (cfg
);
1967 if (cfg
->opt
& (MONO_OPT_CONSPROP
| MONO_OPT_COPYPROP
))
1968 mono_local_cprop (cfg
);
1972 #else /* !DISABLE_JIT */
1974 MONO_EMPTY_SOURCE_FILE (decompose
);
1976 #endif /* !DISABLE_JIT */