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>
21 #define MONO_MATH_DECLARE_ALL 1
22 #include <mono/utils/mono-math.h>
27 * Decompose complex long opcodes on 64 bit machines.
28 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
31 decompose_long_opcode (MonoCompile
*cfg
, MonoInst
*ins
, MonoInst
**repl_ins
)
33 MonoInst
*repl
= NULL
;
37 switch (ins
->opcode
) {
39 ins
->opcode
= OP_SEXT_I4
;
43 if (TARGET_SIZEOF_VOID_P
== 4)
44 ins
->opcode
= OP_LMOVE
;
46 ins
->opcode
= OP_MOVE
;
49 if (TARGET_SIZEOF_VOID_P
== 4)
51 ins
->opcode
= OP_SEXT_I4
;
53 ins
->opcode
= OP_MOVE
;
56 if (TARGET_SIZEOF_VOID_P
== 4) {
58 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
61 ins
->opcode
= OP_MOVE
;
65 ins
->opcode
= OP_SEXT_I4
;
68 ins
->opcode
= OP_ZEXT_I4
;
71 /* Clean out the upper word */
72 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISHR_UN_IMM
, ins
->dreg
, ins
->sreg1
, 0);
78 if (COMPILE_LLVM (cfg
))
80 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
84 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
85 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
89 case OP_LADD_OVF_UN
: {
92 if (COMPILE_LLVM (cfg
))
94 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
98 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
99 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
103 #ifndef __mono_ppc64__
107 if (COMPILE_LLVM (cfg
))
109 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
113 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
114 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
118 case OP_LSUB_OVF_UN
: {
121 if (COMPILE_LLVM (cfg
))
123 if (cfg
->backend
->ilp32
&& SIZEOF_REGISTER
== 8)
127 EMIT_NEW_BIALU (cfg
, repl
, opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
128 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
134 case OP_ICONV_TO_OVF_I8
:
135 case OP_ICONV_TO_OVF_I
:
136 ins
->opcode
= OP_SEXT_I4
;
138 case OP_ICONV_TO_OVF_U8
:
139 case OP_ICONV_TO_OVF_U
:
140 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
,ins
->sreg1
, 0);
141 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
142 MONO_EMIT_NEW_UNALU (cfg
, OP_ZEXT_I4
, ins
->dreg
, ins
->sreg1
);
145 case OP_ICONV_TO_OVF_I8_UN
:
146 case OP_ICONV_TO_OVF_U8_UN
:
147 case OP_ICONV_TO_OVF_I_UN
:
148 case OP_ICONV_TO_OVF_U_UN
:
149 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
150 /* Clean out the upper word */
151 MONO_EMIT_NEW_UNALU (cfg
, OP_ZEXT_I4
, ins
->dreg
, ins
->sreg1
);
154 case OP_LCONV_TO_OVF_I1
:
155 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 127);
156 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
157 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -128);
158 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
159 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
162 case OP_LCONV_TO_OVF_I1_UN
:
163 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 127);
164 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
165 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
168 case OP_LCONV_TO_OVF_U1
:
169 /* probe value to be within 0 to 255 */
170 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 255);
171 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
172 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
175 case OP_LCONV_TO_OVF_U1_UN
:
176 /* probe value to be within 0 to 255 */
177 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 255);
178 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
179 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
182 case OP_LCONV_TO_OVF_I2
:
183 /* Probe value to be within -32768 and 32767 */
184 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
185 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
186 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
187 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
188 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
191 case OP_LCONV_TO_OVF_I2_UN
:
192 /* Probe value to be within 0 and 32767 */
193 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
194 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
195 MONO_EMIT_NEW_UNALU (cfg
, OP_LCONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
198 case OP_LCONV_TO_OVF_U2
:
199 /* Probe value to be within 0 and 65535 */
200 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
201 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
202 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
205 case OP_LCONV_TO_OVF_U2_UN
:
206 /* Probe value to be within 0 and 65535 */
207 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
208 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
209 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
212 case OP_LCONV_TO_OVF_I4
:
213 #if TARGET_SIZEOF_VOID_P == 4
214 case OP_LCONV_TO_OVF_I
:
216 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
217 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
218 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
219 #if SIZEOF_REGISTER == 8
220 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, ((int)-2147483648));
222 g_assert (COMPILE_LLVM (cfg
));
223 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, -2147483648LL);
225 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
226 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
229 case OP_LCONV_TO_OVF_I4_UN
:
230 #if TARGET_SIZEOF_VOID_P == 4
231 case OP_LCONV_TO_OVF_I_UN
:
233 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0x7fffffff);
234 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
235 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
238 case OP_LCONV_TO_OVF_U4
:
239 #if TARGET_SIZEOF_VOID_P == 4
240 case OP_LCONV_TO_OVF_U
:
242 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffffUL
);
243 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
244 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
245 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
246 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
249 case OP_LCONV_TO_OVF_U4_UN
:
250 #if TARGET_SIZEOF_VOID_P == 4
251 case OP_LCONV_TO_OVF_U_UN
:
253 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0xffffffff);
254 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
255 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
258 #if TARGET_SIZEOF_VOID_P == 8
259 case OP_LCONV_TO_OVF_I
:
260 case OP_LCONV_TO_OVF_U_UN
:
262 case OP_LCONV_TO_OVF_U8_UN
:
263 case OP_LCONV_TO_OVF_I8
:
264 ins
->opcode
= OP_MOVE
;
266 #if TARGET_SIZEOF_VOID_P == 8
267 case OP_LCONV_TO_OVF_I_UN
:
269 case OP_LCONV_TO_OVF_I8_UN
:
270 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
271 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
272 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
275 case OP_LCONV_TO_OVF_U8
:
276 #if TARGET_SIZEOF_VOID_P == 8
277 case OP_LCONV_TO_OVF_U
:
279 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg1
, 0);
280 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
281 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
293 * mono_decompose_opcode:
295 * Decompose complex opcodes into ones closer to opcodes supported by
296 * the given architecture.
297 * Returns a MonoInst which represents the result of the decomposition, and can
298 * be pushed on the IL stack. This is needed because the original instruction is
300 * Sets the cfg exception if an opcode is not supported.
303 mono_decompose_opcode (MonoCompile
*cfg
, MonoInst
*ins
)
305 MonoInst
*repl
= NULL
;
306 int type
= ins
->type
;
307 int dreg
= ins
->dreg
;
308 gboolean emulate
= FALSE
;
310 /* FIXME: Instead of = NOP, don't emit the original ins at all */
311 mono_arch_decompose_opts (cfg
, ins
);
314 * The code below assumes that we are called immediately after emitting
315 * ins. This means we can emit code using the normal code generation
318 switch (ins
->opcode
) {
319 /* this doesn't make sense on ppc and other architectures */
320 #if !defined(MONO_ARCH_NO_IOV_CHECK)
322 if (COMPILE_LLVM (cfg
))
324 ins
->opcode
= OP_IADDCC
;
325 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
328 if (COMPILE_LLVM (cfg
))
330 ins
->opcode
= OP_IADDCC
;
331 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
334 if (COMPILE_LLVM (cfg
))
336 ins
->opcode
= OP_ISUBCC
;
337 MONO_EMIT_NEW_COND_EXC (cfg
, IOV
, "OverflowException");
340 if (COMPILE_LLVM (cfg
))
342 ins
->opcode
= OP_ISUBCC
;
343 MONO_EMIT_NEW_COND_EXC (cfg
, IC
, "OverflowException");
346 case OP_ICONV_TO_OVF_I1
:
347 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
348 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
349 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -128);
350 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
351 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
354 case OP_ICONV_TO_OVF_I1_UN
:
355 /* probe values between 0 to 127 */
356 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 127);
357 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
358 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, ins
->dreg
, ins
->sreg1
);
361 case OP_ICONV_TO_OVF_U1
:
362 case OP_ICONV_TO_OVF_U1_UN
:
363 /* probe value to be within 0 to 255 */
364 MONO_EMIT_NEW_COMPARE_IMM (cfg
, ins
->sreg1
, 255);
365 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
366 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xff);
369 case OP_ICONV_TO_OVF_I2
:
370 /* Probe value to be within -32768 and 32767 */
371 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
372 MONO_EMIT_NEW_COND_EXC (cfg
, IGT
, "OverflowException");
373 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, -32768);
374 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
375 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
378 case OP_ICONV_TO_OVF_I2_UN
:
379 /* Convert uint value into short, value within 0 and 32767 */
380 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 32767);
381 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
382 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, ins
->dreg
, ins
->sreg1
);
385 case OP_ICONV_TO_OVF_U2
:
386 case OP_ICONV_TO_OVF_U2_UN
:
387 /* Probe value to be within 0 and 65535 */
388 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0xffff);
389 MONO_EMIT_NEW_COND_EXC (cfg
, IGT_UN
, "OverflowException");
390 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IAND_IMM
, ins
->dreg
, ins
->sreg1
, 0xffff);
393 case OP_ICONV_TO_OVF_U4
:
394 case OP_ICONV_TO_OVF_I4_UN
:
395 #if TARGET_SIZEOF_VOID_P == 4
396 case OP_ICONV_TO_OVF_U
:
397 case OP_ICONV_TO_OVF_I_UN
:
399 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0);
400 MONO_EMIT_NEW_COND_EXC (cfg
, ILT
, "OverflowException");
401 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, ins
->sreg1
);
406 case OP_ICONV_TO_OVF_I4
:
407 case OP_ICONV_TO_OVF_U4_UN
:
408 #if TARGET_SIZEOF_VOID_P == 4
409 case OP_ICONV_TO_OVF_I
:
410 case OP_ICONV_TO_OVF_U_UN
:
412 ins
->opcode
= OP_MOVE
;
415 #if TARGET_SIZEOF_VOID_P == 8
416 ins
->opcode
= OP_SEXT_I4
;
418 ins
->opcode
= OP_MOVE
;
422 #if TARGET_SIZEOF_VOID_P == 8
423 ins
->opcode
= OP_ZEXT_I4
;
425 ins
->opcode
= OP_MOVE
;
430 ins
->opcode
= OP_FMOVE
;
433 case OP_FCONV_TO_OVF_I1_UN
:
434 case OP_FCONV_TO_OVF_I2_UN
:
435 case OP_FCONV_TO_OVF_I4_UN
:
436 case OP_FCONV_TO_OVF_I8_UN
:
437 case OP_FCONV_TO_OVF_U1_UN
:
438 case OP_FCONV_TO_OVF_U2_UN
:
439 case OP_FCONV_TO_OVF_U4_UN
:
440 case OP_FCONV_TO_OVF_I_UN
:
441 case OP_FCONV_TO_OVF_U_UN
:
442 mono_cfg_set_exception_invalid_program (cfg
, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
449 if (cfg
->backend
->emulate_div
&& mono_arch_opcode_needs_emulation (cfg
, ins
->opcode
))
452 if (cfg
->backend
->need_div_check
) {
453 int reg1
= alloc_ireg (cfg
);
454 int reg2
= alloc_ireg (cfg
);
456 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg2
, 0);
457 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
458 if (ins
->opcode
== OP_IDIV
|| ins
->opcode
== OP_IREM
) {
459 /* b == -1 && a == 0x80000000 */
460 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg2
, -1);
461 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, reg1
, -1);
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0x80000000);
463 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, reg2
, -1);
464 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, reg1
, reg1
, reg2
);
465 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 1);
466 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
469 MONO_EMIT_NEW_BIALU (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
474 #if TARGET_SIZEOF_VOID_P == 8
479 if (cfg
->backend
->emulate_div
&& mono_arch_opcode_needs_emulation (cfg
, ins
->opcode
))
482 if (cfg
->backend
->need_div_check
) {
483 int reg1
= alloc_ireg (cfg
);
484 int reg2
= alloc_ireg (cfg
);
485 int reg3
= alloc_ireg (cfg
);
487 MONO_EMIT_NEW_LCOMPARE_IMM (cfg
, ins
->sreg2
, 0);
488 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
489 if (ins
->opcode
== OP_LDIV
|| ins
->opcode
== OP_LREM
) {
490 /* b == -1 && a == 0x80000000 */
491 MONO_EMIT_NEW_I8CONST (cfg
, reg3
, -1);
492 MONO_EMIT_NEW_BIALU (cfg
, OP_LCOMPARE
, -1, ins
->sreg2
, reg3
);
493 MONO_EMIT_NEW_UNALU (cfg
, OP_LCEQ
, reg1
, -1);
494 MONO_EMIT_NEW_I8CONST (cfg
, reg3
, 0x8000000000000000L
);
495 MONO_EMIT_NEW_BIALU (cfg
, OP_LCOMPARE
, -1, ins
->sreg1
, reg3
);
496 MONO_EMIT_NEW_UNALU (cfg
, OP_LCEQ
, reg2
, -1);
497 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, reg1
, reg1
, reg2
);
498 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 1);
499 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
502 MONO_EMIT_NEW_BIALU (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->sreg2
);
514 if (cfg
->backend
->need_div_check
) {
515 int reg1
= alloc_ireg (cfg
);
517 if (ins
->inst_imm
== 0) {
518 // FIXME: Optimize this
519 MONO_EMIT_NEW_ICONST (cfg
, reg1
, 0);
520 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, reg1
, 0);
521 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "DivideByZeroException");
523 if ((ins
->opcode
== OP_DIV_IMM
|| ins
->opcode
== OP_IDIV_IMM
|| ins
->opcode
== OP_REM_IMM
|| ins
->opcode
== OP_IREM_IMM
) &&
524 (ins
->inst_imm
== -1)) {
525 /* b == -1 && a == 0x80000000 */
526 MONO_EMIT_NEW_ICOMPARE_IMM (cfg
, ins
->sreg1
, 0x80000000);
527 MONO_EMIT_NEW_COND_EXC (cfg
, IEQ
, "OverflowException");
529 MONO_EMIT_NEW_BIALU_IMM (cfg
, ins
->opcode
, ins
->dreg
, ins
->sreg1
, ins
->inst_imm
);
535 case OP_ICONV_TO_R_UN
:
536 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
537 if (!COMPILE_LLVM (cfg
))
547 #if SIZEOF_REGISTER == 8
548 if (decompose_long_opcode (cfg
, ins
, &repl
))
551 if (COMPILE_LLVM (cfg
) && decompose_long_opcode (cfg
, ins
, &repl
))
555 if (emulate
&& mono_find_jit_opcode_emulation (ins
->opcode
))
556 cfg
->has_emulated_ops
= TRUE
;
559 if (ins
->opcode
== OP_NOP
) {
564 /* Use the last emitted instruction */
565 ins
= cfg
->cbb
->last_ins
;
568 g_assert (ins
->dreg
== dreg
);
576 #if SIZEOF_REGISTER == 4
577 static int lbr_decomp
[][2] = {
579 {OP_IBGT
, OP_IBGE_UN
}, /* BGE */
580 {OP_IBGT
, OP_IBGT_UN
}, /* BGT */
581 {OP_IBLT
, OP_IBLE_UN
}, /* BLE */
582 {OP_IBLT
, OP_IBLT_UN
}, /* BLT */
584 {OP_IBGT_UN
, OP_IBGE_UN
}, /* BGE_UN */
585 {OP_IBGT_UN
, OP_IBGT_UN
}, /* BGT_UN */
586 {OP_IBLT_UN
, OP_IBLE_UN
}, /* BLE_UN */
587 {OP_IBLT_UN
, OP_IBLT_UN
}, /* BLT_UN */
590 static int lcset_decomp
[][2] = {
592 {OP_IBLT
, OP_IBLE_UN
}, /* CGT */
593 {OP_IBLT_UN
, OP_IBLE_UN
}, /* CGT_UN */
594 {OP_IBGT
, OP_IBGE_UN
}, /* CLT */
595 {OP_IBGT_UN
, OP_IBGE_UN
}, /* CLT_UN */
600 * mono_decompose_long_opts:
602 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
605 mono_decompose_long_opts (MonoCompile
*cfg
)
607 #if SIZEOF_REGISTER == 4
608 MonoBasicBlock
*bb
, *first_bb
;
611 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
612 * needs to be able to handle long vregs.
616 * Create a dummy bblock and emit code into it so we can use the normal
617 * code generation macros.
619 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
622 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
623 MonoInst
*tree
= mono_bb_first_inst(bb
, FILTER_IL_SEQ_POINT
);
624 MonoInst
*prev
= NULL
;
627 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
630 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
633 mono_arch_decompose_long_opts (cfg
, tree
);
635 switch (tree
->opcode
) {
637 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_LS (tree
->dreg
), ins_get_l_low (tree
));
638 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), ins_get_l_high (tree
));
640 case OP_DUMMY_I8CONST
:
641 MONO_EMIT_NEW_DUMMY_INIT (cfg
, MONO_LVREG_LS (tree
->dreg
), OP_DUMMY_ICONST
);
642 MONO_EMIT_NEW_DUMMY_INIT (cfg
, MONO_LVREG_MS (tree
->dreg
), OP_DUMMY_ICONST
);
647 case OP_LCONV_TO_OVF_U8_UN
:
648 case OP_LCONV_TO_OVF_I8
:
649 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
650 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
652 case OP_STOREI8_MEMBASE_REG
:
653 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
));
654 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
));
656 case OP_LOADI8_MEMBASE
:
657 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
);
658 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
);
661 case OP_ICONV_TO_I8
: {
662 guint32 tmpreg
= alloc_ireg (cfg
);
666 * tmp = low > -1 ? 1: 0;
667 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
669 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
670 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, MONO_LVREG_LS (tree
->dreg
), -1);
671 MONO_EMIT_NEW_BIALU (cfg
, OP_ICGT
, tmpreg
, -1, -1);
672 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ISUB_IMM
, MONO_LVREG_MS (tree
->dreg
), tmpreg
, 1);
676 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
677 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
679 case OP_ICONV_TO_OVF_I8
:
680 /* a signed 32 bit num always fits in a signed 64 bit one */
681 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SHR_IMM
, MONO_LVREG_MS (tree
->dreg
), tree
->sreg1
, 31);
682 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
684 case OP_ICONV_TO_OVF_U8
:
685 MONO_EMIT_NEW_COMPARE_IMM (cfg
, tree
->sreg1
, 0);
686 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
687 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
688 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
690 case OP_ICONV_TO_OVF_I8_UN
:
691 case OP_ICONV_TO_OVF_U8_UN
:
692 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
693 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
694 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), tree
->sreg1
);
697 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
700 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
703 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
706 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_U2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
712 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
714 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
716 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R8_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
719 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
721 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R4_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
724 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
725 case OP_LCONV_TO_R_UN
:
726 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_R_UN_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
729 case OP_LCONV_TO_OVF_I1
: {
730 MonoBasicBlock
*is_negative
, *end_label
;
732 NEW_BBLOCK (cfg
, is_negative
);
733 NEW_BBLOCK (cfg
, end_label
);
735 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
736 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
737 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), -1);
738 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
740 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
741 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
744 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 127);
745 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
746 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
749 MONO_START_BB (cfg
, is_negative
);
750 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -128);
751 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
753 MONO_START_BB (cfg
, end_label
);
755 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
758 case OP_LCONV_TO_OVF_I1_UN
:
759 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
760 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
762 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 127);
763 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
764 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -128);
765 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
766 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I1
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
768 case OP_LCONV_TO_OVF_U1
:
769 case OP_LCONV_TO_OVF_U1_UN
:
770 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
771 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
773 /* probe value to be within 0 to 255 */
774 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 255);
775 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
776 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), 0xff);
778 case OP_LCONV_TO_OVF_I2
: {
779 MonoBasicBlock
*is_negative
, *end_label
;
781 NEW_BBLOCK (cfg
, is_negative
);
782 NEW_BBLOCK (cfg
, end_label
);
784 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
785 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
786 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), -1);
787 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
789 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
790 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBLT
, is_negative
);
793 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 32767);
794 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
795 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_BR
, end_label
);
798 MONO_START_BB (cfg
, is_negative
);
799 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -32768);
800 MONO_EMIT_NEW_COND_EXC (cfg
, LT_UN
, "OverflowException");
801 MONO_START_BB (cfg
, end_label
);
803 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
806 case OP_LCONV_TO_OVF_I2_UN
:
807 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
808 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
810 /* Probe value to be within -32768 and 32767 */
811 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 32767);
812 MONO_EMIT_NEW_COND_EXC (cfg
, GT
, "OverflowException");
813 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), -32768);
814 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
815 MONO_EMIT_NEW_UNALU (cfg
, OP_ICONV_TO_I2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
817 case OP_LCONV_TO_OVF_U2
:
818 case OP_LCONV_TO_OVF_U2_UN
:
819 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
820 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
822 /* Probe value to be within 0 and 65535 */
823 MONO_EMIT_NEW_COMPARE_IMM (cfg
, MONO_LVREG_LS (tree
->sreg1
), 0xffff);
824 MONO_EMIT_NEW_COND_EXC (cfg
, GT_UN
, "OverflowException");
825 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), 0xffff);
827 case OP_LCONV_TO_OVF_I4
:
828 case OP_LCONV_TO_OVF_I
:
829 MONO_EMIT_NEW_BIALU (cfg
, OP_LCONV_TO_OVF_I4_2
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg1
));
831 case OP_LCONV_TO_OVF_U4
:
832 case OP_LCONV_TO_OVF_U
:
833 case OP_LCONV_TO_OVF_U4_UN
:
834 case OP_LCONV_TO_OVF_U_UN
:
835 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
836 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
837 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
839 case OP_LCONV_TO_OVF_I_UN
:
840 case OP_LCONV_TO_OVF_I4_UN
:
841 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
842 MONO_EMIT_NEW_COND_EXC (cfg
, NE_UN
, "OverflowException");
843 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_LS (tree
->sreg1
), 0);
844 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
845 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, tree
->dreg
, MONO_LVREG_LS (tree
->sreg1
));
847 case OP_LCONV_TO_OVF_U8
:
848 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
849 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
851 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
852 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
854 case OP_LCONV_TO_OVF_I8_UN
:
855 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, MONO_LVREG_MS (tree
->sreg1
), 0);
856 MONO_EMIT_NEW_COND_EXC (cfg
, LT
, "OverflowException");
858 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
859 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
863 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
864 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
867 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
868 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
872 /* ADC sets the condition code */
873 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
874 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
875 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
878 /* ADC sets the condition code */
879 MONO_EMIT_NEW_BIALU (cfg
, OP_IADDCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
880 MONO_EMIT_NEW_BIALU (cfg
, OP_IADC
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
881 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
884 /* SBB sets the condition code */
885 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
886 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
887 MONO_EMIT_NEW_COND_EXC (cfg
, OV
, "OverflowException");
890 /* SBB sets the condition code */
891 MONO_EMIT_NEW_BIALU (cfg
, OP_ISUBCC
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
892 MONO_EMIT_NEW_BIALU (cfg
, OP_ISBB
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
893 MONO_EMIT_NEW_COND_EXC (cfg
, C
, "OverflowException");
896 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
897 MONO_EMIT_NEW_BIALU (cfg
, OP_IAND
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
900 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
901 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
904 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
905 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
908 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
));
909 MONO_EMIT_NEW_UNALU (cfg
, OP_INOT
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
912 /* Handled in mono_arch_decompose_long_opts () */
913 g_assert_not_reached ();
917 /* FIXME: Add OP_BIGMUL optimization */
921 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADDCC_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), ins_get_l_low (tree
));
922 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ADC_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), ins_get_l_high (tree
));
925 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SUBCC_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), ins_get_l_low (tree
));
926 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_SBB_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), ins_get_l_high (tree
));
929 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), ins_get_l_low (tree
));
930 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_AND_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), ins_get_l_high (tree
));
933 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), ins_get_l_low (tree
));
934 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_OR_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), ins_get_l_high (tree
));
937 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_LS (tree
->sreg1
), ins_get_l_low (tree
));
938 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_XOR_IMM
, MONO_LVREG_MS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
), ins_get_l_high (tree
));
940 #ifdef TARGET_POWERPC
941 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
943 if (tree
->inst_c1
== 32) {
945 /* The original code had this comment: */
946 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
947 * later apply the speedup to the left shift as well
950 /* just move the upper half to the lower and zero the high word */
951 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, MONO_LVREG_LS (tree
->dreg
), MONO_LVREG_MS (tree
->sreg1
));
952 MONO_EMIT_NEW_ICONST (cfg
, MONO_LVREG_MS (tree
->dreg
), 0);
957 MonoInst
*next
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
961 switch (next
->opcode
) {
966 /* Branchless version based on gcc code */
967 d1
= alloc_ireg (cfg
);
968 d2
= alloc_ireg (cfg
);
969 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
970 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
971 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
972 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
973 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
985 /* Convert into three comparisons + branches */
986 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
987 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
988 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
989 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
990 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
991 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
997 /* Branchless version based on gcc code */
998 d1
= alloc_ireg (cfg
);
999 d2
= alloc_ireg (cfg
);
1000 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d1
, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
1001 MONO_EMIT_NEW_BIALU (cfg
, OP_IXOR
, d2
, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
1002 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1004 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1005 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
1013 MonoBasicBlock
*set_to_0
, *set_to_1
;
1015 NEW_BBLOCK (cfg
, set_to_0
);
1016 NEW_BBLOCK (cfg
, set_to_1
);
1018 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
1019 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
1020 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
1021 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_MS (tree
->sreg1
), MONO_LVREG_MS (tree
->sreg2
));
1022 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
1023 MONO_EMIT_NEW_BIALU (cfg
, OP_COMPARE
, -1, MONO_LVREG_LS (tree
->sreg1
), MONO_LVREG_LS (tree
->sreg2
));
1024 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
1025 MONO_START_BB (cfg
, set_to_1
);
1026 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
1027 MONO_START_BB (cfg
, set_to_0
);
1032 g_assert_not_reached ();
1037 /* Not yet used, since lcompare is decomposed before local cprop */
1038 case OP_LCOMPARE_IMM
: {
1039 MonoInst
*next
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
1040 guint32 low_imm
= ins_get_l_low (tree
);
1041 guint32 high_imm
= ins_get_l_high (tree
);
1042 int low_reg
= MONO_LVREG_LS (tree
->sreg1
);
1043 int high_reg
= MONO_LVREG_MS (tree
->sreg1
);
1047 switch (next
->opcode
) {
1052 /* Branchless version based on gcc code */
1053 d1
= alloc_ireg (cfg
);
1054 d2
= alloc_ireg (cfg
);
1055 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
1056 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
1057 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1058 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1059 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, next
->opcode
== OP_LBEQ
? OP_IBEQ
: OP_IBNE_UN
, next
->inst_true_bb
, next
->inst_false_bb
);
1072 /* Convert into three comparisons + branches */
1073 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1074 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][0], next
->inst_true_bb
);
1075 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1076 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, next
->inst_false_bb
);
1077 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
1078 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg
, lbr_decomp
[next
->opcode
- OP_LBEQ
][1], next
->inst_true_bb
, next
->inst_false_bb
);
1084 /* Branchless version based on gcc code */
1085 d1
= alloc_ireg (cfg
);
1086 d2
= alloc_ireg (cfg
);
1087 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d1
, low_reg
, low_imm
);
1088 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_IXOR_IMM
, d2
, high_reg
, high_imm
);
1089 MONO_EMIT_NEW_BIALU (cfg
, OP_IOR
, d1
, d1
, d2
);
1091 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, d1
, 0);
1092 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, next
->dreg
, -1);
1100 MonoBasicBlock
*set_to_0
, *set_to_1
;
1102 NEW_BBLOCK (cfg
, set_to_0
);
1103 NEW_BBLOCK (cfg
, set_to_1
);
1105 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 0);
1106 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1107 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][0], set_to_0
);
1108 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, high_reg
, high_imm
);
1109 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, OP_IBNE_UN
, set_to_1
);
1110 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_COMPARE_IMM
, -1, low_reg
, low_imm
);
1111 MONO_EMIT_NEW_BRANCH_BLOCK (cfg
, lcset_decomp
[next
->opcode
- OP_LCEQ
][1], set_to_0
);
1112 MONO_START_BB (cfg
, set_to_1
);
1113 MONO_EMIT_NEW_ICONST (cfg
, next
->dreg
, 1);
1114 MONO_START_BB (cfg
, set_to_0
);
1119 g_assert_not_reached ();
1128 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1131 /* Replace the original instruction with the new code sequence */
1133 /* Ignore the new value of prev */
1135 mono_replace_ins (cfg
, bb
, tree
, &new_prev
, first_bb
, cfg
->cbb
);
1137 /* Process the newly added ops again since they can be long ops too */
1139 tree
= mono_inst_next (prev
, FILTER_IL_SEQ_POINT
);
1141 tree
= mono_bb_first_inst (bb
, FILTER_IL_SEQ_POINT
);
1143 first_bb
->code
= first_bb
->last_ins
= NULL
;
1144 first_bb
->in_count
= first_bb
->out_count
= 0;
1145 cfg
->cbb
= first_bb
;
1149 tree
= mono_inst_next (tree
, FILTER_IL_SEQ_POINT
);
1156 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1157 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1162 * mono_decompose_vtype_opts:
1164 * Decompose valuetype opcodes.
1167 mono_decompose_vtype_opts (MonoCompile
*cfg
)
1169 MonoBasicBlock
*bb
, *first_bb
;
1172 * Using OP_V opcodes and decomposing them later have two main benefits:
1173 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1175 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1176 * enabling optimizations to work on vtypes too.
1177 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1178 * can be executed anytime. It should be executed as late as possible so vtype
1179 * opcodes can be optimized by the other passes.
1180 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1181 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1183 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1184 * when OP_VMOVE opcodes are decomposed.
1188 * Vregs have no associated type information, so we store the type of the vregs
1193 * Create a dummy bblock and emit code into it so we can use the normal
1194 * code generation macros.
1196 cfg
->cbb
= (MonoBasicBlock
*)mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1197 first_bb
= cfg
->cbb
;
1199 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1201 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1203 MonoInst
*prev
= NULL
;
1204 MonoInst
*src_var
, *dest_var
, *src
, *dest
;
1208 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "BEFORE LOWER-VTYPE-OPTS ");
1210 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1211 cfg
->cbb
->out_of_line
= bb
->out_of_line
;
1217 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1218 #ifdef MONO_ARCH_SIMD_INTRINSICS
1219 mono_simd_decompose_intrinsic (cfg
, bb
, ins
);
1221 switch (ins
->opcode
) {
1223 g_assert (ins
->klass
);
1224 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1226 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1227 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1230 src_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->dreg
);
1233 dest_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->dreg
);
1236 if (src_var
->backend
.is_pinvoke
)
1237 dest_var
->backend
.is_pinvoke
= 1;
1239 EMIT_NEW_VARLOADA ((cfg
), (src
), src_var
, src_var
->inst_vtype
);
1240 EMIT_NEW_VARLOADA ((cfg
), (dest
), dest_var
, dest_var
->inst_vtype
);
1241 mini_emit_memory_copy (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
, 0);
1246 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1249 g_assert (ins
->klass
);
1251 EMIT_NEW_VARLOADA_VREG (cfg
, dest
, ins
->dreg
, m_class_get_byval_arg (ins
->klass
));
1253 mini_emit_initobj (cfg
, dest
, NULL
, ins
->klass
);
1255 if (cfg
->compute_gc_maps
) {
1259 * Tell the GC map code that the vtype is considered live after
1260 * the initialization.
1262 MONO_INST_NEW (cfg
, tmp
, OP_GC_LIVENESS_DEF
);
1263 tmp
->inst_c1
= ins
->dreg
;
1264 MONO_ADD_INS (cfg
->cbb
, tmp
);
1267 case OP_DUMMY_VZERO
:
1268 if (COMPILE_LLVM (cfg
))
1273 case OP_STOREV_MEMBASE
: {
1274 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1276 mono_class_init_sizes (ins
->klass
);
1278 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
) && !(cfg
->gen_write_barriers
&& m_class_has_references (ins
->klass
)))
1282 g_assert (ins
->klass
);
1283 src_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->sreg1
);
1286 EMIT_NEW_VARLOADA_VREG ((cfg
), (src
), ins
->sreg1
, m_class_get_byval_arg (ins
->klass
));
1288 dreg
= alloc_preg (cfg
);
1289 EMIT_NEW_BIALU_IMM (cfg
, dest
, OP_ADD_IMM
, dreg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1290 mini_emit_memory_copy (cfg
, dest
, src
, src_var
->klass
, src_var
->backend
.is_pinvoke
, 0);
1293 case OP_LOADV_MEMBASE
: {
1294 g_assert (ins
->klass
);
1295 if (COMPILE_LLVM (cfg
) && !mini_is_gsharedvt_klass (ins
->klass
))
1298 dest_var
= get_vreg_to_inst (cfg
, ins
->dreg
);
1302 dest_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->dreg
);
1304 dreg
= alloc_preg (cfg
);
1305 EMIT_NEW_BIALU_IMM (cfg
, src
, OP_ADD_IMM
, dreg
, ins
->inst_basereg
, ins
->inst_offset
);
1306 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1307 mini_emit_memory_copy (cfg
, dest
, src
, dest_var
->klass
, dest_var
->backend
.is_pinvoke
, 0);
1310 case OP_OUTARG_VT
: {
1311 if (COMPILE_LLVM (cfg
))
1314 g_assert (ins
->klass
);
1316 src_var
= get_vreg_to_inst (cfg
, ins
->sreg1
);
1318 src_var
= mono_compile_create_var_for_vreg (cfg
, m_class_get_byval_arg (ins
->klass
), OP_LOCAL
, ins
->sreg1
);
1319 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1321 mono_arch_emit_outarg_vt (cfg
, ins
, src
);
1323 /* This might be decomposed into other vtype opcodes */
1327 case OP_OUTARG_VTRETADDR
: {
1328 MonoCallInst
*call
= (MonoCallInst
*)ins
->inst_p1
;
1330 src_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1332 src_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1333 // FIXME: src_var->backend.is_pinvoke ?
1335 EMIT_NEW_VARLOADA (cfg
, src
, src_var
, src_var
->inst_vtype
);
1336 src
->dreg
= ins
->dreg
;
1341 case OP_VCALL_MEMBASE
: {
1342 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1345 if (COMPILE_LLVM (cfg
))
1348 if (call
->vret_in_reg
) {
1349 MonoCallInst
*call2
;
1352 /* Replace the vcall with a scalar call */
1353 MONO_INST_NEW_CALL (cfg
, call2
, OP_NOP
);
1354 memcpy (call2
, call
, sizeof (MonoCallInst
));
1355 switch (ins
->opcode
) {
1357 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL
: OP_CALL
;
1360 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL_REG
: OP_CALL_REG
;
1362 case OP_VCALL_MEMBASE
:
1363 call2
->inst
.opcode
= call
->vret_in_reg_fp
? OP_FCALL_MEMBASE
: OP_CALL_MEMBASE
;
1366 call2
->inst
.dreg
= alloc_preg (cfg
);
1367 MONO_ADD_INS (cfg
->cbb
, ((MonoInst
*)call2
));
1369 /* Compute the vtype location */
1370 dest_var
= get_vreg_to_inst (cfg
, call
->inst
.dreg
);
1372 dest_var
= mono_compile_create_var_for_vreg (cfg
, call
->signature
->ret
, OP_LOCAL
, call
->inst
.dreg
);
1373 EMIT_NEW_VARLOADA (cfg
, dest
, dest_var
, dest_var
->inst_vtype
);
1375 /* Save the result */
1376 if (dest_var
->backend
.is_pinvoke
)
1377 size
= mono_class_native_size (mono_class_from_mono_type_internal (dest_var
->inst_vtype
), NULL
);
1379 size
= mono_type_size (dest_var
->inst_vtype
, &align
);
1382 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI1_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1385 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI2_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1389 if (call
->vret_in_reg_fp
)
1390 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER4_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1392 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1398 if (call
->vret_in_reg_fp
) {
1399 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORER8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1402 #if SIZEOF_REGISTER == 4
1404 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1405 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1407 switch (call2
->inst
.opcode
) {
1409 call2
->inst
.opcode
= OP_LCALL
;
1412 call2
->inst
.opcode
= OP_LCALL_REG
;
1414 case OP_CALL_MEMBASE
:
1415 call2
->inst
.opcode
= OP_LCALL_MEMBASE
;
1418 call2
->inst
.dreg
= alloc_lreg (cfg
);
1419 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_MS_WORD_OFFSET
, MONO_LVREG_MS (call2
->inst
.dreg
));
1420 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI4_MEMBASE_REG
, dest
->dreg
, MINI_LS_WORD_OFFSET
, MONO_LVREG_LS (call2
->inst
.dreg
));
1422 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STOREI8_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1426 /* This assumes the vtype is sizeof (gpointer) long */
1427 MONO_EMIT_NEW_STORE_MEMBASE (cfg
, OP_STORE_MEMBASE_REG
, dest
->dreg
, 0, call2
->inst
.dreg
);
1431 switch (ins
->opcode
) {
1433 ins
->opcode
= OP_VCALL2
;
1436 ins
->opcode
= OP_VCALL2_REG
;
1438 case OP_VCALL_MEMBASE
:
1439 ins
->opcode
= OP_VCALL2_MEMBASE
;
1447 case OP_BOX_ICONST
: {
1450 /* Temporary value required by emit_box () */
1451 if (ins
->opcode
== OP_BOX_ICONST
) {
1452 NEW_ICONST (cfg
, src
, ins
->inst_c0
);
1453 src
->klass
= ins
->klass
;
1454 MONO_ADD_INS (cfg
->cbb
, src
);
1456 MONO_INST_NEW (cfg
, src
, OP_LOCAL
);
1457 src
->type
= STACK_MP
;
1458 src
->klass
= ins
->klass
;
1459 src
->dreg
= ins
->sreg1
;
1461 MonoInst
*tmp
= mini_emit_box (cfg
, src
, ins
->klass
, mini_class_check_context_used (cfg
, ins
->klass
));
1464 MONO_EMIT_NEW_UNALU (cfg
, OP_MOVE
, ins
->dreg
, tmp
->dreg
);
1466 /* This might be decomposed into other vtype opcodes */
1474 g_assert (cfg
->cbb
== first_bb
);
1476 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1477 /* Replace the original instruction with the new code sequence */
1479 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1480 first_bb
->code
= first_bb
->last_ins
= NULL
;
1481 first_bb
->in_count
= first_bb
->out_count
= 0;
1482 cfg
->cbb
= first_bb
;
1489 if (cfg
->verbose_level
> 2) mono_print_bb (bb
, "AFTER LOWER-VTYPE-OPTS ");
1493 inline static MonoInst
*
1494 mono_get_domainvar (MonoCompile
*cfg
)
1496 if (!cfg
->domainvar
)
1497 cfg
->domainvar
= mono_compile_create_var (cfg
, mono_get_int_type (), OP_LOCAL
);
1498 return cfg
->domainvar
;
1502 * mono_decompose_array_access_opts:
1504 * Decompose array access and other misc opcodes.
1507 mono_decompose_array_access_opts (MonoCompile
*cfg
)
1509 MonoBasicBlock
*bb
, *first_bb
;
1512 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1513 * can be executed anytime. It should be run before decompose_long
1517 * Create a dummy bblock and emit code into it so we can use the normal
1518 * code generation macros.
1520 cfg
->cbb
= (MonoBasicBlock
*)mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1521 first_bb
= cfg
->cbb
;
1523 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1525 MonoInst
*prev
= NULL
;
1527 MonoInst
*iargs
[3];
1530 if (!bb
->needs_decompose
)
1533 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1535 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1541 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1542 switch (ins
->opcode
) {
1543 case OP_TYPED_OBJREF
:
1544 ins
->opcode
= OP_MOVE
;
1547 NEW_LOAD_MEMBASE_FLAGS (cfg
, dest
, OP_LOADI4_MEMBASE
, ins
->dreg
, ins
->sreg1
,
1548 ins
->inst_imm
, ins
->flags
);
1549 MONO_ADD_INS (cfg
->cbb
, dest
);
1551 case OP_BOUNDS_CHECK
:
1552 MONO_EMIT_NULL_CHECK (cfg
, ins
->sreg1
, FALSE
);
1553 if (COMPILE_LLVM (cfg
)) {
1554 int index2_reg
= alloc_preg (cfg
);
1555 MONO_EMIT_NEW_UNALU (cfg
, OP_SEXT_I4
, index2_reg
, ins
->sreg2
);
1556 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, index2_reg
, ins
->flags
& MONO_INST_FAULT
, ins
->inst_p0
);
1558 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg
, ins
->sreg1
, ins
->inst_imm
, ins
->sreg2
, ins
->inst_p0
);
1562 if (cfg
->opt
& MONO_OPT_SHARED
) {
1563 EMIT_NEW_DOMAINCONST (cfg
, iargs
[0]);
1564 EMIT_NEW_CLASSCONST (cfg
, iargs
[1], ins
->inst_newa_class
);
1565 MONO_INST_NEW (cfg
, iargs
[2], OP_MOVE
);
1566 iargs
[2]->dreg
= ins
->sreg1
;
1568 dest
= mono_emit_jit_icall (cfg
, ves_icall_array_new
, iargs
);
1569 dest
->dreg
= ins
->dreg
;
1571 MonoClass
*array_class
= mono_class_create_array (ins
->inst_newa_class
, 1);
1572 ERROR_DECL (vt_error
);
1573 MonoVTable
*vtable
= mono_class_vtable_checked (cfg
->domain
, array_class
, vt_error
);
1574 MonoMethod
*managed_alloc
= mono_gc_get_managed_array_allocator (array_class
);
1576 mono_error_assert_ok (vt_error
); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1577 NEW_VTABLECONST (cfg
, iargs
[0], vtable
);
1578 MONO_ADD_INS (cfg
->cbb
, iargs
[0]);
1579 MONO_INST_NEW (cfg
, iargs
[1], OP_MOVE
);
1580 iargs
[1]->dreg
= ins
->sreg1
;
1583 dest
= mono_emit_method_call (cfg
, managed_alloc
, iargs
, NULL
);
1585 dest
= mono_emit_jit_icall (cfg
, ves_icall_array_new_specific
, iargs
);
1586 dest
->dreg
= ins
->dreg
;
1590 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg
, OP_LOADI4_MEMBASE
, ins
->dreg
,
1591 ins
->sreg1
, MONO_STRUCT_OFFSET (MonoString
, length
), ins
->flags
| MONO_INST_INVARIANT_LOAD
);
1597 g_assert (cfg
->cbb
== first_bb
);
1599 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1600 /* Replace the original instruction with the new code sequence */
1602 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1603 first_bb
->code
= first_bb
->last_ins
= NULL
;
1604 first_bb
->in_count
= first_bb
->out_count
= 0;
1605 cfg
->cbb
= first_bb
;
1612 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1622 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1625 * mono_decompose_soft_float:
1627 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1628 * similar to long support on 32 bit platforms. 32 bit float values require special
1629 * handling when used as locals, arguments, and in calls.
1630 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1633 mono_decompose_soft_float (MonoCompile
*cfg
)
1635 MonoBasicBlock
*bb
, *first_bb
;
1638 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1642 * Create a dummy bblock and emit code into it so we can use the normal
1643 * code generation macros.
1645 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1646 first_bb
= cfg
->cbb
;
1648 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1650 MonoInst
*prev
= NULL
;
1653 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "BEFORE HANDLE-SOFT-FLOAT ");
1655 cfg
->cbb
->code
= cfg
->cbb
->last_ins
= NULL
;
1661 for (ins
= bb
->code
; ins
; ins
= ins
->next
) {
1662 const char *spec
= INS_INFO (ins
->opcode
);
1664 /* Most fp operations are handled automatically by opcode emulation */
1666 switch (ins
->opcode
) {
1669 d
.vald
= *(double*)ins
->inst_p0
;
1670 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1675 /* We load the r8 value */
1676 d
.vald
= *(float*)ins
->inst_p0
;
1677 MONO_EMIT_NEW_I8CONST (cfg
, ins
->dreg
, d
.vall
);
1681 ins
->opcode
= OP_LMOVE
;
1684 ins
->opcode
= OP_MOVE
;
1685 ins
->sreg1
= MONO_LVREG_LS (ins
->sreg1
);
1688 ins
->opcode
= OP_MOVE
;
1689 ins
->sreg1
= MONO_LVREG_MS (ins
->sreg1
);
1692 int reg
= ins
->sreg1
;
1694 ins
->opcode
= OP_SETLRET
;
1696 ins
->sreg1
= MONO_LVREG_LS (reg
);
1697 ins
->sreg2
= MONO_LVREG_MS (reg
);
1700 case OP_LOADR8_MEMBASE
:
1701 ins
->opcode
= OP_LOADI8_MEMBASE
;
1703 case OP_STORER8_MEMBASE_REG
:
1704 ins
->opcode
= OP_STOREI8_MEMBASE_REG
;
1706 case OP_STORER4_MEMBASE_REG
: {
1707 MonoInst
*iargs
[2];
1710 /* Arg 1 is the double value */
1711 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1712 iargs
[0]->dreg
= ins
->sreg1
;
1714 /* Arg 2 is the address to store to */
1715 addr_reg
= mono_alloc_preg (cfg
);
1716 EMIT_NEW_BIALU_IMM (cfg
, iargs
[1], OP_PADD_IMM
, addr_reg
, ins
->inst_destbasereg
, ins
->inst_offset
);
1717 mono_emit_jit_icall (cfg
, mono_fstore_r4
, iargs
);
1721 case OP_LOADR4_MEMBASE
: {
1722 MonoInst
*iargs
[1];
1726 addr_reg
= mono_alloc_preg (cfg
);
1727 EMIT_NEW_BIALU_IMM (cfg
, iargs
[0], OP_PADD_IMM
, addr_reg
, ins
->inst_basereg
, ins
->inst_offset
);
1728 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1729 conv
->dreg
= ins
->dreg
;
1734 case OP_FCALL_MEMBASE
: {
1735 MonoCallInst
*call
= (MonoCallInst
*)ins
;
1736 if (call
->signature
->ret
->type
== MONO_TYPE_R4
) {
1737 MonoCallInst
*call2
;
1738 MonoInst
*iargs
[1];
1742 /* Convert the call into a call returning an int */
1743 MONO_INST_NEW_CALL (cfg
, call2
, OP_CALL
);
1744 memcpy (call2
, call
, sizeof (MonoCallInst
));
1745 switch (ins
->opcode
) {
1747 call2
->inst
.opcode
= OP_CALL
;
1750 call2
->inst
.opcode
= OP_CALL_REG
;
1752 case OP_FCALL_MEMBASE
:
1753 call2
->inst
.opcode
= OP_CALL_MEMBASE
;
1756 g_assert_not_reached ();
1758 call2
->inst
.dreg
= mono_alloc_ireg (cfg
);
1759 MONO_ADD_INS (cfg
->cbb
, (MonoInst
*)call2
);
1761 /* Remap OUTARG_VT instructions referencing this call */
1762 for (l
= call
->outarg_vts
; l
; l
= l
->next
)
1763 ((MonoInst
*)(l
->data
))->inst_p0
= call2
;
1765 /* FIXME: Optimize this */
1767 /* Emit an r4->r8 conversion */
1768 EMIT_NEW_VARLOADA_VREG (cfg
, iargs
[0], call2
->inst
.dreg
, mono_get_int32_type ());
1769 conv
= mono_emit_jit_icall (cfg
, mono_fload_r4
, iargs
);
1770 conv
->dreg
= ins
->dreg
;
1772 /* The call sequence might include fp ins */
1775 switch (ins
->opcode
) {
1777 ins
->opcode
= OP_LCALL
;
1780 ins
->opcode
= OP_LCALL_REG
;
1782 case OP_FCALL_MEMBASE
:
1783 ins
->opcode
= OP_LCALL_MEMBASE
;
1786 g_assert_not_reached ();
1792 MonoJitICallInfo
*info
;
1793 MonoInst
*iargs
[2];
1794 MonoInst
*call
, *cmp
, *br
;
1796 /* Convert fcompare+fbcc to icall+icompare+beq */
1799 /* The branch might be optimized away */
1804 info
= mono_find_jit_opcode_emulation (ins
->next
->opcode
);
1806 /* The branch might be optimized away */
1811 /* Create dummy MonoInst's for the arguments */
1812 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1813 iargs
[0]->dreg
= ins
->sreg1
;
1814 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1815 iargs
[1]->dreg
= ins
->sreg2
;
1817 call
= mono_emit_jit_icall_id (cfg
, mono_jit_icall_info_id (info
), iargs
);
1819 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1820 cmp
->sreg1
= call
->dreg
;
1822 MONO_ADD_INS (cfg
->cbb
, cmp
);
1824 MONO_INST_NEW (cfg
, br
, OP_IBNE_UN
);
1825 br
->inst_many_bb
= mono_mempool_alloc (cfg
->mempool
, sizeof (gpointer
) * 2);
1826 br
->inst_true_bb
= ins
->next
->inst_true_bb
;
1827 br
->inst_false_bb
= ins
->next
->inst_false_bb
;
1828 MONO_ADD_INS (cfg
->cbb
, br
);
1830 /* The call sequence might include fp ins */
1833 /* Skip fbcc or fccc */
1834 NULLIFY_INS (ins
->next
);
1842 MonoJitICallInfo
*info
;
1843 MonoInst
*iargs
[2];
1846 /* Convert fccc to icall+icompare+iceq */
1848 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
1851 /* Create dummy MonoInst's for the arguments */
1852 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1853 iargs
[0]->dreg
= ins
->sreg1
;
1854 MONO_INST_NEW (cfg
, iargs
[1], OP_ARG
);
1855 iargs
[1]->dreg
= ins
->sreg2
;
1857 call
= mono_emit_jit_icall_id (cfg
, mono_jit_icall_info_id (info
), iargs
);
1859 MONO_EMIT_NEW_BIALU_IMM (cfg
, OP_ICOMPARE_IMM
, -1, call
->dreg
, 1);
1860 MONO_EMIT_NEW_UNALU (cfg
, OP_ICEQ
, ins
->dreg
, -1);
1862 /* The call sequence might include fp ins */
1867 MonoInst
*iargs
[2];
1868 MonoInst
*call
, *cmp
;
1870 /* Convert to icall+icompare+cond_exc+move */
1872 /* Create dummy MonoInst's for the arguments */
1873 MONO_INST_NEW (cfg
, iargs
[0], OP_ARG
);
1874 iargs
[0]->dreg
= ins
->sreg1
;
1876 call
= mono_emit_jit_icall (cfg
, mono_isfinite_double
, iargs
);
1878 MONO_INST_NEW (cfg
, cmp
, OP_ICOMPARE_IMM
);
1879 cmp
->sreg1
= call
->dreg
;
1881 MONO_ADD_INS (cfg
->cbb
, cmp
);
1883 MONO_EMIT_NEW_COND_EXC (cfg
, INE_UN
, "ArithmeticException");
1885 /* Do the assignment if the value is finite */
1886 MONO_EMIT_NEW_UNALU (cfg
, OP_FMOVE
, ins
->dreg
, ins
->sreg1
);
1892 if (spec
[MONO_INST_SRC1
] == 'f' || spec
[MONO_INST_SRC2
] == 'f' || spec
[MONO_INST_DEST
] == 'f') {
1893 mono_print_ins (ins
);
1894 g_assert_not_reached ();
1899 g_assert (cfg
->cbb
== first_bb
);
1901 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1902 /* Replace the original instruction with the new code sequence */
1904 mono_replace_ins (cfg
, bb
, ins
, &prev
, first_bb
, cfg
->cbb
);
1905 first_bb
->code
= first_bb
->last_ins
= NULL
;
1906 first_bb
->in_count
= first_bb
->out_count
= 0;
1907 cfg
->cbb
= first_bb
;
1914 if (cfg
->verbose_level
> 3) mono_print_bb (bb
, "AFTER HANDLE-SOFT-FLOAT ");
1917 mono_decompose_long_opts (cfg
);
1923 mono_local_emulate_ops (MonoCompile
*cfg
)
1926 gboolean inlined_wrapper
= FALSE
;
1928 for (bb
= cfg
->bb_entry
; bb
; bb
= bb
->next_bb
) {
1931 MONO_BB_FOR_EACH_INS (bb
, ins
) {
1932 int op_noimm
= mono_op_imm_to_op (ins
->opcode
);
1933 MonoJitICallInfo
*info
;
1936 * These opcodes don't have logical equivalence to the emulating native
1937 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1939 if (MONO_HAS_CUSTOM_EMULATION (ins
))
1943 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1944 * to check whether its non-imm counterpart is emulated and, if so,
1945 * decompose it back to its non-imm counterpart.
1948 info
= mono_find_jit_opcode_emulation (op_noimm
);
1950 info
= mono_find_jit_opcode_emulation (ins
->opcode
);
1955 MonoBasicBlock
*first_bb
;
1957 /* Create dummy MonoInst's for the arguments */
1958 g_assert (!info
->sig
->hasthis
);
1959 g_assert (info
->sig
->param_count
<= MONO_MAX_SRC_REGS
);
1962 mono_decompose_op_imm (cfg
, bb
, ins
);
1964 args
= (MonoInst
**)mono_mempool_alloc0 (cfg
->mempool
, sizeof (MonoInst
*) * info
->sig
->param_count
);
1965 if (info
->sig
->param_count
> 0) {
1966 int sregs
[MONO_MAX_SRC_REGS
];
1968 num_sregs
= mono_inst_get_src_registers (ins
, sregs
);
1969 g_assert (num_sregs
== info
->sig
->param_count
);
1970 for (i
= 0; i
< num_sregs
; ++i
) {
1971 MONO_INST_NEW (cfg
, args
[i
], OP_ARG
);
1972 args
[i
]->dreg
= sregs
[i
];
1976 /* We emit the call on a separate dummy basic block */
1977 cfg
->cbb
= mono_mempool_alloc0 ((cfg
)->mempool
, sizeof (MonoBasicBlock
));
1978 first_bb
= cfg
->cbb
;
1980 call
= mono_emit_jit_icall_by_info (cfg
, bb
->real_offset
, info
, args
);
1981 call
->dreg
= ins
->dreg
;
1983 /* Replace ins with the emitted code and do the necessary bb linking */
1984 if (cfg
->cbb
->code
|| (cfg
->cbb
!= first_bb
)) {
1985 MonoInst
*saved_prev
= ins
->prev
;
1987 mono_replace_ins (cfg
, bb
, ins
, &ins
->prev
, first_bb
, cfg
->cbb
);
1988 first_bb
->code
= first_bb
->last_ins
= NULL
;
1989 first_bb
->in_count
= first_bb
->out_count
= 0;
1990 cfg
->cbb
= first_bb
;
1993 /* first instruction of basic block got replaced, so create
1994 * dummy inst that points to start of basic block */
1995 MONO_INST_NEW (cfg
, saved_prev
, OP_NOP
);
1996 saved_prev
= bb
->code
;
1999 /* ins is hanging, continue scanning the emitted code */
2002 g_error ("Failed to emit emulation code");
2004 inlined_wrapper
= TRUE
;
2010 * Avoid rerunning these passes by emitting directly the exception checkpoint
2011 * at IR level, instead of inlining the icall wrapper. FIXME
2013 if (inlined_wrapper
) {
2014 if (!COMPILE_LLVM (cfg
))
2015 mono_decompose_long_opts (cfg
);
2016 if (cfg
->opt
& (MONO_OPT_CONSPROP
| MONO_OPT_COPYPROP
))
2017 mono_local_cprop (cfg
);
2021 #else /* !DISABLE_JIT */
2023 MONO_EMPTY_SOURCE_FILE (decompose
);
2025 #endif /* !DISABLE_JIT */