[build] Skips RemoteExecuted bases tests on monodroid
[mono-project.git] / mono / mini / decompose.c
blobb0198d77820cab022740a85a9bda23068fc63e68
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>
22 #ifndef DISABLE_JIT
25 * Decompose complex long opcodes on 64 bit machines.
26 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
28 static gboolean
29 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
31 MonoInst *repl = NULL;
33 *repl_ins = NULL;
35 switch (ins->opcode) {
36 case OP_LCONV_TO_I4:
37 ins->opcode = OP_SEXT_I4;
38 break;
39 case OP_LCONV_TO_I8:
40 case OP_LCONV_TO_U8:
41 if (SIZEOF_VOID_P == 4)
42 ins->opcode = OP_LMOVE;
43 else
44 ins->opcode = OP_MOVE;
45 break;
46 case OP_LCONV_TO_I:
47 if (SIZEOF_VOID_P == 4)
48 /* OP_LCONV_TO_I4 */
49 ins->opcode = OP_SEXT_I4;
50 else
51 ins->opcode = OP_MOVE;
52 break;
53 case OP_LCONV_TO_U:
54 if (SIZEOF_VOID_P == 4) {
55 /* OP_LCONV_TO_U4 */
56 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
57 NULLIFY_INS (ins);
58 } else {
59 ins->opcode = OP_MOVE;
61 break;
62 case OP_ICONV_TO_I8:
63 ins->opcode = OP_SEXT_I4;
64 break;
65 case OP_ICONV_TO_U8:
66 ins->opcode = OP_ZEXT_I4;
67 break;
68 case OP_LCONV_TO_U4:
69 /* Clean out the upper word */
70 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
71 NULLIFY_INS (ins);
72 break;
73 case OP_LADD_OVF: {
74 int opcode;
76 if (COMPILE_LLVM (cfg))
77 break;
78 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
79 opcode = OP_LADDCC;
80 else
81 opcode = OP_ADDCC;
82 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
83 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
84 NULLIFY_INS (ins);
85 break;
87 case OP_LADD_OVF_UN: {
88 int opcode;
90 if (COMPILE_LLVM (cfg))
91 break;
92 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
93 opcode = OP_LADDCC;
94 else
95 opcode = OP_ADDCC;
96 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
97 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
98 NULLIFY_INS (ins);
99 break;
101 #ifndef __mono_ppc64__
102 case OP_LSUB_OVF: {
103 int opcode;
105 if (COMPILE_LLVM (cfg))
106 break;
107 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
108 opcode = OP_LSUBCC;
109 else
110 opcode = OP_SUBCC;
111 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
112 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
113 NULLIFY_INS (ins);
114 break;
116 case OP_LSUB_OVF_UN: {
117 int opcode;
119 if (COMPILE_LLVM (cfg))
120 break;
121 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
122 opcode = OP_LSUBCC;
123 else
124 opcode = OP_SUBCC;
125 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
126 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
127 NULLIFY_INS (ins);
128 break;
130 #endif
132 case OP_ICONV_TO_OVF_I8:
133 case OP_ICONV_TO_OVF_I:
134 ins->opcode = OP_SEXT_I4;
135 break;
136 case OP_ICONV_TO_OVF_U8:
137 case OP_ICONV_TO_OVF_U:
138 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
139 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
140 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
141 NULLIFY_INS (ins);
142 break;
143 case OP_ICONV_TO_OVF_I8_UN:
144 case OP_ICONV_TO_OVF_U8_UN:
145 case OP_ICONV_TO_OVF_I_UN:
146 case OP_ICONV_TO_OVF_U_UN:
147 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
148 /* Clean out the upper word */
149 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
150 NULLIFY_INS (ins);
151 break;
152 case OP_LCONV_TO_OVF_I1:
153 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
154 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
155 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
156 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
157 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
158 NULLIFY_INS (ins);
159 break;
160 case OP_LCONV_TO_OVF_I1_UN:
161 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
162 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
163 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
164 NULLIFY_INS (ins);
165 break;
166 case OP_LCONV_TO_OVF_U1:
167 /* probe value to be within 0 to 255 */
168 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
169 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
170 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
171 NULLIFY_INS (ins);
172 break;
173 case OP_LCONV_TO_OVF_U1_UN:
174 /* probe value to be within 0 to 255 */
175 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
176 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
177 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
178 NULLIFY_INS (ins);
179 break;
180 case OP_LCONV_TO_OVF_I2:
181 /* Probe value to be within -32768 and 32767 */
182 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
183 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
184 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
185 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
186 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
187 NULLIFY_INS (ins);
188 break;
189 case OP_LCONV_TO_OVF_I2_UN:
190 /* Probe value to be within 0 and 32767 */
191 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
192 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
193 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
194 NULLIFY_INS (ins);
195 break;
196 case OP_LCONV_TO_OVF_U2:
197 /* Probe value to be within 0 and 65535 */
198 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
199 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
200 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
201 NULLIFY_INS (ins);
202 break;
203 case OP_LCONV_TO_OVF_U2_UN:
204 /* Probe value to be within 0 and 65535 */
205 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
206 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
207 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
208 NULLIFY_INS (ins);
209 break;
210 case OP_LCONV_TO_OVF_I4:
211 #if SIZEOF_VOID_P == 4
212 case OP_LCONV_TO_OVF_I:
213 #endif
214 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
215 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
216 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
217 #if SIZEOF_REGISTER == 8
218 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
219 #else
220 g_assert (COMPILE_LLVM (cfg));
221 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
222 #endif
223 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
224 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
225 NULLIFY_INS (ins);
226 break;
227 case OP_LCONV_TO_OVF_I4_UN:
228 #if SIZEOF_VOID_P == 4
229 case OP_LCONV_TO_OVF_I_UN:
230 #endif
231 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
232 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
233 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
234 NULLIFY_INS (ins);
235 break;
236 case OP_LCONV_TO_OVF_U4:
237 #if SIZEOF_VOID_P == 4
238 case OP_LCONV_TO_OVF_U:
239 #endif
240 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
241 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
242 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
243 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
244 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
245 NULLIFY_INS (ins);
246 break;
247 case OP_LCONV_TO_OVF_U4_UN:
248 #if SIZEOF_VOID_P == 4
249 case OP_LCONV_TO_OVF_U_UN:
250 #endif
251 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
252 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
253 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
254 NULLIFY_INS (ins);
255 break;
256 #if SIZEOF_VOID_P == 8
257 case OP_LCONV_TO_OVF_I:
258 case OP_LCONV_TO_OVF_U_UN:
259 #endif
260 case OP_LCONV_TO_OVF_U8_UN:
261 case OP_LCONV_TO_OVF_I8:
262 ins->opcode = OP_MOVE;
263 break;
264 #if SIZEOF_VOID_P == 8
265 case OP_LCONV_TO_OVF_I_UN:
266 #endif
267 case OP_LCONV_TO_OVF_I8_UN:
268 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
269 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
270 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
271 NULLIFY_INS (ins);
272 break;
273 case OP_LCONV_TO_OVF_U8:
274 #if SIZEOF_VOID_P == 8
275 case OP_LCONV_TO_OVF_U:
276 #endif
277 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
278 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
279 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
280 NULLIFY_INS (ins);
281 break;
282 default:
283 return FALSE;
286 *repl_ins = repl;
287 return TRUE;
291 * mono_decompose_opcode:
293 * Decompose complex opcodes into ones closer to opcodes supported by
294 * the given architecture.
295 * Returns a MonoInst which represents the result of the decomposition, and can
296 * be pushed on the IL stack. This is needed because the original instruction is
297 * nullified.
298 * Sets the cfg exception if an opcode is not supported.
300 MonoInst*
301 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
303 MonoInst *repl = NULL;
304 int type = ins->type;
305 int dreg = ins->dreg;
306 gboolean emulate = FALSE;
308 /* FIXME: Instead of = NOP, don't emit the original ins at all */
309 mono_arch_decompose_opts (cfg, ins);
312 * The code below assumes that we are called immediately after emitting
313 * ins. This means we can emit code using the normal code generation
314 * macros.
316 switch (ins->opcode) {
317 /* this doesn't make sense on ppc and other architectures */
318 #if !defined(MONO_ARCH_NO_IOV_CHECK)
319 case OP_IADD_OVF:
320 if (COMPILE_LLVM (cfg))
321 break;
322 ins->opcode = OP_IADDCC;
323 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
324 break;
325 case OP_IADD_OVF_UN:
326 if (COMPILE_LLVM (cfg))
327 break;
328 ins->opcode = OP_IADDCC;
329 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
330 break;
331 case OP_ISUB_OVF:
332 if (COMPILE_LLVM (cfg))
333 break;
334 ins->opcode = OP_ISUBCC;
335 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
336 break;
337 case OP_ISUB_OVF_UN:
338 if (COMPILE_LLVM (cfg))
339 break;
340 ins->opcode = OP_ISUBCC;
341 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
342 break;
343 #endif
344 case OP_ICONV_TO_OVF_I1:
345 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
346 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
347 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
348 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
349 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
350 NULLIFY_INS (ins);
351 break;
352 case OP_ICONV_TO_OVF_I1_UN:
353 /* probe values between 0 to 127 */
354 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
355 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
356 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
357 NULLIFY_INS (ins);
358 break;
359 case OP_ICONV_TO_OVF_U1:
360 case OP_ICONV_TO_OVF_U1_UN:
361 /* probe value to be within 0 to 255 */
362 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
363 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
364 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
365 NULLIFY_INS (ins);
366 break;
367 case OP_ICONV_TO_OVF_I2:
368 /* Probe value to be within -32768 and 32767 */
369 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
370 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
371 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
372 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
373 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
374 NULLIFY_INS (ins);
375 break;
376 case OP_ICONV_TO_OVF_I2_UN:
377 /* Convert uint value into short, value within 0 and 32767 */
378 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
379 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
380 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
381 NULLIFY_INS (ins);
382 break;
383 case OP_ICONV_TO_OVF_U2:
384 case OP_ICONV_TO_OVF_U2_UN:
385 /* Probe value to be within 0 and 65535 */
386 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
387 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
388 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
389 NULLIFY_INS (ins);
390 break;
391 case OP_ICONV_TO_OVF_U4:
392 case OP_ICONV_TO_OVF_I4_UN:
393 #if SIZEOF_VOID_P == 4
394 case OP_ICONV_TO_OVF_U:
395 case OP_ICONV_TO_OVF_I_UN:
396 #endif
397 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
398 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
399 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
400 NULLIFY_INS (ins);
401 break;
402 case OP_ICONV_TO_I4:
403 case OP_ICONV_TO_U4:
404 case OP_ICONV_TO_OVF_I4:
405 case OP_ICONV_TO_OVF_U4_UN:
406 #if SIZEOF_VOID_P == 4
407 case OP_ICONV_TO_OVF_I:
408 case OP_ICONV_TO_OVF_U_UN:
409 #endif
410 ins->opcode = OP_MOVE;
411 break;
412 case OP_ICONV_TO_I:
413 #if SIZEOF_VOID_P == 8
414 ins->opcode = OP_SEXT_I4;
415 #else
416 ins->opcode = OP_MOVE;
417 #endif
418 break;
419 case OP_ICONV_TO_U:
420 #if SIZEOF_VOID_P == 8
421 ins->opcode = OP_ZEXT_I4;
422 #else
423 ins->opcode = OP_MOVE;
424 #endif
425 break;
427 case OP_FCONV_TO_R8:
428 ins->opcode = OP_FMOVE;
429 break;
431 case OP_FCONV_TO_OVF_I1_UN:
432 case OP_FCONV_TO_OVF_I2_UN:
433 case OP_FCONV_TO_OVF_I4_UN:
434 case OP_FCONV_TO_OVF_I8_UN:
435 case OP_FCONV_TO_OVF_U1_UN:
436 case OP_FCONV_TO_OVF_U2_UN:
437 case OP_FCONV_TO_OVF_U4_UN:
438 case OP_FCONV_TO_OVF_U8_UN:
439 case OP_FCONV_TO_OVF_I_UN:
440 case OP_FCONV_TO_OVF_U_UN:
441 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
442 break;
444 case OP_IDIV:
445 case OP_IREM:
446 case OP_IDIV_UN:
447 case OP_IREM_UN:
448 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
449 emulate = TRUE;
450 if (!emulate) {
451 if (cfg->backend->need_div_check) {
452 int reg1 = alloc_ireg (cfg);
453 int reg2 = alloc_ireg (cfg);
454 /* b == 0 */
455 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
456 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
457 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
458 /* b == -1 && a == 0x80000000 */
459 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
460 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
461 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
462 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
463 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
464 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
465 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
468 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
469 NULLIFY_INS (ins);
471 break;
473 #if SIZEOF_VOID_P == 8
474 case OP_LDIV:
475 case OP_LREM:
476 case OP_LDIV_UN:
477 case OP_LREM_UN:
478 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
479 emulate = TRUE;
480 if (!emulate) {
481 if (cfg->backend->need_div_check) {
482 int reg1 = alloc_ireg (cfg);
483 int reg2 = alloc_ireg (cfg);
484 int reg3 = alloc_ireg (cfg);
485 /* b == 0 */
486 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
487 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
488 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
489 /* b == -1 && a == 0x80000000 */
490 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
491 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
492 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
493 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
494 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
495 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
496 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
497 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
498 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
501 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
502 NULLIFY_INS (ins);
504 break;
505 #endif
507 case OP_DIV_IMM:
508 case OP_REM_IMM:
509 case OP_IDIV_IMM:
510 case OP_IREM_IMM:
511 case OP_IDIV_UN_IMM:
512 case OP_IREM_UN_IMM:
513 if (cfg->backend->need_div_check) {
514 int reg1 = alloc_ireg (cfg);
515 /* b == 0 */
516 if (ins->inst_imm == 0) {
517 // FIXME: Optimize this
518 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
519 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
520 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
522 if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
523 (ins->inst_imm == -1)) {
524 /* b == -1 && a == 0x80000000 */
525 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
526 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
528 MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
529 NULLIFY_INS (ins);
530 } else {
531 emulate = TRUE;
533 break;
534 case OP_ICONV_TO_R_UN:
535 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
536 if (!COMPILE_LLVM (cfg))
537 emulate = TRUE;
538 #endif
539 break;
540 default:
541 emulate = TRUE;
542 break;
545 if (emulate) {
546 #if SIZEOF_REGISTER == 8
547 if (decompose_long_opcode (cfg, ins, &repl))
548 emulate = FALSE;
549 #else
550 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
551 emulate = FALSE;
552 #endif
554 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
555 cfg->has_emulated_ops = TRUE;
558 if (ins->opcode == OP_NOP) {
559 if (repl) {
560 repl->type = type;
561 return repl;
562 } else {
563 /* Use the last emitted instruction */
564 ins = cfg->cbb->last_ins;
565 g_assert (ins);
566 ins->type = type;
567 g_assert (ins->dreg == dreg);
568 return ins;
570 } else {
571 return ins;
575 #if SIZEOF_REGISTER == 4
576 static int lbr_decomp [][2] = {
577 {0, 0}, /* BEQ */
578 {OP_IBGT, OP_IBGE_UN}, /* BGE */
579 {OP_IBGT, OP_IBGT_UN}, /* BGT */
580 {OP_IBLT, OP_IBLE_UN}, /* BLE */
581 {OP_IBLT, OP_IBLT_UN}, /* BLT */
582 {0, 0}, /* BNE_UN */
583 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
584 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
585 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
586 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
589 static int lcset_decomp [][2] = {
590 {0, 0}, /* CEQ */
591 {OP_IBLT, OP_IBLE_UN}, /* CGT */
592 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
593 {OP_IBGT, OP_IBGE_UN}, /* CLT */
594 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
596 #endif
599 * mono_decompose_long_opts:
601 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
603 void
604 mono_decompose_long_opts (MonoCompile *cfg)
606 #if SIZEOF_REGISTER == 4
607 MonoBasicBlock *bb, *first_bb;
610 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
611 * needs to be able to handle long vregs.
615 * Create a dummy bblock and emit code into it so we can use the normal
616 * code generation macros.
618 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
619 first_bb = cfg->cbb;
621 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
622 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
623 MonoInst *prev = NULL;
626 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
629 cfg->cbb->code = cfg->cbb->last_ins = NULL;
631 while (tree) {
632 mono_arch_decompose_long_opts (cfg, tree);
634 switch (tree->opcode) {
635 case OP_I8CONST:
636 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
637 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
638 break;
639 case OP_DUMMY_I8CONST:
640 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
641 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
642 break;
643 case OP_LMOVE:
644 case OP_LCONV_TO_U8:
645 case OP_LCONV_TO_I8:
646 case OP_LCONV_TO_OVF_U8_UN:
647 case OP_LCONV_TO_OVF_I8:
648 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
649 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
650 break;
651 case OP_STOREI8_MEMBASE_REG:
652 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (tree->sreg1));
653 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (tree->sreg1));
654 break;
655 case OP_LOADI8_MEMBASE:
656 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_MS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
657 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_LS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
658 break;
660 case OP_ICONV_TO_I8: {
661 guint32 tmpreg = alloc_ireg (cfg);
663 /* branchless code:
664 * low = reg;
665 * tmp = low > -1 ? 1: 0;
666 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
668 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
669 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
670 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
671 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
672 break;
674 case OP_ICONV_TO_U8:
675 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
676 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
677 break;
678 case OP_ICONV_TO_OVF_I8:
679 /* a signed 32 bit num always fits in a signed 64 bit one */
680 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
681 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
682 break;
683 case OP_ICONV_TO_OVF_U8:
684 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
685 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
686 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
687 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
688 break;
689 case OP_ICONV_TO_OVF_I8_UN:
690 case OP_ICONV_TO_OVF_U8_UN:
691 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
692 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
693 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
694 break;
695 case OP_LCONV_TO_I1:
696 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
697 break;
698 case OP_LCONV_TO_U1:
699 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
700 break;
701 case OP_LCONV_TO_I2:
702 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
703 break;
704 case OP_LCONV_TO_U2:
705 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
706 break;
707 case OP_LCONV_TO_I4:
708 case OP_LCONV_TO_U4:
709 case OP_LCONV_TO_I:
710 case OP_LCONV_TO_U:
711 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
712 break;
713 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
714 case OP_LCONV_TO_R8:
715 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
716 break;
717 #endif
718 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
719 case OP_LCONV_TO_R4:
720 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
721 break;
722 #endif
723 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
724 case OP_LCONV_TO_R_UN:
725 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
726 break;
727 #endif
728 case OP_LCONV_TO_OVF_I1: {
729 MonoBasicBlock *is_negative, *end_label;
731 NEW_BBLOCK (cfg, is_negative);
732 NEW_BBLOCK (cfg, end_label);
734 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
735 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
736 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
737 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
739 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
740 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
742 /* Positive */
743 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
744 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
745 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
747 /* Negative */
748 MONO_START_BB (cfg, is_negative);
749 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
750 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
752 MONO_START_BB (cfg, end_label);
754 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
755 break;
757 case OP_LCONV_TO_OVF_I1_UN:
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
759 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
761 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
762 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
763 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
764 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
765 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
766 break;
767 case OP_LCONV_TO_OVF_U1:
768 case OP_LCONV_TO_OVF_U1_UN:
769 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
770 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
772 /* probe value to be within 0 to 255 */
773 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
774 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
775 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
776 break;
777 case OP_LCONV_TO_OVF_I2: {
778 MonoBasicBlock *is_negative, *end_label;
780 NEW_BBLOCK (cfg, is_negative);
781 NEW_BBLOCK (cfg, end_label);
783 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
784 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
785 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
786 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
788 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
789 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
791 /* Positive */
792 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
793 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
794 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
796 /* Negative */
797 MONO_START_BB (cfg, is_negative);
798 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
799 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
800 MONO_START_BB (cfg, end_label);
802 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
803 break;
805 case OP_LCONV_TO_OVF_I2_UN:
806 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
807 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
809 /* Probe value to be within -32768 and 32767 */
810 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
811 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
812 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
813 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
814 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
815 break;
816 case OP_LCONV_TO_OVF_U2:
817 case OP_LCONV_TO_OVF_U2_UN:
818 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
819 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
821 /* Probe value to be within 0 and 65535 */
822 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
823 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
824 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
825 break;
826 case OP_LCONV_TO_OVF_I4:
827 case OP_LCONV_TO_OVF_I:
828 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
829 break;
830 case OP_LCONV_TO_OVF_U4:
831 case OP_LCONV_TO_OVF_U:
832 case OP_LCONV_TO_OVF_U4_UN:
833 case OP_LCONV_TO_OVF_U_UN:
834 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
835 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
836 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
837 break;
838 case OP_LCONV_TO_OVF_I_UN:
839 case OP_LCONV_TO_OVF_I4_UN:
840 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
841 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
842 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
843 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
844 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
845 break;
846 case OP_LCONV_TO_OVF_U8:
847 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
848 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
850 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
851 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
852 break;
853 case OP_LCONV_TO_OVF_I8_UN:
854 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
855 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
857 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
858 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
859 break;
861 case OP_LADD:
862 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
863 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
864 break;
865 case OP_LSUB:
866 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
867 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
868 break;
870 case OP_LADD_OVF:
871 /* ADC sets the condition code */
872 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
873 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
874 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
875 break;
876 case OP_LADD_OVF_UN:
877 /* ADC sets the condition code */
878 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
879 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
880 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
881 break;
882 case OP_LSUB_OVF:
883 /* SBB sets the condition code */
884 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
885 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
886 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
887 break;
888 case OP_LSUB_OVF_UN:
889 /* SBB sets the condition code */
890 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
891 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
892 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
893 break;
894 case OP_LAND:
895 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
896 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
897 break;
898 case OP_LOR:
899 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
900 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
901 break;
902 case OP_LXOR:
903 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
904 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
905 break;
906 case OP_LNOT:
907 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
908 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
909 break;
910 case OP_LNEG:
911 /* Handled in mono_arch_decompose_long_opts () */
912 g_assert_not_reached ();
913 break;
914 case OP_LMUL:
915 /* Emulated */
916 /* FIXME: Add OP_BIGMUL optimization */
917 break;
919 case OP_LADD_IMM:
920 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
922 break;
923 case OP_LSUB_IMM:
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
925 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
926 break;
927 case OP_LAND_IMM:
928 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
929 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
930 break;
931 case OP_LOR_IMM:
932 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
933 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
934 break;
935 case OP_LXOR_IMM:
936 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
937 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
938 break;
939 #ifdef TARGET_POWERPC
940 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
941 case OP_LSHR_UN_IMM:
942 if (tree->inst_c1 == 32) {
944 /* The original code had this comment: */
945 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
946 * later apply the speedup to the left shift as well
947 * See BUG# 57957.
949 /* just move the upper half to the lower and zero the high word */
950 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
951 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
953 break;
954 #endif
955 case OP_LCOMPARE: {
956 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
958 g_assert (next);
960 switch (next->opcode) {
961 case OP_LBEQ:
962 case OP_LBNE_UN: {
963 int d1, d2;
965 /* Branchless version based on gcc code */
966 d1 = alloc_ireg (cfg);
967 d2 = alloc_ireg (cfg);
968 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
969 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
970 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
971 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
972 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
973 NULLIFY_INS (next);
974 break;
976 case OP_LBGE:
977 case OP_LBGT:
978 case OP_LBLE:
979 case OP_LBLT:
980 case OP_LBGE_UN:
981 case OP_LBGT_UN:
982 case OP_LBLE_UN:
983 case OP_LBLT_UN:
984 /* Convert into three comparisons + branches */
985 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
986 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
987 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
988 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
989 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
990 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
991 NULLIFY_INS (next);
992 break;
993 case OP_LCEQ: {
994 int d1, d2;
996 /* Branchless version based on gcc code */
997 d1 = alloc_ireg (cfg);
998 d2 = alloc_ireg (cfg);
999 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1000 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1001 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1003 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1004 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1005 NULLIFY_INS (next);
1006 break;
1008 case OP_LCLT:
1009 case OP_LCLT_UN:
1010 case OP_LCGT:
1011 case OP_LCGT_UN: {
1012 MonoBasicBlock *set_to_0, *set_to_1;
1014 NEW_BBLOCK (cfg, set_to_0);
1015 NEW_BBLOCK (cfg, set_to_1);
1017 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1018 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1019 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1020 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1021 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1022 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1023 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1024 MONO_START_BB (cfg, set_to_1);
1025 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1026 MONO_START_BB (cfg, set_to_0);
1027 NULLIFY_INS (next);
1028 break;
1030 default:
1031 g_assert_not_reached ();
1033 break;
1036 /* Not yet used, since lcompare is decomposed before local cprop */
1037 case OP_LCOMPARE_IMM: {
1038 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1039 guint32 low_imm = tree->inst_ls_word;
1040 guint32 high_imm = tree->inst_ms_word;
1041 int low_reg = MONO_LVREG_LS (tree->sreg1);
1042 int high_reg = MONO_LVREG_MS (tree->sreg1);
1044 g_assert (next);
1046 switch (next->opcode) {
1047 case OP_LBEQ:
1048 case OP_LBNE_UN: {
1049 int d1, d2;
1051 /* Branchless version based on gcc code */
1052 d1 = alloc_ireg (cfg);
1053 d2 = alloc_ireg (cfg);
1054 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1055 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1056 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1057 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1058 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1059 NULLIFY_INS (next);
1060 break;
1063 case OP_LBGE:
1064 case OP_LBGT:
1065 case OP_LBLE:
1066 case OP_LBLT:
1067 case OP_LBGE_UN:
1068 case OP_LBGT_UN:
1069 case OP_LBLE_UN:
1070 case OP_LBLT_UN:
1071 /* Convert into three comparisons + branches */
1072 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1073 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1074 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1075 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1076 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1077 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1078 NULLIFY_INS (next);
1079 break;
1080 case OP_LCEQ: {
1081 int d1, d2;
1083 /* Branchless version based on gcc code */
1084 d1 = alloc_ireg (cfg);
1085 d2 = alloc_ireg (cfg);
1086 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1087 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1088 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1090 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1091 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1092 NULLIFY_INS (next);
1093 break;
1095 case OP_LCLT:
1096 case OP_LCLT_UN:
1097 case OP_LCGT:
1098 case OP_LCGT_UN: {
1099 MonoBasicBlock *set_to_0, *set_to_1;
1101 NEW_BBLOCK (cfg, set_to_0);
1102 NEW_BBLOCK (cfg, set_to_1);
1104 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1105 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1106 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1107 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1108 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1109 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1110 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1111 MONO_START_BB (cfg, set_to_1);
1112 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1113 MONO_START_BB (cfg, set_to_0);
1114 NULLIFY_INS (next);
1115 break;
1117 default:
1118 g_assert_not_reached ();
1120 break;
1123 default:
1124 break;
1127 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1128 MonoInst *new_prev;
1130 /* Replace the original instruction with the new code sequence */
1132 /* Ignore the new value of prev */
1133 new_prev = prev;
1134 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1136 /* Process the newly added ops again since they can be long ops too */
1137 if (prev)
1138 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1139 else
1140 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1142 first_bb->code = first_bb->last_ins = NULL;
1143 first_bb->in_count = first_bb->out_count = 0;
1144 cfg->cbb = first_bb;
1146 else {
1147 prev = tree;
1148 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1152 #endif
1155 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1156 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1161 * mono_decompose_vtype_opts:
1163 * Decompose valuetype opcodes.
1165 void
1166 mono_decompose_vtype_opts (MonoCompile *cfg)
1168 MonoBasicBlock *bb, *first_bb;
1171 * Using OP_V opcodes and decomposing them later have two main benefits:
1172 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1173 * everywhere.
1174 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1175 * enabling optimizations to work on vtypes too.
1176 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1177 * can be executed anytime. It should be executed as late as possible so vtype
1178 * opcodes can be optimized by the other passes.
1179 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1180 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1181 * var to 1.
1182 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1183 * when OP_VMOVE opcodes are decomposed.
1187 * Vregs have no associated type information, so we store the type of the vregs
1188 * in ins->klass.
1192 * Create a dummy bblock and emit code into it so we can use the normal
1193 * code generation macros.
1195 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1196 first_bb = cfg->cbb;
1198 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1200 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1201 MonoInst *ins;
1202 MonoInst *prev = NULL;
1203 MonoInst *src_var, *dest_var, *src, *dest;
1204 gboolean restart;
1205 int dreg;
1207 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1209 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1210 cfg->cbb->out_of_line = bb->out_of_line;
1211 restart = TRUE;
1213 while (restart) {
1214 restart = FALSE;
1216 for (ins = bb->code; ins; ins = ins->next) {
1217 switch (ins->opcode) {
1218 case OP_VMOVE: {
1219 g_assert (ins->klass);
1220 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1221 break;
1222 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1223 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1225 if (!src_var)
1226 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1228 if (!dest_var)
1229 dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1231 // FIXME:
1232 if (src_var->backend.is_pinvoke)
1233 dest_var->backend.is_pinvoke = 1;
1235 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1236 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1237 mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0);
1239 break;
1241 case OP_VZERO:
1242 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1243 break;
1245 g_assert (ins->klass);
1247 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, m_class_get_byval_arg (ins->klass));
1248 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1250 if (cfg->compute_gc_maps) {
1251 MonoInst *tmp;
1254 * Tell the GC map code that the vtype is considered live after
1255 * the initialization.
1257 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1258 tmp->inst_c1 = ins->dreg;
1259 MONO_ADD_INS (cfg->cbb, tmp);
1261 break;
1262 case OP_DUMMY_VZERO:
1263 if (COMPILE_LLVM (cfg))
1264 break;
1266 NULLIFY_INS (ins);
1267 break;
1268 case OP_STOREV_MEMBASE: {
1269 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1271 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !cfg->gen_write_barriers)
1272 break;
1274 if (!src_var) {
1275 g_assert (ins->klass);
1276 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1);
1279 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, m_class_get_byval_arg (ins->klass));
1281 dreg = alloc_preg (cfg);
1282 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1283 mini_emit_memory_copy (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke, 0);
1284 break;
1286 case OP_LOADV_MEMBASE: {
1287 g_assert (ins->klass);
1288 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1289 break;
1291 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1292 // FIXME-VT:
1293 // FIXME:
1294 if (!dest_var)
1295 dest_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->dreg);
1297 dreg = alloc_preg (cfg);
1298 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1299 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1300 mini_emit_memory_copy (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke, 0);
1301 break;
1303 case OP_OUTARG_VT: {
1304 if (COMPILE_LLVM (cfg))
1305 break;
1307 g_assert (ins->klass);
1309 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1310 if (!src_var)
1311 src_var = mono_compile_create_var_for_vreg (cfg, m_class_get_byval_arg (ins->klass), OP_LOCAL, ins->sreg1);
1312 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1314 mono_arch_emit_outarg_vt (cfg, ins, src);
1316 /* This might be decomposed into other vtype opcodes */
1317 restart = TRUE;
1318 break;
1320 case OP_OUTARG_VTRETADDR: {
1321 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1323 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1324 if (!src_var)
1325 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1326 // FIXME: src_var->backend.is_pinvoke ?
1328 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1329 src->dreg = ins->dreg;
1330 break;
1332 case OP_VCALL:
1333 case OP_VCALL_REG:
1334 case OP_VCALL_MEMBASE: {
1335 MonoCallInst *call = (MonoCallInst*)ins;
1336 int size;
1338 if (COMPILE_LLVM (cfg))
1339 break;
1341 if (call->vret_in_reg) {
1342 MonoCallInst *call2;
1344 /* Replace the vcall with a scalar call */
1345 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1346 memcpy (call2, call, sizeof (MonoCallInst));
1347 switch (ins->opcode) {
1348 case OP_VCALL:
1349 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1350 break;
1351 case OP_VCALL_REG:
1352 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1353 break;
1354 case OP_VCALL_MEMBASE:
1355 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1356 break;
1358 call2->inst.dreg = alloc_preg (cfg);
1359 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1361 /* Compute the vtype location */
1362 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1363 if (!dest_var)
1364 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1365 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1367 /* Save the result */
1368 if (dest_var->backend.is_pinvoke)
1369 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1370 else
1371 size = mono_type_size (dest_var->inst_vtype, NULL);
1372 switch (size) {
1373 case 1:
1374 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1375 break;
1376 case 2:
1377 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1378 break;
1379 case 3:
1380 case 4:
1381 if (call->vret_in_reg_fp)
1382 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1383 else
1384 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1385 break;
1386 case 5:
1387 case 6:
1388 case 7:
1389 case 8:
1390 if (call->vret_in_reg_fp) {
1391 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1392 break;
1394 #if SIZEOF_REGISTER == 4
1396 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1397 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1399 switch (call2->inst.opcode) {
1400 case OP_CALL:
1401 call2->inst.opcode = OP_LCALL;
1402 break;
1403 case OP_CALL_REG:
1404 call2->inst.opcode = OP_LCALL_REG;
1405 break;
1406 case OP_CALL_MEMBASE:
1407 call2->inst.opcode = OP_LCALL_MEMBASE;
1408 break;
1410 call2->inst.dreg = alloc_lreg (cfg);
1411 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1412 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1413 #else
1414 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1415 #endif
1416 break;
1417 default:
1418 /* This assumes the vtype is sizeof (gpointer) long */
1419 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1420 break;
1422 } else {
1423 switch (ins->opcode) {
1424 case OP_VCALL:
1425 ins->opcode = OP_VCALL2;
1426 break;
1427 case OP_VCALL_REG:
1428 ins->opcode = OP_VCALL2_REG;
1429 break;
1430 case OP_VCALL_MEMBASE:
1431 ins->opcode = OP_VCALL2_MEMBASE;
1432 break;
1434 ins->dreg = -1;
1436 break;
1438 case OP_BOX:
1439 case OP_BOX_ICONST: {
1440 MonoInst *src;
1442 /* Temporary value required by emit_box () */
1443 if (ins->opcode == OP_BOX_ICONST) {
1444 NEW_ICONST (cfg, src, ins->inst_c0);
1445 src->klass = ins->klass;
1446 MONO_ADD_INS (cfg->cbb, src);
1447 } else {
1448 MONO_INST_NEW (cfg, src, OP_LOCAL);
1449 src->type = STACK_MP;
1450 src->klass = ins->klass;
1451 src->dreg = ins->sreg1;
1453 MonoInst *tmp = mini_emit_box (cfg, src, ins->klass, mini_class_check_context_used (cfg, ins->klass));
1454 g_assert (tmp);
1456 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, tmp->dreg);
1458 /* This might be decomposed into other vtype opcodes */
1459 restart = TRUE;
1460 break;
1462 default:
1463 break;
1466 g_assert (cfg->cbb == first_bb);
1468 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1469 /* Replace the original instruction with the new code sequence */
1471 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1472 first_bb->code = first_bb->last_ins = NULL;
1473 first_bb->in_count = first_bb->out_count = 0;
1474 cfg->cbb = first_bb;
1476 else
1477 prev = ins;
1481 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1485 inline static MonoInst *
1486 mono_get_domainvar (MonoCompile *cfg)
1488 if (!cfg->domainvar)
1489 cfg->domainvar = mono_compile_create_var (cfg, mono_get_int_type (), OP_LOCAL);
1490 return cfg->domainvar;
1494 * mono_decompose_array_access_opts:
1496 * Decompose array access and other misc opcodes.
1498 void
1499 mono_decompose_array_access_opts (MonoCompile *cfg)
1501 MonoBasicBlock *bb, *first_bb;
1504 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1505 * can be executed anytime. It should be run before decompose_long
1509 * Create a dummy bblock and emit code into it so we can use the normal
1510 * code generation macros.
1512 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1513 first_bb = cfg->cbb;
1515 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1516 MonoInst *ins;
1517 MonoInst *prev = NULL;
1518 MonoInst *dest;
1519 MonoInst *iargs [3];
1520 gboolean restart;
1522 if (!bb->needs_decompose)
1523 continue;
1525 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1527 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1528 restart = TRUE;
1530 while (restart) {
1531 restart = FALSE;
1533 for (ins = bb->code; ins; ins = ins->next) {
1534 switch (ins->opcode) {
1535 case OP_TYPED_OBJREF:
1536 ins->opcode = OP_MOVE;
1537 break;
1538 case OP_LDLEN:
1539 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1540 ins->inst_imm, ins->flags);
1541 MONO_ADD_INS (cfg->cbb, dest);
1542 break;
1543 case OP_BOUNDS_CHECK:
1544 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1, FALSE);
1545 if (COMPILE_LLVM (cfg)) {
1546 int index2_reg = alloc_preg (cfg);
1547 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, ins->sreg2);
1548 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, index2_reg, ins->flags & MONO_INST_FAULT);
1549 } else {
1550 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1552 break;
1553 case OP_NEWARR:
1554 if (cfg->opt & MONO_OPT_SHARED) {
1555 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1556 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1557 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1558 iargs [2]->dreg = ins->sreg1;
1560 dest = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
1561 dest->dreg = ins->dreg;
1562 } else {
1563 MonoClass *array_class = mono_class_create_array (ins->inst_newa_class, 1);
1564 ERROR_DECL_VALUE (vt_error);
1565 MonoVTable *vtable = mono_class_vtable_checked (cfg->domain, array_class, &vt_error);
1566 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1568 mono_error_assert_ok (&vt_error); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1569 NEW_VTABLECONST (cfg, iargs [0], vtable);
1570 MONO_ADD_INS (cfg->cbb, iargs [0]);
1571 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1572 iargs [1]->dreg = ins->sreg1;
1574 if (managed_alloc)
1575 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1576 else
1577 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1578 dest->dreg = ins->dreg;
1580 break;
1581 case OP_STRLEN:
1582 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1583 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1584 break;
1585 default:
1586 break;
1589 g_assert (cfg->cbb == first_bb);
1591 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1592 /* Replace the original instruction with the new code sequence */
1594 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1595 first_bb->code = first_bb->last_ins = NULL;
1596 first_bb->in_count = first_bb->out_count = 0;
1597 cfg->cbb = first_bb;
1599 else
1600 prev = ins;
1604 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1608 typedef union {
1609 guint32 vali [2];
1610 gint64 vall;
1611 double vald;
1612 } DVal;
1614 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1617 * mono_decompose_soft_float:
1619 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1620 * similar to long support on 32 bit platforms. 32 bit float values require special
1621 * handling when used as locals, arguments, and in calls.
1622 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1624 void
1625 mono_decompose_soft_float (MonoCompile *cfg)
1627 MonoBasicBlock *bb, *first_bb;
1630 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1634 * Create a dummy bblock and emit code into it so we can use the normal
1635 * code generation macros.
1637 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1638 first_bb = cfg->cbb;
1640 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1641 MonoInst *ins;
1642 MonoInst *prev = NULL;
1643 gboolean restart;
1645 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1647 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1648 restart = TRUE;
1650 while (restart) {
1651 restart = FALSE;
1653 for (ins = bb->code; ins; ins = ins->next) {
1654 const char *spec = INS_INFO (ins->opcode);
1656 /* Most fp operations are handled automatically by opcode emulation */
1658 switch (ins->opcode) {
1659 case OP_R8CONST: {
1660 DVal d;
1661 d.vald = *(double*)ins->inst_p0;
1662 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1663 break;
1665 case OP_R4CONST: {
1666 DVal d;
1667 /* We load the r8 value */
1668 d.vald = *(float*)ins->inst_p0;
1669 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1670 break;
1672 case OP_FMOVE:
1673 ins->opcode = OP_LMOVE;
1674 break;
1675 case OP_FGETLOW32:
1676 ins->opcode = OP_MOVE;
1677 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1678 break;
1679 case OP_FGETHIGH32:
1680 ins->opcode = OP_MOVE;
1681 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1682 break;
1683 case OP_SETFRET: {
1684 int reg = ins->sreg1;
1686 ins->opcode = OP_SETLRET;
1687 ins->dreg = -1;
1688 ins->sreg1 = MONO_LVREG_LS (reg);
1689 ins->sreg2 = MONO_LVREG_MS (reg);
1690 break;
1692 case OP_LOADR8_MEMBASE:
1693 ins->opcode = OP_LOADI8_MEMBASE;
1694 break;
1695 case OP_STORER8_MEMBASE_REG:
1696 ins->opcode = OP_STOREI8_MEMBASE_REG;
1697 break;
1698 case OP_STORER4_MEMBASE_REG: {
1699 MonoInst *iargs [2];
1700 int addr_reg;
1702 /* Arg 1 is the double value */
1703 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1704 iargs [0]->dreg = ins->sreg1;
1706 /* Arg 2 is the address to store to */
1707 addr_reg = mono_alloc_preg (cfg);
1708 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1709 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1710 restart = TRUE;
1711 break;
1713 case OP_LOADR4_MEMBASE: {
1714 MonoInst *iargs [1];
1715 MonoInst *conv;
1716 int addr_reg;
1718 addr_reg = mono_alloc_preg (cfg);
1719 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1720 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1721 conv->dreg = ins->dreg;
1722 break;
1724 case OP_FCALL:
1725 case OP_FCALL_REG:
1726 case OP_FCALL_MEMBASE: {
1727 MonoCallInst *call = (MonoCallInst*)ins;
1728 if (call->signature->ret->type == MONO_TYPE_R4) {
1729 MonoCallInst *call2;
1730 MonoInst *iargs [1];
1731 MonoInst *conv;
1732 GSList *l;
1734 /* Convert the call into a call returning an int */
1735 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1736 memcpy (call2, call, sizeof (MonoCallInst));
1737 switch (ins->opcode) {
1738 case OP_FCALL:
1739 call2->inst.opcode = OP_CALL;
1740 break;
1741 case OP_FCALL_REG:
1742 call2->inst.opcode = OP_CALL_REG;
1743 break;
1744 case OP_FCALL_MEMBASE:
1745 call2->inst.opcode = OP_CALL_MEMBASE;
1746 break;
1747 default:
1748 g_assert_not_reached ();
1750 call2->inst.dreg = mono_alloc_ireg (cfg);
1751 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1753 /* Remap OUTARG_VT instructions referencing this call */
1754 for (l = call->outarg_vts; l; l = l->next)
1755 ((MonoInst*)(l->data))->inst_p0 = call2;
1757 /* FIXME: Optimize this */
1759 /* Emit an r4->r8 conversion */
1760 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, mono_get_int32_type ());
1761 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1762 conv->dreg = ins->dreg;
1764 /* The call sequence might include fp ins */
1765 restart = TRUE;
1766 } else {
1767 switch (ins->opcode) {
1768 case OP_FCALL:
1769 ins->opcode = OP_LCALL;
1770 break;
1771 case OP_FCALL_REG:
1772 ins->opcode = OP_LCALL_REG;
1773 break;
1774 case OP_FCALL_MEMBASE:
1775 ins->opcode = OP_LCALL_MEMBASE;
1776 break;
1777 default:
1778 g_assert_not_reached ();
1781 break;
1783 case OP_FCOMPARE: {
1784 MonoJitICallInfo *info;
1785 MonoInst *iargs [2];
1786 MonoInst *call, *cmp, *br;
1788 /* Convert fcompare+fbcc to icall+icompare+beq */
1790 if (!ins->next) {
1791 /* The branch might be optimized away */
1792 NULLIFY_INS (ins);
1793 break;
1796 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1797 if (!info) {
1798 /* The branch might be optimized away */
1799 NULLIFY_INS (ins);
1800 break;
1803 /* Create dummy MonoInst's for the arguments */
1804 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1805 iargs [0]->dreg = ins->sreg1;
1806 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1807 iargs [1]->dreg = ins->sreg2;
1809 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1811 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1812 cmp->sreg1 = call->dreg;
1813 cmp->inst_imm = 0;
1814 MONO_ADD_INS (cfg->cbb, cmp);
1816 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1817 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1818 br->inst_true_bb = ins->next->inst_true_bb;
1819 br->inst_false_bb = ins->next->inst_false_bb;
1820 MONO_ADD_INS (cfg->cbb, br);
1822 /* The call sequence might include fp ins */
1823 restart = TRUE;
1825 /* Skip fbcc or fccc */
1826 NULLIFY_INS (ins->next);
1827 break;
1829 case OP_FCEQ:
1830 case OP_FCGT:
1831 case OP_FCGT_UN:
1832 case OP_FCLT:
1833 case OP_FCLT_UN: {
1834 MonoJitICallInfo *info;
1835 MonoInst *iargs [2];
1836 MonoInst *call;
1838 /* Convert fccc to icall+icompare+iceq */
1840 info = mono_find_jit_opcode_emulation (ins->opcode);
1841 g_assert (info);
1843 /* Create dummy MonoInst's for the arguments */
1844 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1845 iargs [0]->dreg = ins->sreg1;
1846 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1847 iargs [1]->dreg = ins->sreg2;
1849 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1851 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1852 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1854 /* The call sequence might include fp ins */
1855 restart = TRUE;
1856 break;
1858 case OP_CKFINITE: {
1859 MonoInst *iargs [2];
1860 MonoInst *call, *cmp;
1862 /* Convert to icall+icompare+cond_exc+move */
1864 /* Create dummy MonoInst's for the arguments */
1865 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1866 iargs [0]->dreg = ins->sreg1;
1868 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1870 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1871 cmp->sreg1 = call->dreg;
1872 cmp->inst_imm = 1;
1873 MONO_ADD_INS (cfg->cbb, cmp);
1875 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1877 /* Do the assignment if the value is finite */
1878 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1880 restart = TRUE;
1881 break;
1883 default:
1884 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1885 mono_print_ins (ins);
1886 g_assert_not_reached ();
1888 break;
1891 g_assert (cfg->cbb == first_bb);
1893 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1894 /* Replace the original instruction with the new code sequence */
1896 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1897 first_bb->code = first_bb->last_ins = NULL;
1898 first_bb->in_count = first_bb->out_count = 0;
1899 cfg->cbb = first_bb;
1901 else
1902 prev = ins;
1906 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1909 mono_decompose_long_opts (cfg);
1912 #endif
1914 void
1915 mono_local_emulate_ops (MonoCompile *cfg)
1917 MonoBasicBlock *bb;
1918 gboolean inlined_wrapper = FALSE;
1920 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1921 MonoInst *ins;
1923 MONO_BB_FOR_EACH_INS (bb, ins) {
1924 int op_noimm = mono_op_imm_to_op (ins->opcode);
1925 MonoJitICallInfo *info;
1928 * These opcodes don't have logical equivalence to the emulating native
1929 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1931 if (MONO_HAS_CUSTOM_EMULATION (ins))
1932 continue;
1935 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1936 * to check whether its non-imm counterpart is emulated and, if so,
1937 * decompose it back to its non-imm counterpart.
1939 if (op_noimm != -1)
1940 info = mono_find_jit_opcode_emulation (op_noimm);
1941 else
1942 info = mono_find_jit_opcode_emulation (ins->opcode);
1944 if (info) {
1945 MonoInst **args;
1946 MonoInst *call;
1947 MonoBasicBlock *first_bb;
1949 /* Create dummy MonoInst's for the arguments */
1950 g_assert (!info->sig->hasthis);
1951 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1953 if (op_noimm != -1)
1954 mono_decompose_op_imm (cfg, bb, ins);
1956 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1957 if (info->sig->param_count > 0) {
1958 int sregs [MONO_MAX_SRC_REGS];
1959 int num_sregs, i;
1960 num_sregs = mono_inst_get_src_registers (ins, sregs);
1961 g_assert (num_sregs == info->sig->param_count);
1962 for (i = 0; i < num_sregs; ++i) {
1963 MONO_INST_NEW (cfg, args [i], OP_ARG);
1964 args [i]->dreg = sregs [i];
1968 /* We emit the call on a separate dummy basic block */
1969 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1970 first_bb = cfg->cbb;
1972 call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
1973 call->dreg = ins->dreg;
1975 /* Replace ins with the emitted code and do the necessary bb linking */
1976 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1977 MonoInst *saved_prev = ins->prev;
1979 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1980 first_bb->code = first_bb->last_ins = NULL;
1981 first_bb->in_count = first_bb->out_count = 0;
1982 cfg->cbb = first_bb;
1984 /* ins is hanging, continue scanning the emitted code */
1985 ins = saved_prev;
1986 } else {
1987 g_error ("Failed to emit emulation code");
1989 inlined_wrapper = TRUE;
1995 * Avoid rerunning these passes by emitting directly the exception checkpoint
1996 * at IR level, instead of inlining the icall wrapper. FIXME
1998 if (inlined_wrapper) {
1999 if (!COMPILE_LLVM (cfg))
2000 mono_decompose_long_opts (cfg);
2001 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
2002 mono_local_cprop (cfg);
2006 #else /* !DISABLE_JIT */
2008 MONO_EMPTY_SOURCE_FILE (decompose);
2010 #endif /* !DISABLE_JIT */