[interp] Fix interp logging (#17636)
[mono-project.git] / mono / mini / decompose.c
blob392f89c66cc2da4941a6bd7da904ee8994ef2d5d
1 /**
2 * \file
3 * Functions to decompose complex IR instructions into simpler ones.
5 * Author:
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.
13 #include "mini.h"
14 #include "mini-runtime.h"
15 #include "ir-emit.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>
24 #ifndef DISABLE_JIT
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.
30 static gboolean
31 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
33 MonoInst *repl = NULL;
35 *repl_ins = NULL;
37 switch (ins->opcode) {
38 case OP_LCONV_TO_I4:
39 ins->opcode = OP_SEXT_I4;
40 break;
41 case OP_LCONV_TO_I8:
42 case OP_LCONV_TO_U8:
43 if (TARGET_SIZEOF_VOID_P == 4)
44 ins->opcode = OP_LMOVE;
45 else
46 ins->opcode = OP_MOVE;
47 break;
48 case OP_LCONV_TO_I:
49 if (TARGET_SIZEOF_VOID_P == 4)
50 /* OP_LCONV_TO_I4 */
51 ins->opcode = OP_SEXT_I4;
52 else
53 ins->opcode = OP_MOVE;
54 break;
55 case OP_LCONV_TO_U:
56 if (TARGET_SIZEOF_VOID_P == 4) {
57 /* OP_LCONV_TO_U4 */
58 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
59 NULLIFY_INS (ins);
60 } else {
61 ins->opcode = OP_MOVE;
63 break;
64 case OP_ICONV_TO_I8:
65 ins->opcode = OP_SEXT_I4;
66 break;
67 case OP_ICONV_TO_U8:
68 ins->opcode = OP_ZEXT_I4;
69 break;
70 case OP_LCONV_TO_U4:
71 /* Clean out the upper word */
72 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
73 NULLIFY_INS (ins);
74 break;
75 case OP_LADD_OVF: {
76 int opcode;
78 if (COMPILE_LLVM (cfg))
79 break;
80 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
81 opcode = OP_LADDCC;
82 else
83 opcode = OP_ADDCC;
84 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
85 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
86 NULLIFY_INS (ins);
87 break;
89 case OP_LADD_OVF_UN: {
90 int opcode;
92 if (COMPILE_LLVM (cfg))
93 break;
94 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
95 opcode = OP_LADDCC;
96 else
97 opcode = OP_ADDCC;
98 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
99 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
100 NULLIFY_INS (ins);
101 break;
103 #ifndef __mono_ppc64__
104 case OP_LSUB_OVF: {
105 int opcode;
107 if (COMPILE_LLVM (cfg))
108 break;
109 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
110 opcode = OP_LSUBCC;
111 else
112 opcode = OP_SUBCC;
113 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
114 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
115 NULLIFY_INS (ins);
116 break;
118 case OP_LSUB_OVF_UN: {
119 int opcode;
121 if (COMPILE_LLVM (cfg))
122 break;
123 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
124 opcode = OP_LSUBCC;
125 else
126 opcode = OP_SUBCC;
127 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
128 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
129 NULLIFY_INS (ins);
130 break;
132 #endif
134 case OP_ICONV_TO_OVF_I8:
135 case OP_ICONV_TO_OVF_I:
136 ins->opcode = OP_SEXT_I4;
137 break;
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);
143 NULLIFY_INS (ins);
144 break;
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);
152 NULLIFY_INS (ins);
153 break;
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);
160 NULLIFY_INS (ins);
161 break;
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);
166 NULLIFY_INS (ins);
167 break;
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);
173 NULLIFY_INS (ins);
174 break;
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);
180 NULLIFY_INS (ins);
181 break;
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);
189 NULLIFY_INS (ins);
190 break;
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);
196 NULLIFY_INS (ins);
197 break;
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);
203 NULLIFY_INS (ins);
204 break;
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);
210 NULLIFY_INS (ins);
211 break;
212 case OP_LCONV_TO_OVF_I4:
213 #if TARGET_SIZEOF_VOID_P == 4
214 case OP_LCONV_TO_OVF_I:
215 #endif
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));
221 #else
222 g_assert (COMPILE_LLVM (cfg));
223 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
224 #endif
225 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
226 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
227 NULLIFY_INS (ins);
228 break;
229 case OP_LCONV_TO_OVF_I4_UN:
230 #if TARGET_SIZEOF_VOID_P == 4
231 case OP_LCONV_TO_OVF_I_UN:
232 #endif
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);
236 NULLIFY_INS (ins);
237 break;
238 case OP_LCONV_TO_OVF_U4:
239 #if TARGET_SIZEOF_VOID_P == 4
240 case OP_LCONV_TO_OVF_U:
241 #endif
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);
247 NULLIFY_INS (ins);
248 break;
249 case OP_LCONV_TO_OVF_U4_UN:
250 #if TARGET_SIZEOF_VOID_P == 4
251 case OP_LCONV_TO_OVF_U_UN:
252 #endif
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);
256 NULLIFY_INS (ins);
257 break;
258 #if TARGET_SIZEOF_VOID_P == 8
259 case OP_LCONV_TO_OVF_I:
260 case OP_LCONV_TO_OVF_U_UN:
261 #endif
262 case OP_LCONV_TO_OVF_U8_UN:
263 case OP_LCONV_TO_OVF_I8:
264 ins->opcode = OP_MOVE;
265 break;
266 #if TARGET_SIZEOF_VOID_P == 8
267 case OP_LCONV_TO_OVF_I_UN:
268 #endif
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);
273 NULLIFY_INS (ins);
274 break;
275 case OP_LCONV_TO_OVF_U8:
276 #if TARGET_SIZEOF_VOID_P == 8
277 case OP_LCONV_TO_OVF_U:
278 #endif
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);
282 NULLIFY_INS (ins);
283 break;
284 default:
285 return FALSE;
288 *repl_ins = repl;
289 return TRUE;
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
299 * nullified.
300 * Sets the cfg exception if an opcode is not supported.
302 MonoInst*
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
316 * macros.
318 switch (ins->opcode) {
319 /* this doesn't make sense on ppc and other architectures */
320 #if !defined(MONO_ARCH_NO_IOV_CHECK)
321 case OP_IADD_OVF:
322 if (COMPILE_LLVM (cfg))
323 break;
324 ins->opcode = OP_IADDCC;
325 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
326 break;
327 case OP_IADD_OVF_UN:
328 if (COMPILE_LLVM (cfg))
329 break;
330 ins->opcode = OP_IADDCC;
331 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
332 break;
333 case OP_ISUB_OVF:
334 if (COMPILE_LLVM (cfg))
335 break;
336 ins->opcode = OP_ISUBCC;
337 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
338 break;
339 case OP_ISUB_OVF_UN:
340 if (COMPILE_LLVM (cfg))
341 break;
342 ins->opcode = OP_ISUBCC;
343 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
344 break;
345 #endif
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);
352 NULLIFY_INS (ins);
353 break;
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);
359 NULLIFY_INS (ins);
360 break;
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);
367 NULLIFY_INS (ins);
368 break;
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);
376 NULLIFY_INS (ins);
377 break;
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);
383 NULLIFY_INS (ins);
384 break;
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);
391 NULLIFY_INS (ins);
392 break;
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:
398 #endif
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);
402 NULLIFY_INS (ins);
403 break;
404 case OP_ICONV_TO_I4:
405 case OP_ICONV_TO_U4:
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:
411 #endif
412 ins->opcode = OP_MOVE;
413 break;
414 case OP_ICONV_TO_I:
415 #if TARGET_SIZEOF_VOID_P == 8
416 ins->opcode = OP_SEXT_I4;
417 #else
418 ins->opcode = OP_MOVE;
419 #endif
420 break;
421 case OP_ICONV_TO_U:
422 #if TARGET_SIZEOF_VOID_P == 8
423 ins->opcode = OP_ZEXT_I4;
424 #else
425 ins->opcode = OP_MOVE;
426 #endif
427 break;
429 case OP_FCONV_TO_R8:
430 ins->opcode = OP_FMOVE;
431 break;
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."));
443 break;
445 case OP_IDIV:
446 case OP_IREM:
447 case OP_IDIV_UN:
448 case OP_IREM_UN:
449 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
450 emulate = TRUE;
451 if (!emulate) {
452 if (cfg->backend->need_div_check) {
453 int reg1 = alloc_ireg (cfg);
454 int reg2 = alloc_ireg (cfg);
455 /* b == 0 */
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);
470 NULLIFY_INS (ins);
472 break;
474 #if TARGET_SIZEOF_VOID_P == 8
475 case OP_LDIV:
476 case OP_LREM:
477 case OP_LDIV_UN:
478 case OP_LREM_UN:
479 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
480 emulate = TRUE;
481 if (!emulate) {
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);
486 /* b == 0 */
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);
503 NULLIFY_INS (ins);
505 break;
506 #endif
508 case OP_DIV_IMM:
509 case OP_REM_IMM:
510 case OP_IDIV_IMM:
511 case OP_IREM_IMM:
512 case OP_IDIV_UN_IMM:
513 case OP_IREM_UN_IMM:
514 if (cfg->backend->need_div_check) {
515 int reg1 = alloc_ireg (cfg);
516 /* b == 0 */
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);
530 NULLIFY_INS (ins);
531 } else {
532 emulate = TRUE;
534 break;
535 case OP_ICONV_TO_R_UN:
536 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
537 if (!COMPILE_LLVM (cfg))
538 emulate = TRUE;
539 #endif
540 break;
541 default:
542 emulate = TRUE;
543 break;
546 if (emulate) {
547 #if SIZEOF_REGISTER == 8
548 if (decompose_long_opcode (cfg, ins, &repl))
549 emulate = FALSE;
550 #else
551 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
552 emulate = FALSE;
553 #endif
555 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
556 cfg->has_emulated_ops = TRUE;
559 if (ins->opcode == OP_NOP) {
560 if (repl) {
561 repl->type = type;
562 return repl;
563 } else {
564 /* Use the last emitted instruction */
565 ins = cfg->cbb->last_ins;
566 g_assert (ins);
567 ins->type = type;
568 g_assert (ins->dreg == dreg);
569 return ins;
571 } else {
572 return ins;
576 #if SIZEOF_REGISTER == 4
577 static int lbr_decomp [][2] = {
578 {0, 0}, /* BEQ */
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 */
583 {0, 0}, /* BNE_UN */
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] = {
591 {0, 0}, /* CEQ */
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 */
597 #endif
600 * mono_decompose_long_opts:
602 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
604 void
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));
620 first_bb = cfg->cbb;
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;
632 while (tree) {
633 mono_arch_decompose_long_opts (cfg, tree);
635 switch (tree->opcode) {
636 case OP_I8CONST:
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));
639 break;
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);
643 break;
644 case OP_LMOVE:
645 case OP_LCONV_TO_U8:
646 case OP_LCONV_TO_I8:
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));
651 break;
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));
655 break;
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);
659 break;
661 case OP_ICONV_TO_I8: {
662 guint32 tmpreg = alloc_ireg (cfg);
664 /* branchless code:
665 * low = reg;
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);
673 break;
675 case OP_ICONV_TO_U8:
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);
678 break;
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);
683 break;
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);
689 break;
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);
695 break;
696 case OP_LCONV_TO_I1:
697 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
698 break;
699 case OP_LCONV_TO_U1:
700 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
701 break;
702 case OP_LCONV_TO_I2:
703 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
704 break;
705 case OP_LCONV_TO_U2:
706 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
707 break;
708 case OP_LCONV_TO_I4:
709 case OP_LCONV_TO_U4:
710 case OP_LCONV_TO_I:
711 case OP_LCONV_TO_U:
712 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
713 break;
714 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
715 case OP_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));
717 break;
718 #endif
719 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
720 case OP_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));
722 break;
723 #endif
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));
727 break;
728 #endif
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);
743 /* Positive */
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);
748 /* Negative */
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));
756 break;
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));
767 break;
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);
777 break;
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);
792 /* Positive */
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);
797 /* Negative */
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));
804 break;
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));
816 break;
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);
826 break;
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));
830 break;
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));
838 break;
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));
846 break;
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));
853 break;
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));
860 break;
862 case OP_LADD:
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));
865 break;
866 case OP_LSUB:
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));
869 break;
871 case OP_LADD_OVF:
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");
876 break;
877 case OP_LADD_OVF_UN:
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");
882 break;
883 case OP_LSUB_OVF:
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");
888 break;
889 case OP_LSUB_OVF_UN:
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");
894 break;
895 case OP_LAND:
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));
898 break;
899 case OP_LOR:
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));
902 break;
903 case OP_LXOR:
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));
906 break;
907 case OP_LNOT:
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));
910 break;
911 case OP_LNEG:
912 /* Handled in mono_arch_decompose_long_opts () */
913 g_assert_not_reached ();
914 break;
915 case OP_LMUL:
916 /* Emulated */
917 /* FIXME: Add OP_BIGMUL optimization */
918 break;
920 case OP_LADD_IMM:
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));
923 break;
924 case OP_LSUB_IMM:
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));
927 break;
928 case OP_LAND_IMM:
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));
931 break;
932 case OP_LOR_IMM:
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));
935 break;
936 case OP_LXOR_IMM:
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));
939 break;
940 #ifdef TARGET_POWERPC
941 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
942 case OP_LSHR_UN_IMM:
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
948 * See BUG# 57957.
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);
954 break;
955 #endif
956 case OP_LCOMPARE: {
957 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
959 g_assert (next);
961 switch (next->opcode) {
962 case OP_LBEQ:
963 case OP_LBNE_UN: {
964 int d1, d2;
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);
974 NULLIFY_INS (next);
975 break;
977 case OP_LBGE:
978 case OP_LBGT:
979 case OP_LBLE:
980 case OP_LBLT:
981 case OP_LBGE_UN:
982 case OP_LBGT_UN:
983 case OP_LBLE_UN:
984 case OP_LBLT_UN:
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);
992 NULLIFY_INS (next);
993 break;
994 case OP_LCEQ: {
995 int d1, d2;
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);
1006 NULLIFY_INS (next);
1007 break;
1009 case OP_LCLT:
1010 case OP_LCLT_UN:
1011 case OP_LCGT:
1012 case OP_LCGT_UN: {
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);
1028 NULLIFY_INS (next);
1029 break;
1031 default:
1032 g_assert_not_reached ();
1034 break;
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);
1045 g_assert (next);
1047 switch (next->opcode) {
1048 case OP_LBEQ:
1049 case OP_LBNE_UN: {
1050 int d1, d2;
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);
1060 NULLIFY_INS (next);
1061 break;
1064 case OP_LBGE:
1065 case OP_LBGT:
1066 case OP_LBLE:
1067 case OP_LBLT:
1068 case OP_LBGE_UN:
1069 case OP_LBGT_UN:
1070 case OP_LBLE_UN:
1071 case OP_LBLT_UN:
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);
1079 NULLIFY_INS (next);
1080 break;
1081 case OP_LCEQ: {
1082 int d1, d2;
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);
1093 NULLIFY_INS (next);
1094 break;
1096 case OP_LCLT:
1097 case OP_LCLT_UN:
1098 case OP_LCGT:
1099 case OP_LCGT_UN: {
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);
1115 NULLIFY_INS (next);
1116 break;
1118 default:
1119 g_assert_not_reached ();
1121 break;
1124 default:
1125 break;
1128 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1129 MonoInst *new_prev;
1131 /* Replace the original instruction with the new code sequence */
1133 /* Ignore the new value of prev */
1134 new_prev = 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 */
1138 if (prev)
1139 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1140 else
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;
1147 else {
1148 prev = tree;
1149 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1153 #endif
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.
1166 void
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
1174 * everywhere.
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
1182 * var to 1.
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
1189 * in ins->klass.
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) {
1202 MonoInst *ins;
1203 MonoInst *prev = NULL;
1204 MonoInst *src_var, *dest_var, *src, *dest;
1205 gboolean restart;
1206 int dreg;
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;
1212 restart = TRUE;
1214 while (restart) {
1215 restart = FALSE;
1217 for (ins = bb->code; ins; ins = ins->next) {
1218 #ifdef MONO_ARCH_SIMD_INTRINSICS
1219 mono_simd_decompose_intrinsic (cfg, bb, ins);
1220 #endif
1221 switch (ins->opcode) {
1222 case OP_VMOVE: {
1223 g_assert (ins->klass);
1224 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1225 break;
1226 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1227 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1229 if (!src_var)
1230 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1232 if (!dest_var)
1233 dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1235 // FIXME:
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);
1243 break;
1245 case OP_VZERO:
1246 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1247 break;
1249 g_assert (ins->klass);
1251 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, m_class_get_byval_arg (ins->klass));
1253 if (m_class_get_image (ins->klass) == mono_defaults.corlib && !strcmp (m_class_get_name (ins->klass), "MonoError")) {
1254 // Used in icall wrappers, optimize initialization
1255 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, dest->dreg, MONO_STRUCT_OFFSET (MonoErrorExternal, init), 0);
1256 } else {
1257 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1260 if (cfg->compute_gc_maps) {
1261 MonoInst *tmp;
1264 * Tell the GC map code that the vtype is considered live after
1265 * the initialization.
1267 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1268 tmp->inst_c1 = ins->dreg;
1269 MONO_ADD_INS (cfg->cbb, tmp);
1271 break;
1272 case OP_DUMMY_VZERO:
1273 if (COMPILE_LLVM (cfg))
1274 break;
1276 NULLIFY_INS (ins);
1277 break;
1278 case OP_STOREV_MEMBASE: {
1279 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1281 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !cfg->gen_write_barriers)
1282 break;
1284 if (!src_var) {
1285 g_assert (ins->klass);
1286 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1);
1289 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, m_class_get_byval_arg (ins->klass));
1291 dreg = alloc_preg (cfg);
1292 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1293 mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0);
1294 break;
1296 case OP_LOADV_MEMBASE: {
1297 g_assert (ins->klass);
1298 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1299 break;
1301 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1302 // FIXME-VT:
1303 // FIXME:
1304 if (!dest_var)
1305 dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1307 dreg = alloc_preg (cfg);
1308 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1309 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1310 mini_emit_memory_copy (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke, 0);
1311 break;
1313 case OP_OUTARG_VT: {
1314 if (COMPILE_LLVM (cfg))
1315 break;
1317 g_assert (ins->klass);
1319 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1320 if (!src_var)
1321 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1);
1322 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1324 mono_arch_emit_outarg_vt (cfg, ins, src);
1326 /* This might be decomposed into other vtype opcodes */
1327 restart = TRUE;
1328 break;
1330 case OP_OUTARG_VTRETADDR: {
1331 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1333 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1334 if (!src_var)
1335 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1336 // FIXME: src_var->backend.is_pinvoke ?
1338 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1339 src->dreg = ins->dreg;
1340 break;
1342 case OP_VCALL:
1343 case OP_VCALL_REG:
1344 case OP_VCALL_MEMBASE: {
1345 MonoCallInst *call = (MonoCallInst*)ins;
1346 int size;
1348 if (COMPILE_LLVM (cfg))
1349 break;
1351 if (call->vret_in_reg) {
1352 MonoCallInst *call2;
1354 /* Replace the vcall with a scalar call */
1355 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1356 memcpy (call2, call, sizeof (MonoCallInst));
1357 switch (ins->opcode) {
1358 case OP_VCALL:
1359 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1360 break;
1361 case OP_VCALL_REG:
1362 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1363 break;
1364 case OP_VCALL_MEMBASE:
1365 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1366 break;
1368 call2->inst.dreg = alloc_preg (cfg);
1369 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1371 /* Compute the vtype location */
1372 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1373 if (!dest_var)
1374 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1375 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1377 /* Save the result */
1378 if (dest_var->backend.is_pinvoke)
1379 size = mono_class_native_size (mono_class_from_mono_type_internal (dest_var->inst_vtype), NULL);
1380 else
1381 size = mono_type_size (dest_var->inst_vtype, NULL);
1382 switch (size) {
1383 case 1:
1384 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1385 break;
1386 case 2:
1387 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1388 break;
1389 case 3:
1390 case 4:
1391 if (call->vret_in_reg_fp)
1392 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1393 else
1394 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1395 break;
1396 case 5:
1397 case 6:
1398 case 7:
1399 case 8:
1400 if (call->vret_in_reg_fp) {
1401 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1402 break;
1404 #if SIZEOF_REGISTER == 4
1406 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1407 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1409 switch (call2->inst.opcode) {
1410 case OP_CALL:
1411 call2->inst.opcode = OP_LCALL;
1412 break;
1413 case OP_CALL_REG:
1414 call2->inst.opcode = OP_LCALL_REG;
1415 break;
1416 case OP_CALL_MEMBASE:
1417 call2->inst.opcode = OP_LCALL_MEMBASE;
1418 break;
1420 call2->inst.dreg = alloc_lreg (cfg);
1421 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1422 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1423 #else
1424 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1425 #endif
1426 break;
1427 default:
1428 /* This assumes the vtype is sizeof (gpointer) long */
1429 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1430 break;
1432 } else {
1433 switch (ins->opcode) {
1434 case OP_VCALL:
1435 ins->opcode = OP_VCALL2;
1436 break;
1437 case OP_VCALL_REG:
1438 ins->opcode = OP_VCALL2_REG;
1439 break;
1440 case OP_VCALL_MEMBASE:
1441 ins->opcode = OP_VCALL2_MEMBASE;
1442 break;
1444 ins->dreg = -1;
1446 break;
1448 case OP_BOX:
1449 case OP_BOX_ICONST: {
1450 MonoInst *src;
1452 /* Temporary value required by emit_box () */
1453 if (ins->opcode == OP_BOX_ICONST) {
1454 NEW_ICONST (cfg, src, ins->inst_c0);
1455 src->klass = ins->klass;
1456 MONO_ADD_INS (cfg->cbb, src);
1457 } else {
1458 MONO_INST_NEW (cfg, src, OP_LOCAL);
1459 src->type = STACK_MP;
1460 src->klass = ins->klass;
1461 src->dreg = ins->sreg1;
1463 MonoInst *tmp = mini_emit_box (cfg, src, ins->klass, mini_class_check_context_used (cfg, ins->klass));
1464 g_assert (tmp);
1466 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, tmp->dreg);
1468 /* This might be decomposed into other vtype opcodes */
1469 restart = TRUE;
1470 break;
1472 default:
1473 break;
1476 g_assert (cfg->cbb == first_bb);
1478 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1479 /* Replace the original instruction with the new code sequence */
1481 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1482 first_bb->code = first_bb->last_ins = NULL;
1483 first_bb->in_count = first_bb->out_count = 0;
1484 cfg->cbb = first_bb;
1486 else
1487 prev = ins;
1491 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1495 inline static MonoInst *
1496 mono_get_domainvar (MonoCompile *cfg)
1498 if (!cfg->domainvar)
1499 cfg->domainvar = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
1500 return cfg->domainvar;
1504 * mono_decompose_array_access_opts:
1506 * Decompose array access and other misc opcodes.
1508 void
1509 mono_decompose_array_access_opts (MonoCompile *cfg)
1511 MonoBasicBlock *bb, *first_bb;
1514 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1515 * can be executed anytime. It should be run before decompose_long
1519 * Create a dummy bblock and emit code into it so we can use the normal
1520 * code generation macros.
1522 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1523 first_bb = cfg->cbb;
1525 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1526 MonoInst *ins;
1527 MonoInst *prev = NULL;
1528 MonoInst *dest;
1529 MonoInst *iargs [3];
1530 gboolean restart;
1532 if (!bb->needs_decompose)
1533 continue;
1535 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1537 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1538 restart = TRUE;
1540 while (restart) {
1541 restart = FALSE;
1543 for (ins = bb->code; ins; ins = ins->next) {
1544 switch (ins->opcode) {
1545 case OP_TYPED_OBJREF:
1546 ins->opcode = OP_MOVE;
1547 break;
1548 case OP_LDLEN:
1549 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1550 ins->inst_imm, ins->flags);
1551 MONO_ADD_INS (cfg->cbb, dest);
1552 break;
1553 case OP_BOUNDS_CHECK:
1554 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1, FALSE);
1555 if (COMPILE_LLVM (cfg)) {
1556 int index2_reg = alloc_preg (cfg);
1557 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, ins->sreg2);
1558 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, index2_reg, ins->flags & MONO_INST_FAULT, ins->inst_p0);
1559 } else {
1560 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->inst_p0);
1562 break;
1563 case OP_NEWARR:
1564 if (cfg->opt & MONO_OPT_SHARED) {
1565 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1566 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1567 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1568 iargs [2]->dreg = ins->sreg1;
1570 dest = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
1571 dest->dreg = ins->dreg;
1572 } else {
1573 MonoClass *array_class = mono_class_create_array (ins->inst_newa_class, 1);
1574 ERROR_DECL (vt_error);
1575 MonoVTable *vtable = mono_class_vtable_checked (cfg->domain, array_class, vt_error);
1576 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1578 mono_error_assert_ok (vt_error); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1579 NEW_VTABLECONST (cfg, iargs [0], vtable);
1580 MONO_ADD_INS (cfg->cbb, iargs [0]);
1581 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1582 iargs [1]->dreg = ins->sreg1;
1584 if (managed_alloc)
1585 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1586 else
1587 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1588 dest->dreg = ins->dreg;
1590 break;
1591 case OP_STRLEN:
1592 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1593 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1594 break;
1595 default:
1596 break;
1599 g_assert (cfg->cbb == first_bb);
1601 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1602 /* Replace the original instruction with the new code sequence */
1604 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1605 first_bb->code = first_bb->last_ins = NULL;
1606 first_bb->in_count = first_bb->out_count = 0;
1607 cfg->cbb = first_bb;
1609 else
1610 prev = ins;
1614 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1618 typedef union {
1619 guint32 vali [2];
1620 gint64 vall;
1621 double vald;
1622 } DVal;
1624 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1627 * mono_decompose_soft_float:
1629 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1630 * similar to long support on 32 bit platforms. 32 bit float values require special
1631 * handling when used as locals, arguments, and in calls.
1632 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1634 void
1635 mono_decompose_soft_float (MonoCompile *cfg)
1637 MonoBasicBlock *bb, *first_bb;
1640 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1644 * Create a dummy bblock and emit code into it so we can use the normal
1645 * code generation macros.
1647 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1648 first_bb = cfg->cbb;
1650 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1651 MonoInst *ins;
1652 MonoInst *prev = NULL;
1653 gboolean restart;
1655 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1657 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1658 restart = TRUE;
1660 while (restart) {
1661 restart = FALSE;
1663 for (ins = bb->code; ins; ins = ins->next) {
1664 const char *spec = INS_INFO (ins->opcode);
1666 /* Most fp operations are handled automatically by opcode emulation */
1668 switch (ins->opcode) {
1669 case OP_R8CONST: {
1670 DVal d;
1671 d.vald = *(double*)ins->inst_p0;
1672 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1673 break;
1675 case OP_R4CONST: {
1676 DVal d;
1677 /* We load the r8 value */
1678 d.vald = *(float*)ins->inst_p0;
1679 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1680 break;
1682 case OP_FMOVE:
1683 ins->opcode = OP_LMOVE;
1684 break;
1685 case OP_FGETLOW32:
1686 ins->opcode = OP_MOVE;
1687 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1688 break;
1689 case OP_FGETHIGH32:
1690 ins->opcode = OP_MOVE;
1691 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1692 break;
1693 case OP_SETFRET: {
1694 int reg = ins->sreg1;
1696 ins->opcode = OP_SETLRET;
1697 ins->dreg = -1;
1698 ins->sreg1 = MONO_LVREG_LS (reg);
1699 ins->sreg2 = MONO_LVREG_MS (reg);
1700 break;
1702 case OP_LOADR8_MEMBASE:
1703 ins->opcode = OP_LOADI8_MEMBASE;
1704 break;
1705 case OP_STORER8_MEMBASE_REG:
1706 ins->opcode = OP_STOREI8_MEMBASE_REG;
1707 break;
1708 case OP_STORER4_MEMBASE_REG: {
1709 MonoInst *iargs [2];
1710 int addr_reg;
1712 /* Arg 1 is the double value */
1713 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1714 iargs [0]->dreg = ins->sreg1;
1716 /* Arg 2 is the address to store to */
1717 addr_reg = mono_alloc_preg (cfg);
1718 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1719 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1720 restart = TRUE;
1721 break;
1723 case OP_LOADR4_MEMBASE: {
1724 MonoInst *iargs [1];
1725 MonoInst *conv;
1726 int addr_reg;
1728 addr_reg = mono_alloc_preg (cfg);
1729 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1730 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1731 conv->dreg = ins->dreg;
1732 break;
1734 case OP_FCALL:
1735 case OP_FCALL_REG:
1736 case OP_FCALL_MEMBASE: {
1737 MonoCallInst *call = (MonoCallInst*)ins;
1738 if (call->signature->ret->type == MONO_TYPE_R4) {
1739 MonoCallInst *call2;
1740 MonoInst *iargs [1];
1741 MonoInst *conv;
1742 GSList *l;
1744 /* Convert the call into a call returning an int */
1745 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1746 memcpy (call2, call, sizeof (MonoCallInst));
1747 switch (ins->opcode) {
1748 case OP_FCALL:
1749 call2->inst.opcode = OP_CALL;
1750 break;
1751 case OP_FCALL_REG:
1752 call2->inst.opcode = OP_CALL_REG;
1753 break;
1754 case OP_FCALL_MEMBASE:
1755 call2->inst.opcode = OP_CALL_MEMBASE;
1756 break;
1757 default:
1758 g_assert_not_reached ();
1760 call2->inst.dreg = mono_alloc_ireg (cfg);
1761 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1763 /* Remap OUTARG_VT instructions referencing this call */
1764 for (l = call->outarg_vts; l; l = l->next)
1765 ((MonoInst*)(l->data))->inst_p0 = call2;
1767 /* FIXME: Optimize this */
1769 /* Emit an r4->r8 conversion */
1770 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, mono_get_int32_type ());
1771 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1772 conv->dreg = ins->dreg;
1774 /* The call sequence might include fp ins */
1775 restart = TRUE;
1776 } else {
1777 switch (ins->opcode) {
1778 case OP_FCALL:
1779 ins->opcode = OP_LCALL;
1780 break;
1781 case OP_FCALL_REG:
1782 ins->opcode = OP_LCALL_REG;
1783 break;
1784 case OP_FCALL_MEMBASE:
1785 ins->opcode = OP_LCALL_MEMBASE;
1786 break;
1787 default:
1788 g_assert_not_reached ();
1791 break;
1793 case OP_FCOMPARE: {
1794 MonoJitICallInfo *info;
1795 MonoInst *iargs [2];
1796 MonoInst *call, *cmp, *br;
1798 /* Convert fcompare+fbcc to icall+icompare+beq */
1800 if (!ins->next) {
1801 /* The branch might be optimized away */
1802 NULLIFY_INS (ins);
1803 break;
1806 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1807 if (!info) {
1808 /* The branch might be optimized away */
1809 NULLIFY_INS (ins);
1810 break;
1813 /* Create dummy MonoInst's for the arguments */
1814 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1815 iargs [0]->dreg = ins->sreg1;
1816 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1817 iargs [1]->dreg = ins->sreg2;
1819 call = mono_emit_jit_icall_id (cfg, mono_jit_icall_info_id (info), iargs);
1821 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1822 cmp->sreg1 = call->dreg;
1823 cmp->inst_imm = 0;
1824 MONO_ADD_INS (cfg->cbb, cmp);
1826 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1827 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1828 br->inst_true_bb = ins->next->inst_true_bb;
1829 br->inst_false_bb = ins->next->inst_false_bb;
1830 MONO_ADD_INS (cfg->cbb, br);
1832 /* The call sequence might include fp ins */
1833 restart = TRUE;
1835 /* Skip fbcc or fccc */
1836 NULLIFY_INS (ins->next);
1837 break;
1839 case OP_FCEQ:
1840 case OP_FCGT:
1841 case OP_FCGT_UN:
1842 case OP_FCLT:
1843 case OP_FCLT_UN: {
1844 MonoJitICallInfo *info;
1845 MonoInst *iargs [2];
1846 MonoInst *call;
1848 /* Convert fccc to icall+icompare+iceq */
1850 info = mono_find_jit_opcode_emulation (ins->opcode);
1851 g_assert (info);
1853 /* Create dummy MonoInst's for the arguments */
1854 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1855 iargs [0]->dreg = ins->sreg1;
1856 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1857 iargs [1]->dreg = ins->sreg2;
1859 call = mono_emit_jit_icall_id (cfg, mono_jit_icall_info_id (info), iargs);
1861 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1862 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1864 /* The call sequence might include fp ins */
1865 restart = TRUE;
1866 break;
1868 case OP_CKFINITE: {
1869 MonoInst *iargs [2];
1870 MonoInst *call, *cmp;
1872 /* Convert to icall+icompare+cond_exc+move */
1874 /* Create dummy MonoInst's for the arguments */
1875 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1876 iargs [0]->dreg = ins->sreg1;
1878 call = mono_emit_jit_icall (cfg, mono_isfinite_double, iargs);
1880 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1881 cmp->sreg1 = call->dreg;
1882 cmp->inst_imm = 1;
1883 MONO_ADD_INS (cfg->cbb, cmp);
1885 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1887 /* Do the assignment if the value is finite */
1888 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1890 restart = TRUE;
1891 break;
1893 default:
1894 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1895 mono_print_ins (ins);
1896 g_assert_not_reached ();
1898 break;
1901 g_assert (cfg->cbb == first_bb);
1903 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1904 /* Replace the original instruction with the new code sequence */
1906 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1907 first_bb->code = first_bb->last_ins = NULL;
1908 first_bb->in_count = first_bb->out_count = 0;
1909 cfg->cbb = first_bb;
1911 else
1912 prev = ins;
1916 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1919 mono_decompose_long_opts (cfg);
1922 #endif
1924 void
1925 mono_local_emulate_ops (MonoCompile *cfg)
1927 MonoBasicBlock *bb;
1928 gboolean inlined_wrapper = FALSE;
1930 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1931 MonoInst *ins;
1933 MONO_BB_FOR_EACH_INS (bb, ins) {
1934 int op_noimm = mono_op_imm_to_op (ins->opcode);
1935 MonoJitICallInfo *info;
1938 * These opcodes don't have logical equivalence to the emulating native
1939 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1941 if (MONO_HAS_CUSTOM_EMULATION (ins))
1942 continue;
1945 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1946 * to check whether its non-imm counterpart is emulated and, if so,
1947 * decompose it back to its non-imm counterpart.
1949 if (op_noimm != -1)
1950 info = mono_find_jit_opcode_emulation (op_noimm);
1951 else
1952 info = mono_find_jit_opcode_emulation (ins->opcode);
1954 if (info) {
1955 MonoInst **args;
1956 MonoInst *call;
1957 MonoBasicBlock *first_bb;
1959 /* Create dummy MonoInst's for the arguments */
1960 g_assert (!info->sig->hasthis);
1961 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1963 if (op_noimm != -1)
1964 mono_decompose_op_imm (cfg, bb, ins);
1966 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1967 if (info->sig->param_count > 0) {
1968 int sregs [MONO_MAX_SRC_REGS];
1969 int num_sregs, i;
1970 num_sregs = mono_inst_get_src_registers (ins, sregs);
1971 g_assert (num_sregs == info->sig->param_count);
1972 for (i = 0; i < num_sregs; ++i) {
1973 MONO_INST_NEW (cfg, args [i], OP_ARG);
1974 args [i]->dreg = sregs [i];
1978 /* We emit the call on a separate dummy basic block */
1979 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1980 first_bb = cfg->cbb;
1982 call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
1983 call->dreg = ins->dreg;
1985 /* Replace ins with the emitted code and do the necessary bb linking */
1986 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1987 MonoInst *saved_prev = ins->prev;
1989 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1990 first_bb->code = first_bb->last_ins = NULL;
1991 first_bb->in_count = first_bb->out_count = 0;
1992 cfg->cbb = first_bb;
1994 if (!saved_prev) {
1995 /* first instruction of basic block got replaced, so create
1996 * dummy inst that points to start of basic block */
1997 MONO_INST_NEW (cfg, saved_prev, OP_NOP);
1998 saved_prev = bb->code;
2001 /* ins is hanging, continue scanning the emitted code */
2002 ins = saved_prev;
2003 } else {
2004 g_error ("Failed to emit emulation code");
2006 inlined_wrapper = TRUE;
2012 * Avoid rerunning these passes by emitting directly the exception checkpoint
2013 * at IR level, instead of inlining the icall wrapper. FIXME
2015 if (inlined_wrapper) {
2016 if (!COMPILE_LLVM (cfg))
2017 mono_decompose_long_opts (cfg);
2018 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
2019 mono_local_cprop (cfg);
2023 #else /* !DISABLE_JIT */
2025 MONO_EMPTY_SOURCE_FILE (decompose);
2027 #endif /* !DISABLE_JIT */