[LoongArch64] Part-5:add loongarch support in some files for LoongArch64. (#21769)
[mono-project.git] / mono / mini / decompose.c
blobb36a7ecc255a33678ab3cee5f3f4774c005a21e0
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_IDIV:
434 case OP_IREM:
435 case OP_IDIV_UN:
436 case OP_IREM_UN:
437 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
438 emulate = TRUE;
439 if (!emulate) {
440 if (cfg->backend->need_div_check) {
441 int reg1 = alloc_ireg (cfg);
442 int reg2 = alloc_ireg (cfg);
443 /* b == 0 */
444 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
445 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
446 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
447 /* b == -1 && a == 0x80000000 */
448 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
449 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
450 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
451 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
452 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
453 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
454 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
457 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
458 NULLIFY_INS (ins);
460 break;
462 #if TARGET_SIZEOF_VOID_P == 8
463 case OP_LDIV:
464 case OP_LREM:
465 case OP_LDIV_UN:
466 case OP_LREM_UN:
467 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
468 emulate = TRUE;
469 if (!emulate) {
470 if (cfg->backend->need_div_check) {
471 int reg1 = alloc_ireg (cfg);
472 int reg2 = alloc_ireg (cfg);
473 int reg3 = alloc_ireg (cfg);
474 /* b == 0 */
475 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
476 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
477 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
478 /* b == -1 && a == 0x80000000 */
479 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
480 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
481 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
482 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
483 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
484 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
485 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
486 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
487 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
490 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
491 NULLIFY_INS (ins);
493 break;
494 #endif
496 case OP_DIV_IMM:
497 case OP_REM_IMM:
498 case OP_IDIV_IMM:
499 case OP_IREM_IMM:
500 case OP_IDIV_UN_IMM:
501 case OP_IREM_UN_IMM:
502 if (cfg->backend->need_div_check) {
503 int reg1 = alloc_ireg (cfg);
504 /* b == 0 */
505 if (ins->inst_imm == 0) {
506 // FIXME: Optimize this
507 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
508 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
509 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
511 if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
512 (ins->inst_imm == -1)) {
513 /* b == -1 && a == 0x80000000 */
514 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
515 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
517 MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
518 NULLIFY_INS (ins);
519 } else {
520 emulate = TRUE;
522 break;
523 case OP_ICONV_TO_R_UN:
524 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
525 if (!COMPILE_LLVM (cfg))
526 emulate = TRUE;
527 #endif
528 break;
529 default:
530 emulate = TRUE;
531 break;
534 if (emulate) {
535 #if SIZEOF_REGISTER == 8
536 if (decompose_long_opcode (cfg, ins, &repl))
537 emulate = FALSE;
538 #else
539 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
540 emulate = FALSE;
541 #endif
543 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
544 cfg->has_emulated_ops = TRUE;
547 if (ins->opcode == OP_NOP) {
548 if (repl) {
549 repl->type = type;
550 return repl;
551 } else {
552 /* Use the last emitted instruction */
553 ins = cfg->cbb->last_ins;
554 g_assert (ins);
555 ins->type = type;
556 g_assert (ins->dreg == dreg);
557 return ins;
559 } else {
560 return ins;
564 #if SIZEOF_REGISTER == 4
565 static int lbr_decomp [][2] = {
566 {0, 0}, /* BEQ */
567 {OP_IBGT, OP_IBGE_UN}, /* BGE */
568 {OP_IBGT, OP_IBGT_UN}, /* BGT */
569 {OP_IBLT, OP_IBLE_UN}, /* BLE */
570 {OP_IBLT, OP_IBLT_UN}, /* BLT */
571 {0, 0}, /* BNE_UN */
572 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
573 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
574 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
575 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
578 static int lcset_decomp [][2] = {
579 {0, 0}, /* CEQ */
580 {OP_IBLT, OP_IBLE_UN}, /* CGT */
581 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
582 {OP_IBGT, OP_IBGE_UN}, /* CLT */
583 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
585 #endif
588 * mono_decompose_long_opts:
590 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
592 void
593 mono_decompose_long_opts (MonoCompile *cfg)
595 #if SIZEOF_REGISTER == 4
596 MonoBasicBlock *bb, *first_bb;
599 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
600 * needs to be able to handle long vregs.
604 * Create a dummy bblock and emit code into it so we can use the normal
605 * code generation macros.
607 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
608 first_bb = cfg->cbb;
610 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
611 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
612 MonoInst *prev = NULL;
615 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
618 cfg->cbb->code = cfg->cbb->last_ins = NULL;
620 while (tree) {
621 mono_arch_decompose_long_opts (cfg, tree);
623 switch (tree->opcode) {
624 case OP_I8CONST:
625 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), ins_get_l_low (tree));
626 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), ins_get_l_high (tree));
627 break;
628 case OP_DUMMY_I8CONST:
629 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
630 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
631 break;
632 case OP_LMOVE:
633 case OP_LCONV_TO_U8:
634 case OP_LCONV_TO_I8:
635 case OP_LCONV_TO_OVF_U8_UN:
636 case OP_LCONV_TO_OVF_I8:
637 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
638 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
639 break;
640 case OP_STOREI8_MEMBASE_REG:
641 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));
642 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));
643 break;
644 case OP_LOADI8_MEMBASE:
645 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);
646 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);
647 break;
649 case OP_ICONV_TO_I8: {
650 guint32 tmpreg = alloc_ireg (cfg);
652 /* branchless code:
653 * low = reg;
654 * tmp = low > -1 ? 1: 0;
655 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
657 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
658 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
659 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
660 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
661 break;
663 case OP_ICONV_TO_U8:
664 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
665 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
666 break;
667 case OP_ICONV_TO_OVF_I8:
668 /* a signed 32 bit num always fits in a signed 64 bit one */
669 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
670 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
671 break;
672 case OP_ICONV_TO_OVF_U8:
673 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
674 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
675 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
676 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
677 break;
678 case OP_ICONV_TO_OVF_I8_UN:
679 case OP_ICONV_TO_OVF_U8_UN:
680 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
681 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
682 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
683 break;
684 case OP_LCONV_TO_I1:
685 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
686 break;
687 case OP_LCONV_TO_U1:
688 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
689 break;
690 case OP_LCONV_TO_I2:
691 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
692 break;
693 case OP_LCONV_TO_U2:
694 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
695 break;
696 case OP_LCONV_TO_I4:
697 case OP_LCONV_TO_U4:
698 case OP_LCONV_TO_I:
699 case OP_LCONV_TO_U:
700 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
701 break;
702 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
703 case OP_LCONV_TO_R8:
704 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
705 break;
706 #endif
707 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
708 case OP_LCONV_TO_R4:
709 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
710 break;
711 #endif
712 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
713 case OP_LCONV_TO_R_UN:
714 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
715 break;
716 #endif
717 case OP_LCONV_TO_OVF_I1: {
718 MonoBasicBlock *is_negative, *end_label;
720 NEW_BBLOCK (cfg, is_negative);
721 NEW_BBLOCK (cfg, end_label);
723 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
724 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
725 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
726 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
728 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
729 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
731 /* Positive */
732 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
733 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
734 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
736 /* Negative */
737 MONO_START_BB (cfg, is_negative);
738 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
739 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
741 MONO_START_BB (cfg, end_label);
743 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
744 break;
746 case OP_LCONV_TO_OVF_I1_UN:
747 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
748 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
750 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
751 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
752 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
753 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
754 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
755 break;
756 case OP_LCONV_TO_OVF_U1:
757 case OP_LCONV_TO_OVF_U1_UN:
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
759 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
761 /* probe value to be within 0 to 255 */
762 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
763 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
764 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
765 break;
766 case OP_LCONV_TO_OVF_I2: {
767 MonoBasicBlock *is_negative, *end_label;
769 NEW_BBLOCK (cfg, is_negative);
770 NEW_BBLOCK (cfg, end_label);
772 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
773 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
774 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
775 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
777 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
778 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
780 /* Positive */
781 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
782 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
783 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
785 /* Negative */
786 MONO_START_BB (cfg, is_negative);
787 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
788 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
789 MONO_START_BB (cfg, end_label);
791 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
792 break;
794 case OP_LCONV_TO_OVF_I2_UN:
795 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
796 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
798 /* Probe value to be within -32768 and 32767 */
799 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
800 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
801 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
802 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
803 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
804 break;
805 case OP_LCONV_TO_OVF_U2:
806 case OP_LCONV_TO_OVF_U2_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 0 and 65535 */
811 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
812 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
813 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
814 break;
815 case OP_LCONV_TO_OVF_I4:
816 case OP_LCONV_TO_OVF_I:
817 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
818 break;
819 case OP_LCONV_TO_OVF_U4:
820 case OP_LCONV_TO_OVF_U:
821 case OP_LCONV_TO_OVF_U4_UN:
822 case OP_LCONV_TO_OVF_U_UN:
823 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
824 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
825 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
826 break;
827 case OP_LCONV_TO_OVF_I_UN:
828 case OP_LCONV_TO_OVF_I4_UN:
829 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
830 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
831 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
832 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
833 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
834 break;
835 case OP_LCONV_TO_OVF_U8:
836 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
837 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
839 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
840 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
841 break;
842 case OP_LCONV_TO_OVF_I8_UN:
843 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
844 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
846 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
847 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
848 break;
850 case OP_LADD:
851 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
852 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
853 break;
854 case OP_LSUB:
855 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
856 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
857 break;
859 case OP_LADD_OVF:
860 /* ADC sets the condition code */
861 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
862 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
863 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
864 break;
865 case OP_LADD_OVF_UN:
866 /* ADC sets the condition code */
867 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
868 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
869 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
870 break;
871 case OP_LSUB_OVF:
872 /* SBB sets the condition code */
873 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
874 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, 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_LSUB_OVF_UN:
878 /* SBB sets the condition code */
879 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
880 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, 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_LAND:
884 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
885 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
886 break;
887 case OP_LOR:
888 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
889 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
890 break;
891 case OP_LXOR:
892 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
893 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
894 break;
895 case OP_LNOT:
896 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
897 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
898 break;
899 case OP_LNEG:
900 /* Handled in mono_arch_decompose_long_opts () */
901 g_assert_not_reached ();
902 break;
903 case OP_LMUL:
904 /* Emulated */
905 /* FIXME: Add OP_BIGMUL optimization */
906 break;
908 case OP_LADD_IMM:
909 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), ins_get_l_low (tree));
910 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), ins_get_l_high (tree));
911 break;
912 case OP_LSUB_IMM:
913 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), ins_get_l_low (tree));
914 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), ins_get_l_high (tree));
915 break;
916 case OP_LAND_IMM:
917 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), ins_get_l_low (tree));
918 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), ins_get_l_high (tree));
919 break;
920 case OP_LOR_IMM:
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), ins_get_l_low (tree));
922 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), ins_get_l_high (tree));
923 break;
924 case OP_LXOR_IMM:
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), ins_get_l_low (tree));
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), ins_get_l_high (tree));
927 break;
928 #ifdef TARGET_POWERPC
929 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
930 case OP_LSHR_UN_IMM:
931 if (tree->inst_c1 == 32) {
933 /* The original code had this comment: */
934 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
935 * later apply the speedup to the left shift as well
936 * See BUG# 57957.
938 /* just move the upper half to the lower and zero the high word */
939 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
940 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
942 break;
943 #endif
944 case OP_LCOMPARE: {
945 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
947 g_assert (next);
949 switch (next->opcode) {
950 case OP_LBEQ:
951 case OP_LBNE_UN: {
952 int d1, d2;
954 /* Branchless version based on gcc code */
955 d1 = alloc_ireg (cfg);
956 d2 = alloc_ireg (cfg);
957 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
958 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
959 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
960 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
961 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
962 NULLIFY_INS (next);
963 break;
965 case OP_LBGE:
966 case OP_LBGT:
967 case OP_LBLE:
968 case OP_LBLT:
969 case OP_LBGE_UN:
970 case OP_LBGT_UN:
971 case OP_LBLE_UN:
972 case OP_LBLT_UN:
973 /* Convert into three comparisons + branches */
974 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
975 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
976 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
977 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
978 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
979 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
980 NULLIFY_INS (next);
981 break;
982 case OP_LCEQ: {
983 int d1, d2;
985 /* Branchless version based on gcc code */
986 d1 = alloc_ireg (cfg);
987 d2 = alloc_ireg (cfg);
988 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
989 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
990 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
992 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
993 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
994 NULLIFY_INS (next);
995 break;
997 case OP_LCLT:
998 case OP_LCLT_UN:
999 case OP_LCGT:
1000 case OP_LCGT_UN: {
1001 MonoBasicBlock *set_to_0, *set_to_1;
1003 NEW_BBLOCK (cfg, set_to_0);
1004 NEW_BBLOCK (cfg, set_to_1);
1006 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1007 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1008 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1009 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1010 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1011 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1012 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1013 MONO_START_BB (cfg, set_to_1);
1014 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1015 MONO_START_BB (cfg, set_to_0);
1016 NULLIFY_INS (next);
1017 break;
1019 default:
1020 g_assert_not_reached ();
1022 break;
1025 /* Not yet used, since lcompare is decomposed before local cprop */
1026 case OP_LCOMPARE_IMM: {
1027 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1028 guint32 low_imm = ins_get_l_low (tree);
1029 guint32 high_imm = ins_get_l_high (tree);
1030 int low_reg = MONO_LVREG_LS (tree->sreg1);
1031 int high_reg = MONO_LVREG_MS (tree->sreg1);
1033 g_assert (next);
1035 switch (next->opcode) {
1036 case OP_LBEQ:
1037 case OP_LBNE_UN: {
1038 int d1, d2;
1040 /* Branchless version based on gcc code */
1041 d1 = alloc_ireg (cfg);
1042 d2 = alloc_ireg (cfg);
1043 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1044 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1045 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1046 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1047 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1048 NULLIFY_INS (next);
1049 break;
1052 case OP_LBGE:
1053 case OP_LBGT:
1054 case OP_LBLE:
1055 case OP_LBLT:
1056 case OP_LBGE_UN:
1057 case OP_LBGT_UN:
1058 case OP_LBLE_UN:
1059 case OP_LBLT_UN:
1060 /* Convert into three comparisons + branches */
1061 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1062 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1063 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1064 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1065 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1066 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1067 NULLIFY_INS (next);
1068 break;
1069 case OP_LCEQ: {
1070 int d1, d2;
1072 /* Branchless version based on gcc code */
1073 d1 = alloc_ireg (cfg);
1074 d2 = alloc_ireg (cfg);
1075 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1076 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1077 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1079 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1080 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1081 NULLIFY_INS (next);
1082 break;
1084 case OP_LCLT:
1085 case OP_LCLT_UN:
1086 case OP_LCGT:
1087 case OP_LCGT_UN: {
1088 MonoBasicBlock *set_to_0, *set_to_1;
1090 NEW_BBLOCK (cfg, set_to_0);
1091 NEW_BBLOCK (cfg, set_to_1);
1093 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1094 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1095 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1096 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1097 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1098 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1099 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1100 MONO_START_BB (cfg, set_to_1);
1101 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1102 MONO_START_BB (cfg, set_to_0);
1103 NULLIFY_INS (next);
1104 break;
1106 default:
1107 g_assert_not_reached ();
1109 break;
1112 default:
1113 break;
1116 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1117 MonoInst *new_prev;
1119 /* Replace the original instruction with the new code sequence */
1121 /* Ignore the new value of prev */
1122 new_prev = prev;
1123 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1125 /* Process the newly added ops again since they can be long ops too */
1126 if (prev)
1127 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1128 else
1129 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1131 first_bb->code = first_bb->last_ins = NULL;
1132 first_bb->in_count = first_bb->out_count = 0;
1133 cfg->cbb = first_bb;
1135 else {
1136 prev = tree;
1137 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1141 #endif
1144 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1145 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1150 * mono_decompose_vtype_opts:
1152 * Decompose valuetype opcodes.
1154 void
1155 mono_decompose_vtype_opts (MonoCompile *cfg)
1157 MonoBasicBlock *bb, *first_bb;
1160 * Using OP_V opcodes and decomposing them later have two main benefits:
1161 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1162 * everywhere.
1163 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1164 * enabling optimizations to work on vtypes too.
1165 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1166 * can be executed anytime. It should be executed as late as possible so vtype
1167 * opcodes can be optimized by the other passes.
1168 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1169 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1170 * var to 1.
1171 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1172 * when OP_VMOVE opcodes are decomposed.
1176 * Vregs have no associated type information, so we store the type of the vregs
1177 * in ins->klass.
1181 * Create a dummy bblock and emit code into it so we can use the normal
1182 * code generation macros.
1184 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1185 first_bb = cfg->cbb;
1187 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1189 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1190 MonoInst *ins;
1191 MonoInst *prev = NULL;
1192 MonoInst *src_var, *dest_var, *src, *dest;
1193 gboolean restart;
1194 int dreg;
1196 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1198 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1199 cfg->cbb->out_of_line = bb->out_of_line;
1200 restart = TRUE;
1202 while (restart) {
1203 restart = FALSE;
1205 for (ins = bb->code; ins; ins = ins->next) {
1206 #ifdef MONO_ARCH_SIMD_INTRINSICS
1207 mono_simd_decompose_intrinsic (cfg, bb, ins);
1208 #endif
1209 switch (ins->opcode) {
1210 case OP_VMOVE: {
1211 g_assert (ins->klass);
1212 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1213 break;
1214 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1215 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1217 if (!src_var)
1218 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1220 if (!dest_var)
1221 dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1223 // FIXME:
1224 if (src_var->backend.is_pinvoke)
1225 dest_var->backend.is_pinvoke = 1;
1227 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1228 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1229 mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0);
1231 break;
1233 case OP_VZERO:
1234 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1235 break;
1237 g_assert (ins->klass);
1239 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, m_class_get_byval_arg (ins->klass));
1241 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1243 if (cfg->compute_gc_maps) {
1244 MonoInst *tmp;
1247 * Tell the GC map code that the vtype is considered live after
1248 * the initialization.
1250 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1251 tmp->inst_c1 = ins->dreg;
1252 MONO_ADD_INS (cfg->cbb, tmp);
1254 break;
1255 case OP_DUMMY_VZERO:
1256 if (COMPILE_LLVM (cfg))
1257 break;
1259 NULLIFY_INS (ins);
1260 break;
1261 case OP_STOREV_MEMBASE: {
1262 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1264 mono_class_init_sizes (ins->klass);
1266 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !(cfg->gen_write_barriers && m_class_has_references (ins->klass)))
1267 break;
1269 if (!src_var) {
1270 g_assert (ins->klass);
1271 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1);
1274 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, m_class_get_byval_arg (ins->klass));
1276 dreg = alloc_preg (cfg);
1277 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1278 mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, ins->flags);
1279 break;
1281 case OP_LOADV_MEMBASE: {
1282 g_assert (ins->klass);
1283 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1284 break;
1286 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1287 // FIXME-VT:
1288 // FIXME:
1289 if (!dest_var)
1290 dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1292 dreg = alloc_preg (cfg);
1293 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1294 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1295 mini_emit_memory_copy (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke, 0);
1296 break;
1298 case OP_OUTARG_VT: {
1299 if (COMPILE_LLVM (cfg))
1300 break;
1302 g_assert (ins->klass);
1304 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1305 if (!src_var)
1306 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1);
1307 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1309 mono_arch_emit_outarg_vt (cfg, ins, src);
1311 /* This might be decomposed into other vtype opcodes */
1312 restart = TRUE;
1313 break;
1315 case OP_OUTARG_VTRETADDR: {
1316 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1318 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1319 if (!src_var)
1320 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1321 // FIXME: src_var->backend.is_pinvoke ?
1323 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1324 src->dreg = ins->dreg;
1325 break;
1327 case OP_VCALL:
1328 case OP_VCALL_REG:
1329 case OP_VCALL_MEMBASE: {
1330 MonoCallInst *call = (MonoCallInst*)ins;
1331 int size;
1333 if (COMPILE_LLVM (cfg))
1334 break;
1336 if (call->vret_in_reg) {
1337 MonoCallInst *call2;
1338 int align;
1340 /* Replace the vcall with a scalar call */
1341 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1342 memcpy (call2, call, sizeof (MonoCallInst));
1343 switch (ins->opcode) {
1344 case OP_VCALL:
1345 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1346 break;
1347 case OP_VCALL_REG:
1348 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1349 break;
1350 case OP_VCALL_MEMBASE:
1351 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1352 break;
1354 call2->inst.dreg = alloc_preg (cfg);
1355 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1357 /* Compute the vtype location */
1358 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1359 if (!dest_var)
1360 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1361 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1363 /* Save the result */
1364 if (dest_var->backend.is_pinvoke)
1365 size = mono_class_native_size (mono_class_from_mono_type_internal (dest_var->inst_vtype), NULL);
1366 else
1367 size = mono_type_size (dest_var->inst_vtype, &align);
1368 switch (size) {
1369 case 1:
1370 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1371 break;
1372 case 2:
1373 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1374 break;
1375 case 3:
1376 case 4:
1377 if (call->vret_in_reg_fp)
1378 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1379 else
1380 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1381 break;
1382 case 5:
1383 case 6:
1384 case 7:
1385 case 8:
1386 if (call->vret_in_reg_fp) {
1387 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1388 break;
1390 #if SIZEOF_REGISTER == 4
1392 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1393 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1395 switch (call2->inst.opcode) {
1396 case OP_CALL:
1397 call2->inst.opcode = OP_LCALL;
1398 break;
1399 case OP_CALL_REG:
1400 call2->inst.opcode = OP_LCALL_REG;
1401 break;
1402 case OP_CALL_MEMBASE:
1403 call2->inst.opcode = OP_LCALL_MEMBASE;
1404 break;
1406 call2->inst.dreg = alloc_lreg (cfg);
1407 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1408 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1409 #else
1410 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1411 #endif
1412 break;
1413 default:
1414 /* This assumes the vtype is sizeof (gpointer) long */
1415 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1416 break;
1418 } else {
1419 switch (ins->opcode) {
1420 case OP_VCALL:
1421 ins->opcode = OP_VCALL2;
1422 break;
1423 case OP_VCALL_REG:
1424 ins->opcode = OP_VCALL2_REG;
1425 break;
1426 case OP_VCALL_MEMBASE:
1427 ins->opcode = OP_VCALL2_MEMBASE;
1428 break;
1430 ins->dreg = -1;
1432 break;
1434 case OP_BOX:
1435 case OP_BOX_ICONST: {
1436 MonoInst *src;
1438 /* Temporary value required by emit_box () */
1439 if (ins->opcode == OP_BOX_ICONST) {
1440 NEW_ICONST (cfg, src, ins->inst_c0);
1441 src->klass = ins->klass;
1442 MONO_ADD_INS (cfg->cbb, src);
1443 } else {
1444 MONO_INST_NEW (cfg, src, OP_LOCAL);
1445 src->type = STACK_MP;
1446 src->klass = ins->klass;
1447 src->dreg = ins->sreg1;
1449 MonoInst *tmp = mini_emit_box (cfg, src, ins->klass, mini_class_check_context_used (cfg, ins->klass));
1450 g_assert (tmp);
1452 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, tmp->dreg);
1454 /* This might be decomposed into other vtype opcodes */
1455 restart = TRUE;
1456 break;
1458 default:
1459 break;
1462 g_assert (cfg->cbb == first_bb);
1464 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1465 /* Replace the original instruction with the new code sequence */
1467 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1468 first_bb->code = first_bb->last_ins = NULL;
1469 first_bb->in_count = first_bb->out_count = 0;
1470 cfg->cbb = first_bb;
1472 else
1473 prev = ins;
1477 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1481 inline static MonoInst *
1482 mono_get_domainvar (MonoCompile *cfg)
1484 if (!cfg->domainvar)
1485 cfg->domainvar = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
1486 return cfg->domainvar;
1490 * mono_decompose_array_access_opts:
1492 * Decompose array access and other misc opcodes.
1494 void
1495 mono_decompose_array_access_opts (MonoCompile *cfg)
1497 MonoBasicBlock *bb, *first_bb;
1500 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1501 * can be executed anytime. It should be run before decompose_long
1505 * Create a dummy bblock and emit code into it so we can use the normal
1506 * code generation macros.
1508 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1509 first_bb = cfg->cbb;
1511 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1512 MonoInst *ins;
1513 MonoInst *prev = NULL;
1514 MonoInst *dest;
1515 MonoInst *iargs [3];
1516 gboolean restart;
1518 if (!bb->needs_decompose)
1519 continue;
1521 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1523 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1524 restart = TRUE;
1526 while (restart) {
1527 restart = FALSE;
1529 for (ins = bb->code; ins; ins = ins->next) {
1530 switch (ins->opcode) {
1531 case OP_TYPED_OBJREF:
1532 ins->opcode = OP_MOVE;
1533 break;
1534 case OP_LDLEN:
1535 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1536 ins->inst_imm, ins->flags);
1537 MONO_ADD_INS (cfg->cbb, dest);
1538 break;
1539 case OP_BOUNDS_CHECK:
1540 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1, FALSE);
1541 if (COMPILE_LLVM (cfg)) {
1542 int index2_reg = alloc_preg (cfg);
1543 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, ins->sreg2);
1544 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, index2_reg, ins->flags & MONO_INST_FAULT, ins->inst_p0);
1545 } else {
1546 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->inst_p0);
1548 break;
1549 case OP_NEWARR:
1550 if (cfg->opt & MONO_OPT_SHARED) {
1551 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1552 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1553 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1554 iargs [2]->dreg = ins->sreg1;
1556 dest = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
1557 dest->dreg = ins->dreg;
1558 } else {
1559 MonoClass *array_class = mono_class_create_array (ins->inst_newa_class, 1);
1560 ERROR_DECL (vt_error);
1561 MonoVTable *vtable = mono_class_vtable_checked (cfg->domain, array_class, vt_error);
1562 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1564 mono_error_assert_ok (vt_error); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1565 NEW_VTABLECONST (cfg, iargs [0], vtable);
1566 MONO_ADD_INS (cfg->cbb, iargs [0]);
1567 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1568 iargs [1]->dreg = ins->sreg1;
1570 if (managed_alloc)
1571 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1572 else
1573 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1574 dest->dreg = ins->dreg;
1576 break;
1577 case OP_STRLEN:
1578 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1579 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1580 break;
1581 default:
1582 break;
1585 g_assert (cfg->cbb == first_bb);
1587 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1588 /* Replace the original instruction with the new code sequence */
1590 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1591 first_bb->code = first_bb->last_ins = NULL;
1592 first_bb->in_count = first_bb->out_count = 0;
1593 cfg->cbb = first_bb;
1595 else
1596 prev = ins;
1600 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1604 typedef union {
1605 guint32 vali [2];
1606 gint64 vall;
1607 double vald;
1608 } DVal;
1610 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1613 * mono_decompose_soft_float:
1615 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1616 * similar to long support on 32 bit platforms. 32 bit float values require special
1617 * handling when used as locals, arguments, and in calls.
1618 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1620 void
1621 mono_decompose_soft_float (MonoCompile *cfg)
1623 MonoBasicBlock *bb, *first_bb;
1626 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1630 * Create a dummy bblock and emit code into it so we can use the normal
1631 * code generation macros.
1633 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1634 first_bb = cfg->cbb;
1636 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1637 MonoInst *ins;
1638 MonoInst *prev = NULL;
1639 gboolean restart;
1641 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1643 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1644 restart = TRUE;
1646 while (restart) {
1647 restart = FALSE;
1649 for (ins = bb->code; ins; ins = ins->next) {
1650 const char *spec = INS_INFO (ins->opcode);
1652 /* Most fp operations are handled automatically by opcode emulation */
1654 switch (ins->opcode) {
1655 case OP_R8CONST: {
1656 DVal d;
1657 d.vald = *(double*)ins->inst_p0;
1658 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1659 break;
1661 case OP_R4CONST: {
1662 DVal d;
1663 /* We load the r8 value */
1664 d.vald = *(float*)ins->inst_p0;
1665 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1666 break;
1668 case OP_FMOVE:
1669 ins->opcode = OP_LMOVE;
1670 break;
1671 case OP_FGETLOW32:
1672 ins->opcode = OP_MOVE;
1673 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1674 break;
1675 case OP_FGETHIGH32:
1676 ins->opcode = OP_MOVE;
1677 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1678 break;
1679 case OP_SETFRET: {
1680 int reg = ins->sreg1;
1682 ins->opcode = OP_SETLRET;
1683 ins->dreg = -1;
1684 ins->sreg1 = MONO_LVREG_LS (reg);
1685 ins->sreg2 = MONO_LVREG_MS (reg);
1686 break;
1688 case OP_LOADR8_MEMBASE:
1689 ins->opcode = OP_LOADI8_MEMBASE;
1690 break;
1691 case OP_STORER8_MEMBASE_REG:
1692 ins->opcode = OP_STOREI8_MEMBASE_REG;
1693 break;
1694 case OP_STORER4_MEMBASE_REG: {
1695 MonoInst *iargs [2];
1696 int addr_reg;
1698 /* Arg 1 is the double value */
1699 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1700 iargs [0]->dreg = ins->sreg1;
1702 /* Arg 2 is the address to store to */
1703 addr_reg = mono_alloc_preg (cfg);
1704 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1705 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1706 restart = TRUE;
1707 break;
1709 case OP_LOADR4_MEMBASE: {
1710 MonoInst *iargs [1];
1711 MonoInst *conv;
1712 int addr_reg;
1714 addr_reg = mono_alloc_preg (cfg);
1715 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1716 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1717 conv->dreg = ins->dreg;
1718 break;
1720 case OP_FCALL:
1721 case OP_FCALL_REG:
1722 case OP_FCALL_MEMBASE: {
1723 MonoCallInst *call = (MonoCallInst*)ins;
1724 if (call->signature->ret->type == MONO_TYPE_R4) {
1725 MonoCallInst *call2;
1726 MonoInst *iargs [1];
1727 MonoInst *conv;
1728 GSList *l;
1730 /* Convert the call into a call returning an int */
1731 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1732 memcpy (call2, call, sizeof (MonoCallInst));
1733 switch (ins->opcode) {
1734 case OP_FCALL:
1735 call2->inst.opcode = OP_CALL;
1736 break;
1737 case OP_FCALL_REG:
1738 call2->inst.opcode = OP_CALL_REG;
1739 break;
1740 case OP_FCALL_MEMBASE:
1741 call2->inst.opcode = OP_CALL_MEMBASE;
1742 break;
1743 default:
1744 g_assert_not_reached ();
1746 call2->inst.dreg = mono_alloc_ireg (cfg);
1747 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1749 /* Remap OUTARG_VT instructions referencing this call */
1750 for (l = call->outarg_vts; l; l = l->next)
1751 ((MonoInst*)(l->data))->inst_p0 = call2;
1753 /* FIXME: Optimize this */
1755 /* Emit an r4->r8 conversion */
1756 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, mono_get_int32_type ());
1757 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1758 conv->dreg = ins->dreg;
1760 /* The call sequence might include fp ins */
1761 restart = TRUE;
1762 } else {
1763 switch (ins->opcode) {
1764 case OP_FCALL:
1765 ins->opcode = OP_LCALL;
1766 break;
1767 case OP_FCALL_REG:
1768 ins->opcode = OP_LCALL_REG;
1769 break;
1770 case OP_FCALL_MEMBASE:
1771 ins->opcode = OP_LCALL_MEMBASE;
1772 break;
1773 default:
1774 g_assert_not_reached ();
1777 break;
1779 case OP_FCOMPARE: {
1780 MonoJitICallInfo *info;
1781 MonoInst *iargs [2];
1782 MonoInst *call, *cmp, *br;
1784 /* Convert fcompare+fbcc to icall+icompare+beq */
1786 if (!ins->next) {
1787 /* The branch might be optimized away */
1788 NULLIFY_INS (ins);
1789 break;
1792 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1793 if (!info) {
1794 /* The branch might be optimized away */
1795 NULLIFY_INS (ins);
1796 break;
1799 /* Create dummy MonoInst's for the arguments */
1800 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1801 iargs [0]->dreg = ins->sreg1;
1802 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1803 iargs [1]->dreg = ins->sreg2;
1805 call = mono_emit_jit_icall_id (cfg, mono_jit_icall_info_id (info), iargs);
1807 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1808 cmp->sreg1 = call->dreg;
1809 cmp->inst_imm = 0;
1810 MONO_ADD_INS (cfg->cbb, cmp);
1812 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1813 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1814 br->inst_true_bb = ins->next->inst_true_bb;
1815 br->inst_false_bb = ins->next->inst_false_bb;
1816 MONO_ADD_INS (cfg->cbb, br);
1818 /* The call sequence might include fp ins */
1819 restart = TRUE;
1821 /* Skip fbcc or fccc */
1822 NULLIFY_INS (ins->next);
1823 break;
1825 case OP_FCEQ:
1826 case OP_FCGT:
1827 case OP_FCGT_UN:
1828 case OP_FCLT:
1829 case OP_FCLT_UN: {
1830 MonoJitICallInfo *info;
1831 MonoInst *iargs [2];
1832 MonoInst *call;
1834 /* Convert fccc to icall+icompare+iceq */
1836 info = mono_find_jit_opcode_emulation (ins->opcode);
1837 g_assert (info);
1839 /* Create dummy MonoInst's for the arguments */
1840 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1841 iargs [0]->dreg = ins->sreg1;
1842 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1843 iargs [1]->dreg = ins->sreg2;
1845 call = mono_emit_jit_icall_id (cfg, mono_jit_icall_info_id (info), iargs);
1847 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1848 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1850 /* The call sequence might include fp ins */
1851 restart = TRUE;
1852 break;
1854 case OP_CKFINITE: {
1855 MonoInst *iargs [2];
1856 MonoInst *call, *cmp;
1858 /* Convert to icall+icompare+cond_exc+move */
1860 /* Create dummy MonoInst's for the arguments */
1861 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1862 iargs [0]->dreg = ins->sreg1;
1864 call = mono_emit_jit_icall (cfg, mono_isfinite_double, iargs);
1866 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1867 cmp->sreg1 = call->dreg;
1868 cmp->inst_imm = 1;
1869 MONO_ADD_INS (cfg->cbb, cmp);
1871 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1873 /* Do the assignment if the value is finite */
1874 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1876 restart = TRUE;
1877 break;
1879 default:
1880 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1881 mono_print_ins (ins);
1882 g_assert_not_reached ();
1884 break;
1887 g_assert (cfg->cbb == first_bb);
1889 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1890 /* Replace the original instruction with the new code sequence */
1892 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1893 first_bb->code = first_bb->last_ins = NULL;
1894 first_bb->in_count = first_bb->out_count = 0;
1895 cfg->cbb = first_bb;
1897 else
1898 prev = ins;
1902 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1905 mono_decompose_long_opts (cfg);
1908 #endif
1910 void
1911 mono_local_emulate_ops (MonoCompile *cfg)
1913 MonoBasicBlock *bb;
1914 gboolean inlined_wrapper = FALSE;
1916 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1917 MonoInst *ins;
1919 MONO_BB_FOR_EACH_INS (bb, ins) {
1920 int op_noimm = mono_op_imm_to_op (ins->opcode);
1921 MonoJitICallInfo *info;
1924 * These opcodes don't have logical equivalence to the emulating native
1925 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1927 if (MONO_HAS_CUSTOM_EMULATION (ins))
1928 continue;
1931 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1932 * to check whether its non-imm counterpart is emulated and, if so,
1933 * decompose it back to its non-imm counterpart.
1935 if (op_noimm != -1)
1936 info = mono_find_jit_opcode_emulation (op_noimm);
1937 else
1938 info = mono_find_jit_opcode_emulation (ins->opcode);
1940 if (info) {
1941 MonoInst **args;
1942 MonoInst *call;
1943 MonoBasicBlock *first_bb;
1945 /* Create dummy MonoInst's for the arguments */
1946 g_assert (!info->sig->hasthis);
1947 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1949 if (op_noimm != -1)
1950 mono_decompose_op_imm (cfg, bb, ins);
1952 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1953 if (info->sig->param_count > 0) {
1954 int sregs [MONO_MAX_SRC_REGS];
1955 int num_sregs, i;
1956 num_sregs = mono_inst_get_src_registers (ins, sregs);
1957 g_assert (num_sregs == info->sig->param_count);
1958 for (i = 0; i < num_sregs; ++i) {
1959 MONO_INST_NEW (cfg, args [i], OP_ARG);
1960 args [i]->dreg = sregs [i];
1964 /* We emit the call on a separate dummy basic block */
1965 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1966 first_bb = cfg->cbb;
1968 call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
1969 call->dreg = ins->dreg;
1971 /* Replace ins with the emitted code and do the necessary bb linking */
1972 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1973 MonoInst *saved_prev = ins->prev;
1975 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1976 first_bb->code = first_bb->last_ins = NULL;
1977 first_bb->in_count = first_bb->out_count = 0;
1978 cfg->cbb = first_bb;
1980 if (!saved_prev) {
1981 /* first instruction of basic block got replaced, so create
1982 * dummy inst that points to start of basic block */
1983 MONO_INST_NEW (cfg, saved_prev, OP_NOP);
1984 saved_prev = bb->code;
1987 /* ins is hanging, continue scanning the emitted code */
1988 ins = saved_prev;
1989 } else {
1990 g_error ("Failed to emit emulation code");
1992 inlined_wrapper = TRUE;
1998 * Avoid rerunning these passes by emitting directly the exception checkpoint
1999 * at IR level, instead of inlining the icall wrapper. FIXME
2001 if (inlined_wrapper) {
2002 if (!COMPILE_LLVM (cfg))
2003 mono_decompose_long_opts (cfg);
2004 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
2005 mono_local_cprop (cfg);
2009 #else /* !DISABLE_JIT */
2011 MONO_EMPTY_SOURCE_FILE (decompose);
2013 #endif /* !DISABLE_JIT */