[ci] Bump timeout in ms-test-suite
[mono-project.git] / mono / mini / decompose.c
blobaaa34a3bc34fba472c49726be3bd70936bc4426a
1 /*
2 * decompose.c: Functions to decompose complex IR instructions into simpler ones.
4 * Author:
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2002 Ximian, Inc.
8 * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
12 #include "mini.h"
13 #include "ir-emit.h"
14 #include "jit-icalls.h"
16 #include <mono/metadata/gc-internals.h>
17 #include <mono/metadata/abi-details.h>
18 #include <mono/utils/mono-compiler.h>
20 #ifndef DISABLE_JIT
22 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
23 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
24 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
25 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
28 * Decompose complex long opcodes on 64 bit machines.
29 * This is also used on 32 bit machines when using LLVM, so it needs to handle I/U correctly.
31 static gboolean
32 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
34 MonoInst *repl = NULL;
36 *repl_ins = NULL;
38 switch (ins->opcode) {
39 case OP_LCONV_TO_I4:
40 ins->opcode = OP_SEXT_I4;
41 break;
42 case OP_LCONV_TO_I8:
43 case OP_LCONV_TO_U8:
44 if (SIZEOF_VOID_P == 4)
45 ins->opcode = OP_LMOVE;
46 else
47 ins->opcode = OP_MOVE;
48 break;
49 case OP_LCONV_TO_I:
50 if (SIZEOF_VOID_P == 4)
51 /* OP_LCONV_TO_I4 */
52 ins->opcode = OP_SEXT_I4;
53 else
54 ins->opcode = OP_MOVE;
55 break;
56 case OP_LCONV_TO_U:
57 if (SIZEOF_VOID_P == 4) {
58 /* OP_LCONV_TO_U4 */
59 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
60 NULLIFY_INS (ins);
61 } else {
62 ins->opcode = OP_MOVE;
64 break;
65 case OP_ICONV_TO_I8:
66 ins->opcode = OP_SEXT_I4;
67 break;
68 case OP_ICONV_TO_U8:
69 ins->opcode = OP_ZEXT_I4;
70 break;
71 case OP_LCONV_TO_U4:
72 /* Clean out the upper word */
73 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
74 NULLIFY_INS (ins);
75 break;
76 case OP_LADD_OVF: {
77 int opcode;
79 if (COMPILE_LLVM (cfg))
80 break;
81 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
82 opcode = OP_LADDCC;
83 else
84 opcode = OP_ADDCC;
85 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
86 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
87 NULLIFY_INS (ins);
88 break;
90 case OP_LADD_OVF_UN: {
91 int opcode;
93 if (COMPILE_LLVM (cfg))
94 break;
95 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
96 opcode = OP_LADDCC;
97 else
98 opcode = OP_ADDCC;
99 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
100 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
101 NULLIFY_INS (ins);
102 break;
104 #ifndef __mono_ppc64__
105 case OP_LSUB_OVF: {
106 int opcode;
108 if (COMPILE_LLVM (cfg))
109 break;
110 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
111 opcode = OP_LSUBCC;
112 else
113 opcode = OP_SUBCC;
114 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
115 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
116 NULLIFY_INS (ins);
117 break;
119 case OP_LSUB_OVF_UN: {
120 int opcode;
122 if (COMPILE_LLVM (cfg))
123 break;
124 if (cfg->backend->ilp32 && SIZEOF_REGISTER == 8)
125 opcode = OP_LSUBCC;
126 else
127 opcode = OP_SUBCC;
128 EMIT_NEW_BIALU (cfg, repl, opcode, ins->dreg, ins->sreg1, ins->sreg2);
129 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
130 NULLIFY_INS (ins);
131 break;
133 #endif
135 case OP_ICONV_TO_OVF_I8:
136 case OP_ICONV_TO_OVF_I:
137 ins->opcode = OP_SEXT_I4;
138 break;
139 case OP_ICONV_TO_OVF_U8:
140 case OP_ICONV_TO_OVF_U:
141 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
142 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
143 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
144 NULLIFY_INS (ins);
145 break;
146 case OP_ICONV_TO_OVF_I8_UN:
147 case OP_ICONV_TO_OVF_U8_UN:
148 case OP_ICONV_TO_OVF_I_UN:
149 case OP_ICONV_TO_OVF_U_UN:
150 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
151 /* Clean out the upper word */
152 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
153 NULLIFY_INS (ins);
154 break;
155 case OP_LCONV_TO_OVF_I1:
156 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
157 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
158 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
159 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
160 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
161 NULLIFY_INS (ins);
162 break;
163 case OP_LCONV_TO_OVF_I1_UN:
164 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
165 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
166 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
167 NULLIFY_INS (ins);
168 break;
169 case OP_LCONV_TO_OVF_U1:
170 /* probe value to be within 0 to 255 */
171 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
172 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
173 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
174 NULLIFY_INS (ins);
175 break;
176 case OP_LCONV_TO_OVF_U1_UN:
177 /* probe value to be within 0 to 255 */
178 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
179 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
180 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
181 NULLIFY_INS (ins);
182 break;
183 case OP_LCONV_TO_OVF_I2:
184 /* Probe value to be within -32768 and 32767 */
185 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
186 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
187 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
188 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
189 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
190 NULLIFY_INS (ins);
191 break;
192 case OP_LCONV_TO_OVF_I2_UN:
193 /* Probe value to be within 0 and 32767 */
194 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
195 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
196 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
197 NULLIFY_INS (ins);
198 break;
199 case OP_LCONV_TO_OVF_U2:
200 /* Probe value to be within 0 and 65535 */
201 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
202 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
203 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
204 NULLIFY_INS (ins);
205 break;
206 case OP_LCONV_TO_OVF_U2_UN:
207 /* Probe value to be within 0 and 65535 */
208 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
209 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
210 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
211 NULLIFY_INS (ins);
212 break;
213 case OP_LCONV_TO_OVF_I4:
214 #if SIZEOF_VOID_P == 4
215 case OP_LCONV_TO_OVF_I:
216 #endif
217 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
218 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
219 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
220 #if SIZEOF_REGISTER == 8
221 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
222 #else
223 g_assert (COMPILE_LLVM (cfg));
224 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
225 #endif
226 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
227 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
228 NULLIFY_INS (ins);
229 break;
230 case OP_LCONV_TO_OVF_I4_UN:
231 #if SIZEOF_VOID_P == 4
232 case OP_LCONV_TO_OVF_I_UN:
233 #endif
234 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
235 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
236 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
237 NULLIFY_INS (ins);
238 break;
239 case OP_LCONV_TO_OVF_U4:
240 #if SIZEOF_VOID_P == 4
241 case OP_LCONV_TO_OVF_U:
242 #endif
243 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
244 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
245 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
246 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
247 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
248 NULLIFY_INS (ins);
249 break;
250 case OP_LCONV_TO_OVF_U4_UN:
251 #if SIZEOF_VOID_P == 4
252 case OP_LCONV_TO_OVF_U_UN:
253 #endif
254 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
255 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
256 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
257 NULLIFY_INS (ins);
258 break;
259 #if SIZEOF_VOID_P == 8
260 case OP_LCONV_TO_OVF_I:
261 case OP_LCONV_TO_OVF_U_UN:
262 #endif
263 case OP_LCONV_TO_OVF_U8_UN:
264 case OP_LCONV_TO_OVF_I8:
265 ins->opcode = OP_MOVE;
266 break;
267 #if SIZEOF_VOID_P == 8
268 case OP_LCONV_TO_OVF_I_UN:
269 #endif
270 case OP_LCONV_TO_OVF_I8_UN:
271 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
272 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
273 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
274 NULLIFY_INS (ins);
275 break;
276 case OP_LCONV_TO_OVF_U8:
277 #if SIZEOF_VOID_P == 8
278 case OP_LCONV_TO_OVF_U:
279 #endif
280 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
281 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
282 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
283 NULLIFY_INS (ins);
284 break;
285 default:
286 return FALSE;
289 *repl_ins = repl;
290 return TRUE;
294 * mono_decompose_opcode:
296 * Decompose complex opcodes into ones closer to opcodes supported by
297 * the given architecture.
298 * Returns a MonoInst which represents the result of the decomposition, and can
299 * be pushed on the IL stack. This is needed because the original instruction is
300 * nullified.
301 * Sets the cfg exception if an opcode is not supported.
303 MonoInst*
304 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
306 MonoInst *repl = NULL;
307 int type = ins->type;
308 int dreg = ins->dreg;
309 gboolean emulate = FALSE;
311 /* FIXME: Instead of = NOP, don't emit the original ins at all */
312 mono_arch_decompose_opts (cfg, ins);
315 * The code below assumes that we are called immediately after emitting
316 * ins. This means we can emit code using the normal code generation
317 * macros.
319 switch (ins->opcode) {
320 /* this doesn't make sense on ppc and other architectures */
321 #if !defined(MONO_ARCH_NO_IOV_CHECK)
322 case OP_IADD_OVF:
323 if (COMPILE_LLVM (cfg))
324 break;
325 ins->opcode = OP_IADDCC;
326 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
327 break;
328 case OP_IADD_OVF_UN:
329 if (COMPILE_LLVM (cfg))
330 break;
331 ins->opcode = OP_IADDCC;
332 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
333 break;
334 case OP_ISUB_OVF:
335 if (COMPILE_LLVM (cfg))
336 break;
337 ins->opcode = OP_ISUBCC;
338 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
339 break;
340 case OP_ISUB_OVF_UN:
341 if (COMPILE_LLVM (cfg))
342 break;
343 ins->opcode = OP_ISUBCC;
344 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
345 break;
346 #endif
347 case OP_ICONV_TO_OVF_I1:
348 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
349 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
350 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
351 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
352 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
353 NULLIFY_INS (ins);
354 break;
355 case OP_ICONV_TO_OVF_I1_UN:
356 /* probe values between 0 to 127 */
357 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
358 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
359 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
360 NULLIFY_INS (ins);
361 break;
362 case OP_ICONV_TO_OVF_U1:
363 case OP_ICONV_TO_OVF_U1_UN:
364 /* probe value to be within 0 to 255 */
365 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
366 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
367 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
368 NULLIFY_INS (ins);
369 break;
370 case OP_ICONV_TO_OVF_I2:
371 /* Probe value to be within -32768 and 32767 */
372 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
373 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
374 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
375 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
376 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
377 NULLIFY_INS (ins);
378 break;
379 case OP_ICONV_TO_OVF_I2_UN:
380 /* Convert uint value into short, value within 0 and 32767 */
381 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
382 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
383 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
384 NULLIFY_INS (ins);
385 break;
386 case OP_ICONV_TO_OVF_U2:
387 case OP_ICONV_TO_OVF_U2_UN:
388 /* Probe value to be within 0 and 65535 */
389 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
390 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
391 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
392 NULLIFY_INS (ins);
393 break;
394 case OP_ICONV_TO_OVF_U4:
395 case OP_ICONV_TO_OVF_I4_UN:
396 #if SIZEOF_VOID_P == 4
397 case OP_ICONV_TO_OVF_U:
398 case OP_ICONV_TO_OVF_I_UN:
399 #endif
400 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
401 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
402 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
403 NULLIFY_INS (ins);
404 break;
405 case OP_ICONV_TO_I4:
406 case OP_ICONV_TO_U4:
407 case OP_ICONV_TO_OVF_I4:
408 case OP_ICONV_TO_OVF_U4_UN:
409 #if SIZEOF_VOID_P == 4
410 case OP_ICONV_TO_OVF_I:
411 case OP_ICONV_TO_OVF_U_UN:
412 #endif
413 ins->opcode = OP_MOVE;
414 break;
415 case OP_ICONV_TO_I:
416 #if SIZEOF_VOID_P == 8
417 ins->opcode = OP_SEXT_I4;
418 #else
419 ins->opcode = OP_MOVE;
420 #endif
421 break;
422 case OP_ICONV_TO_U:
423 #if SIZEOF_VOID_P == 8
424 ins->opcode = OP_ZEXT_I4;
425 #else
426 ins->opcode = OP_MOVE;
427 #endif
428 break;
430 case OP_FCONV_TO_R8:
431 ins->opcode = OP_FMOVE;
432 break;
434 case OP_FCONV_TO_OVF_I1_UN:
435 case OP_FCONV_TO_OVF_I2_UN:
436 case OP_FCONV_TO_OVF_I4_UN:
437 case OP_FCONV_TO_OVF_I8_UN:
438 case OP_FCONV_TO_OVF_U1_UN:
439 case OP_FCONV_TO_OVF_U2_UN:
440 case OP_FCONV_TO_OVF_U4_UN:
441 case OP_FCONV_TO_OVF_U8_UN:
442 case OP_FCONV_TO_OVF_I_UN:
443 case OP_FCONV_TO_OVF_U_UN:
444 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
445 break;
447 case OP_IDIV:
448 case OP_IREM:
449 case OP_IDIV_UN:
450 case OP_IREM_UN:
451 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
452 emulate = TRUE;
453 if (!emulate) {
454 if (cfg->backend->need_div_check) {
455 int reg1 = alloc_ireg (cfg);
456 int reg2 = alloc_ireg (cfg);
457 /* b == 0 */
458 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
459 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
460 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
461 /* b == -1 && a == 0x80000000 */
462 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
463 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
464 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
465 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
466 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
467 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
468 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
471 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
472 NULLIFY_INS (ins);
474 break;
476 #if SIZEOF_VOID_P == 8
477 case OP_LDIV:
478 case OP_LREM:
479 case OP_LDIV_UN:
480 case OP_LREM_UN:
481 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
482 emulate = TRUE;
483 if (!emulate) {
484 if (cfg->backend->need_div_check) {
485 int reg1 = alloc_ireg (cfg);
486 int reg2 = alloc_ireg (cfg);
487 int reg3 = alloc_ireg (cfg);
488 /* b == 0 */
489 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
490 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
491 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
492 /* b == -1 && a == 0x80000000 */
493 MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
494 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
495 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
496 MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
497 MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
498 MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
499 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
500 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
501 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
504 MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
505 NULLIFY_INS (ins);
507 break;
508 #endif
510 case OP_DIV_IMM:
511 case OP_REM_IMM:
512 case OP_IDIV_IMM:
513 case OP_IREM_IMM:
514 case OP_IDIV_UN_IMM:
515 case OP_IREM_UN_IMM:
516 if (cfg->backend->need_div_check) {
517 int reg1 = alloc_ireg (cfg);
518 /* b == 0 */
519 if (ins->inst_imm == 0) {
520 // FIXME: Optimize this
521 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
522 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
523 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
525 if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
526 (ins->inst_imm == -1)) {
527 /* b == -1 && a == 0x80000000 */
528 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
529 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
531 MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
532 NULLIFY_INS (ins);
533 } else {
534 emulate = TRUE;
536 break;
538 default:
539 emulate = TRUE;
540 break;
543 if (emulate) {
544 #if SIZEOF_REGISTER == 8
545 if (decompose_long_opcode (cfg, ins, &repl))
546 emulate = FALSE;
547 #else
548 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
549 emulate = FALSE;
550 #endif
552 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
553 cfg->has_emulated_ops = TRUE;
556 if (ins->opcode == OP_NOP) {
557 if (repl) {
558 repl->type = type;
559 return repl;
560 } else {
561 /* Use the last emitted instruction */
562 ins = cfg->cbb->last_ins;
563 g_assert (ins);
564 ins->type = type;
565 g_assert (ins->dreg == dreg);
566 return ins;
568 } else {
569 return ins;
573 #if SIZEOF_REGISTER == 4
574 static int lbr_decomp [][2] = {
575 {0, 0}, /* BEQ */
576 {OP_IBGT, OP_IBGE_UN}, /* BGE */
577 {OP_IBGT, OP_IBGT_UN}, /* BGT */
578 {OP_IBLT, OP_IBLE_UN}, /* BLE */
579 {OP_IBLT, OP_IBLT_UN}, /* BLT */
580 {0, 0}, /* BNE_UN */
581 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
582 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
583 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
584 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
587 static int lcset_decomp [][2] = {
588 {0, 0}, /* CEQ */
589 {OP_IBLT, OP_IBLE_UN}, /* CGT */
590 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
591 {OP_IBGT, OP_IBGE_UN}, /* CLT */
592 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
594 #endif
597 * mono_decompose_long_opts:
599 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
601 void
602 mono_decompose_long_opts (MonoCompile *cfg)
604 #if SIZEOF_REGISTER == 4
605 MonoBasicBlock *bb, *first_bb;
608 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
609 * needs to be able to handle long vregs.
613 * Create a dummy bblock and emit code into it so we can use the normal
614 * code generation macros.
616 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
617 first_bb = cfg->cbb;
619 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
620 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
621 MonoInst *prev = NULL;
624 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
627 cfg->cbb->code = cfg->cbb->last_ins = NULL;
629 while (tree) {
630 mono_arch_decompose_long_opts (cfg, tree);
632 switch (tree->opcode) {
633 case OP_I8CONST:
634 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
635 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
636 break;
637 case OP_DUMMY_I8CONST:
638 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
639 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
640 break;
641 case OP_LMOVE:
642 case OP_LCONV_TO_U8:
643 case OP_LCONV_TO_I8:
644 case OP_LCONV_TO_OVF_U8_UN:
645 case OP_LCONV_TO_OVF_I8:
646 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
647 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
648 break;
649 case OP_STOREI8_MEMBASE_REG:
650 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (tree->sreg1));
651 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (tree->sreg1));
652 break;
653 case OP_LOADI8_MEMBASE:
654 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_MS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
655 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_LS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
656 break;
658 case OP_ICONV_TO_I8: {
659 guint32 tmpreg = alloc_ireg (cfg);
661 /* branchless code:
662 * low = reg;
663 * tmp = low > -1 ? 1: 0;
664 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
666 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
667 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
668 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
669 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
670 break;
672 case OP_ICONV_TO_U8:
673 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
674 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
675 break;
676 case OP_ICONV_TO_OVF_I8:
677 /* a signed 32 bit num always fits in a signed 64 bit one */
678 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
679 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
680 break;
681 case OP_ICONV_TO_OVF_U8:
682 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
683 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
684 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
685 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
686 break;
687 case OP_ICONV_TO_OVF_I8_UN:
688 case OP_ICONV_TO_OVF_U8_UN:
689 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
690 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
691 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
692 break;
693 case OP_LCONV_TO_I1:
694 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
695 break;
696 case OP_LCONV_TO_U1:
697 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
698 break;
699 case OP_LCONV_TO_I2:
700 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
701 break;
702 case OP_LCONV_TO_U2:
703 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
704 break;
705 case OP_LCONV_TO_I4:
706 case OP_LCONV_TO_U4:
707 case OP_LCONV_TO_I:
708 case OP_LCONV_TO_U:
709 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
710 break;
711 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
712 case OP_LCONV_TO_R8:
713 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
714 break;
715 #endif
716 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
717 case OP_LCONV_TO_R4:
718 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
719 break;
720 #endif
721 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
722 case OP_LCONV_TO_R_UN:
723 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
724 break;
725 #endif
726 case OP_LCONV_TO_OVF_I1: {
727 MonoBasicBlock *is_negative, *end_label;
729 NEW_BBLOCK (cfg, is_negative);
730 NEW_BBLOCK (cfg, end_label);
732 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
733 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
734 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
735 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
737 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
738 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
740 /* Positive */
741 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
742 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
743 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
745 /* Negative */
746 MONO_START_BB (cfg, is_negative);
747 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
748 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
750 MONO_START_BB (cfg, end_label);
752 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
753 break;
755 case OP_LCONV_TO_OVF_I1_UN:
756 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
757 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
759 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
760 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
761 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
762 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
763 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
764 break;
765 case OP_LCONV_TO_OVF_U1:
766 case OP_LCONV_TO_OVF_U1_UN:
767 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
768 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
770 /* probe value to be within 0 to 255 */
771 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
772 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
773 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
774 break;
775 case OP_LCONV_TO_OVF_I2: {
776 MonoBasicBlock *is_negative, *end_label;
778 NEW_BBLOCK (cfg, is_negative);
779 NEW_BBLOCK (cfg, end_label);
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
782 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
783 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
784 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
786 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
787 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
789 /* Positive */
790 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
791 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
792 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
794 /* Negative */
795 MONO_START_BB (cfg, is_negative);
796 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
797 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
798 MONO_START_BB (cfg, end_label);
800 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
801 break;
803 case OP_LCONV_TO_OVF_I2_UN:
804 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
805 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
807 /* Probe value to be within -32768 and 32767 */
808 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
809 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
810 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
811 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
812 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
813 break;
814 case OP_LCONV_TO_OVF_U2:
815 case OP_LCONV_TO_OVF_U2_UN:
816 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
817 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
819 /* Probe value to be within 0 and 65535 */
820 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
821 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
822 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
823 break;
824 case OP_LCONV_TO_OVF_I4:
825 case OP_LCONV_TO_OVF_I:
826 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
827 break;
828 case OP_LCONV_TO_OVF_U4:
829 case OP_LCONV_TO_OVF_U:
830 case OP_LCONV_TO_OVF_U4_UN:
831 case OP_LCONV_TO_OVF_U_UN:
832 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
833 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
834 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
835 break;
836 case OP_LCONV_TO_OVF_I_UN:
837 case OP_LCONV_TO_OVF_I4_UN:
838 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
839 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
840 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
841 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
842 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
843 break;
844 case OP_LCONV_TO_OVF_U8:
845 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
846 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
848 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
849 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
850 break;
851 case OP_LCONV_TO_OVF_I8_UN:
852 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
853 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
855 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
856 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
857 break;
859 case OP_LADD:
860 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
861 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
862 break;
863 case OP_LSUB:
864 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
865 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
866 break;
868 case OP_LADD_OVF:
869 /* ADC sets the condition code */
870 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
871 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
872 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
873 break;
874 case OP_LADD_OVF_UN:
875 /* ADC sets the condition code */
876 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
877 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
878 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
879 break;
880 case OP_LSUB_OVF:
881 /* SBB sets the condition code */
882 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
883 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
884 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
885 break;
886 case OP_LSUB_OVF_UN:
887 /* SBB sets the condition code */
888 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
889 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
890 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
891 break;
892 case OP_LAND:
893 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
894 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
895 break;
896 case OP_LOR:
897 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
898 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
899 break;
900 case OP_LXOR:
901 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
902 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
903 break;
904 case OP_LNOT:
905 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
906 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
907 break;
908 case OP_LNEG:
909 /* Handled in mono_arch_decompose_long_opts () */
910 g_assert_not_reached ();
911 break;
912 case OP_LMUL:
913 /* Emulated */
914 /* FIXME: Add OP_BIGMUL optimization */
915 break;
917 case OP_LADD_IMM:
918 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
919 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
920 break;
921 case OP_LSUB_IMM:
922 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
923 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
924 break;
925 case OP_LAND_IMM:
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
928 break;
929 case OP_LOR_IMM:
930 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
931 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
932 break;
933 case OP_LXOR_IMM:
934 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
935 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
936 break;
937 #ifdef TARGET_POWERPC
938 /* FIXME This is normally handled in cprop. Proper fix or remove if no longer needed. */
939 case OP_LSHR_UN_IMM:
940 if (tree->inst_c1 == 32) {
942 /* The original code had this comment: */
943 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
944 * later apply the speedup to the left shift as well
945 * See BUG# 57957.
947 /* just move the upper half to the lower and zero the high word */
948 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
949 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
951 break;
952 #endif
953 case OP_LCOMPARE: {
954 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
956 g_assert (next);
958 switch (next->opcode) {
959 case OP_LBEQ:
960 case OP_LBNE_UN: {
961 int d1, d2;
963 /* Branchless version based on gcc code */
964 d1 = alloc_ireg (cfg);
965 d2 = alloc_ireg (cfg);
966 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
967 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
968 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
969 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
970 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
971 NULLIFY_INS (next);
972 break;
974 case OP_LBGE:
975 case OP_LBGT:
976 case OP_LBLE:
977 case OP_LBLT:
978 case OP_LBGE_UN:
979 case OP_LBGT_UN:
980 case OP_LBLE_UN:
981 case OP_LBLT_UN:
982 /* Convert into three comparisons + branches */
983 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
984 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
985 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
986 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
987 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
988 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
989 NULLIFY_INS (next);
990 break;
991 case OP_LCEQ: {
992 int d1, d2;
994 /* Branchless version based on gcc code */
995 d1 = alloc_ireg (cfg);
996 d2 = alloc_ireg (cfg);
997 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
998 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
999 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1001 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1002 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1003 NULLIFY_INS (next);
1004 break;
1006 case OP_LCLT:
1007 case OP_LCLT_UN:
1008 case OP_LCGT:
1009 case OP_LCGT_UN: {
1010 MonoBasicBlock *set_to_0, *set_to_1;
1012 NEW_BBLOCK (cfg, set_to_0);
1013 NEW_BBLOCK (cfg, set_to_1);
1015 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1016 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1017 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1018 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1019 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1020 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1021 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1022 MONO_START_BB (cfg, set_to_1);
1023 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1024 MONO_START_BB (cfg, set_to_0);
1025 NULLIFY_INS (next);
1026 break;
1028 default:
1029 g_assert_not_reached ();
1031 break;
1034 /* Not yet used, since lcompare is decomposed before local cprop */
1035 case OP_LCOMPARE_IMM: {
1036 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1037 guint32 low_imm = tree->inst_ls_word;
1038 guint32 high_imm = tree->inst_ms_word;
1039 int low_reg = MONO_LVREG_LS (tree->sreg1);
1040 int high_reg = MONO_LVREG_MS (tree->sreg1);
1042 g_assert (next);
1044 switch (next->opcode) {
1045 case OP_LBEQ:
1046 case OP_LBNE_UN: {
1047 int d1, d2;
1049 /* Branchless version based on gcc code */
1050 d1 = alloc_ireg (cfg);
1051 d2 = alloc_ireg (cfg);
1052 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1053 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1054 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1055 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1056 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1057 NULLIFY_INS (next);
1058 break;
1061 case OP_LBGE:
1062 case OP_LBGT:
1063 case OP_LBLE:
1064 case OP_LBLT:
1065 case OP_LBGE_UN:
1066 case OP_LBGT_UN:
1067 case OP_LBLE_UN:
1068 case OP_LBLT_UN:
1069 /* Convert into three comparisons + branches */
1070 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1071 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1072 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1073 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1074 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1075 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1076 NULLIFY_INS (next);
1077 break;
1078 case OP_LCEQ: {
1079 int d1, d2;
1081 /* Branchless version based on gcc code */
1082 d1 = alloc_ireg (cfg);
1083 d2 = alloc_ireg (cfg);
1084 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1085 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1086 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1088 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1089 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1090 NULLIFY_INS (next);
1091 break;
1093 case OP_LCLT:
1094 case OP_LCLT_UN:
1095 case OP_LCGT:
1096 case OP_LCGT_UN: {
1097 MonoBasicBlock *set_to_0, *set_to_1;
1099 NEW_BBLOCK (cfg, set_to_0);
1100 NEW_BBLOCK (cfg, set_to_1);
1102 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1103 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1104 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1105 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1106 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1107 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1108 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1109 MONO_START_BB (cfg, set_to_1);
1110 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1111 MONO_START_BB (cfg, set_to_0);
1112 NULLIFY_INS (next);
1113 break;
1115 default:
1116 g_assert_not_reached ();
1118 break;
1121 default:
1122 break;
1125 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1126 MonoInst *new_prev;
1128 /* Replace the original instruction with the new code sequence */
1130 /* Ignore the new value of prev */
1131 new_prev = prev;
1132 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1134 /* Process the newly added ops again since they can be long ops too */
1135 if (prev)
1136 tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1137 else
1138 tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1140 first_bb->code = first_bb->last_ins = NULL;
1141 first_bb->in_count = first_bb->out_count = 0;
1142 cfg->cbb = first_bb;
1144 else {
1145 prev = tree;
1146 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1150 #endif
1153 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1154 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1159 * mono_decompose_vtype_opts:
1161 * Decompose valuetype opcodes.
1163 void
1164 mono_decompose_vtype_opts (MonoCompile *cfg)
1166 MonoBasicBlock *bb, *first_bb;
1169 * Using OP_V opcodes and decomposing them later have two main benefits:
1170 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1171 * everywhere.
1172 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1173 * enabling optimizations to work on vtypes too.
1174 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1175 * can be executed anytime. It should be executed as late as possible so vtype
1176 * opcodes can be optimized by the other passes.
1177 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1178 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1179 * var to 1.
1180 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1181 * when OP_VMOVE opcodes are decomposed.
1185 * Vregs have no associated type information, so we store the type of the vregs
1186 * in ins->klass.
1190 * Create a dummy bblock and emit code into it so we can use the normal
1191 * code generation macros.
1193 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1194 first_bb = cfg->cbb;
1196 /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1198 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1199 MonoInst *ins;
1200 MonoInst *prev = NULL;
1201 MonoInst *src_var, *dest_var, *src, *dest;
1202 gboolean restart;
1203 int dreg;
1205 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1207 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1208 restart = TRUE;
1210 while (restart) {
1211 restart = FALSE;
1213 for (ins = bb->code; ins; ins = ins->next) {
1214 switch (ins->opcode) {
1215 case OP_VMOVE: {
1216 g_assert (ins->klass);
1217 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1218 break;
1219 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1220 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1222 if (!src_var)
1223 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1225 if (!dest_var)
1226 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1228 // FIXME:
1229 if (src_var->backend.is_pinvoke)
1230 dest_var->backend.is_pinvoke = 1;
1232 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1233 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1235 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1236 break;
1238 case OP_VZERO:
1239 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1240 break;
1242 g_assert (ins->klass);
1244 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1245 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1247 if (cfg->compute_gc_maps) {
1248 MonoInst *tmp;
1251 * Tell the GC map code that the vtype is considered live after
1252 * the initialization.
1254 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1255 tmp->inst_c1 = ins->dreg;
1256 MONO_ADD_INS (cfg->cbb, tmp);
1258 break;
1259 case OP_DUMMY_VZERO:
1260 if (COMPILE_LLVM (cfg))
1261 break;
1263 NULLIFY_INS (ins);
1264 break;
1265 case OP_STOREV_MEMBASE: {
1266 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1268 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass) && !cfg->gen_write_barriers)
1269 break;
1271 if (!src_var) {
1272 g_assert (ins->klass);
1273 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1276 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1278 dreg = alloc_preg (cfg);
1279 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1280 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1281 break;
1283 case OP_LOADV_MEMBASE: {
1284 g_assert (ins->klass);
1285 if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1286 break;
1288 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1289 // FIXME-VT:
1290 // FIXME:
1291 if (!dest_var)
1292 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1294 dreg = alloc_preg (cfg);
1295 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1296 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1297 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1298 break;
1300 case OP_OUTARG_VT: {
1301 if (COMPILE_LLVM (cfg))
1302 break;
1304 g_assert (ins->klass);
1306 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1307 if (!src_var)
1308 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1309 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1311 mono_arch_emit_outarg_vt (cfg, ins, src);
1313 /* This might be decomposed into other vtype opcodes */
1314 restart = TRUE;
1315 break;
1317 case OP_OUTARG_VTRETADDR: {
1318 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1320 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1321 if (!src_var)
1322 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1323 // FIXME: src_var->backend.is_pinvoke ?
1325 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1326 src->dreg = ins->dreg;
1327 break;
1329 case OP_VCALL:
1330 case OP_VCALL_REG:
1331 case OP_VCALL_MEMBASE: {
1332 MonoCallInst *call = (MonoCallInst*)ins;
1333 int size;
1335 if (COMPILE_LLVM (cfg))
1336 break;
1338 if (call->vret_in_reg) {
1339 MonoCallInst *call2;
1341 /* Replace the vcall with a scalar call */
1342 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1343 memcpy (call2, call, sizeof (MonoCallInst));
1344 switch (ins->opcode) {
1345 case OP_VCALL:
1346 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1347 break;
1348 case OP_VCALL_REG:
1349 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1350 break;
1351 case OP_VCALL_MEMBASE:
1352 call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1353 break;
1355 call2->inst.dreg = alloc_preg (cfg);
1356 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1358 /* Compute the vtype location */
1359 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1360 if (!dest_var)
1361 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1362 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1364 /* Save the result */
1365 if (dest_var->backend.is_pinvoke)
1366 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1367 else
1368 size = mono_type_size (dest_var->inst_vtype, NULL);
1369 switch (size) {
1370 case 1:
1371 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1372 break;
1373 case 2:
1374 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1375 break;
1376 case 3:
1377 case 4:
1378 if (call->vret_in_reg_fp)
1379 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1380 else
1381 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1382 break;
1383 case 5:
1384 case 6:
1385 case 7:
1386 case 8:
1387 if (call->vret_in_reg_fp) {
1388 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1389 break;
1391 #if SIZEOF_REGISTER == 4
1393 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1394 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1396 switch (call2->inst.opcode) {
1397 case OP_CALL:
1398 call2->inst.opcode = OP_LCALL;
1399 break;
1400 case OP_CALL_REG:
1401 call2->inst.opcode = OP_LCALL_REG;
1402 break;
1403 case OP_CALL_MEMBASE:
1404 call2->inst.opcode = OP_LCALL_MEMBASE;
1405 break;
1407 call2->inst.dreg = alloc_lreg (cfg);
1408 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1409 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1410 #else
1411 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1412 #endif
1413 break;
1414 default:
1415 /* This assumes the vtype is sizeof (gpointer) long */
1416 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1417 break;
1419 } else {
1420 switch (ins->opcode) {
1421 case OP_VCALL:
1422 ins->opcode = OP_VCALL2;
1423 break;
1424 case OP_VCALL_REG:
1425 ins->opcode = OP_VCALL2_REG;
1426 break;
1427 case OP_VCALL_MEMBASE:
1428 ins->opcode = OP_VCALL2_MEMBASE;
1429 break;
1431 ins->dreg = -1;
1433 break;
1435 default:
1436 break;
1439 g_assert (cfg->cbb == first_bb);
1441 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1442 /* Replace the original instruction with the new code sequence */
1444 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1445 first_bb->code = first_bb->last_ins = NULL;
1446 first_bb->in_count = first_bb->out_count = 0;
1447 cfg->cbb = first_bb;
1449 else
1450 prev = ins;
1454 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1458 inline static MonoInst *
1459 mono_get_domainvar (MonoCompile *cfg)
1461 if (!cfg->domainvar)
1462 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1463 return cfg->domainvar;
1467 * mono_decompose_array_access_opts:
1469 * Decompose array access opcodes.
1471 void
1472 mono_decompose_array_access_opts (MonoCompile *cfg)
1474 MonoBasicBlock *bb, *first_bb;
1477 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1478 * can be executed anytime. It should be run before decompose_long
1482 * Create a dummy bblock and emit code into it so we can use the normal
1483 * code generation macros.
1485 cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1486 first_bb = cfg->cbb;
1488 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1489 MonoInst *ins;
1490 MonoInst *prev = NULL;
1491 MonoInst *dest;
1492 MonoInst *iargs [3];
1493 gboolean restart;
1495 if (!bb->has_array_access)
1496 continue;
1498 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1500 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1501 restart = TRUE;
1503 while (restart) {
1504 restart = FALSE;
1506 for (ins = bb->code; ins; ins = ins->next) {
1507 switch (ins->opcode) {
1508 case OP_LDLEN:
1509 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1510 MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1511 MONO_ADD_INS (cfg->cbb, dest);
1512 break;
1513 case OP_BOUNDS_CHECK:
1514 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1515 if (COMPILE_LLVM (cfg))
1516 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1517 else
1518 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1519 break;
1520 case OP_NEWARR:
1521 if (cfg->opt & MONO_OPT_SHARED) {
1522 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1523 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1524 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1525 iargs [2]->dreg = ins->sreg1;
1527 dest = mono_emit_jit_icall (cfg, ves_icall_array_new, iargs);
1528 dest->dreg = ins->dreg;
1529 } else {
1530 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1531 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1532 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1534 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1535 NEW_VTABLECONST (cfg, iargs [0], vtable);
1536 MONO_ADD_INS (cfg->cbb, iargs [0]);
1537 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1538 iargs [1]->dreg = ins->sreg1;
1540 if (managed_alloc)
1541 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1542 else
1543 dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1544 dest->dreg = ins->dreg;
1546 break;
1547 case OP_STRLEN:
1548 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1549 ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1550 break;
1551 default:
1552 break;
1555 g_assert (cfg->cbb == first_bb);
1557 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1558 /* Replace the original instruction with the new code sequence */
1560 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1561 first_bb->code = first_bb->last_ins = NULL;
1562 first_bb->in_count = first_bb->out_count = 0;
1563 cfg->cbb = first_bb;
1565 else
1566 prev = ins;
1570 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1574 typedef union {
1575 guint32 vali [2];
1576 gint64 vall;
1577 double vald;
1578 } DVal;
1580 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1583 * mono_decompose_soft_float:
1585 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1586 * similar to long support on 32 bit platforms. 32 bit float values require special
1587 * handling when used as locals, arguments, and in calls.
1588 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1590 void
1591 mono_decompose_soft_float (MonoCompile *cfg)
1593 MonoBasicBlock *bb, *first_bb;
1596 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1600 * Create a dummy bblock and emit code into it so we can use the normal
1601 * code generation macros.
1603 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1604 first_bb = cfg->cbb;
1606 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1607 MonoInst *ins;
1608 MonoInst *prev = NULL;
1609 gboolean restart;
1611 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1613 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1614 restart = TRUE;
1616 while (restart) {
1617 restart = FALSE;
1619 for (ins = bb->code; ins; ins = ins->next) {
1620 const char *spec = INS_INFO (ins->opcode);
1622 /* Most fp operations are handled automatically by opcode emulation */
1624 switch (ins->opcode) {
1625 case OP_R8CONST: {
1626 DVal d;
1627 d.vald = *(double*)ins->inst_p0;
1628 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1629 break;
1631 case OP_R4CONST: {
1632 DVal d;
1633 /* We load the r8 value */
1634 d.vald = *(float*)ins->inst_p0;
1635 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1636 break;
1638 case OP_FMOVE:
1639 ins->opcode = OP_LMOVE;
1640 break;
1641 case OP_FGETLOW32:
1642 ins->opcode = OP_MOVE;
1643 ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1644 break;
1645 case OP_FGETHIGH32:
1646 ins->opcode = OP_MOVE;
1647 ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1648 break;
1649 case OP_SETFRET: {
1650 int reg = ins->sreg1;
1652 ins->opcode = OP_SETLRET;
1653 ins->dreg = -1;
1654 ins->sreg1 = MONO_LVREG_LS (reg);
1655 ins->sreg2 = MONO_LVREG_MS (reg);
1656 break;
1658 case OP_LOADR8_MEMBASE:
1659 ins->opcode = OP_LOADI8_MEMBASE;
1660 break;
1661 case OP_STORER8_MEMBASE_REG:
1662 ins->opcode = OP_STOREI8_MEMBASE_REG;
1663 break;
1664 case OP_STORER4_MEMBASE_REG: {
1665 MonoInst *iargs [2];
1666 int addr_reg;
1668 /* Arg 1 is the double value */
1669 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1670 iargs [0]->dreg = ins->sreg1;
1672 /* Arg 2 is the address to store to */
1673 addr_reg = mono_alloc_preg (cfg);
1674 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1675 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1676 restart = TRUE;
1677 break;
1679 case OP_LOADR4_MEMBASE: {
1680 MonoInst *iargs [1];
1681 MonoInst *conv;
1682 int addr_reg;
1684 addr_reg = mono_alloc_preg (cfg);
1685 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1686 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1687 conv->dreg = ins->dreg;
1688 break;
1690 case OP_FCALL:
1691 case OP_FCALL_REG:
1692 case OP_FCALL_MEMBASE: {
1693 MonoCallInst *call = (MonoCallInst*)ins;
1694 if (call->signature->ret->type == MONO_TYPE_R4) {
1695 MonoCallInst *call2;
1696 MonoInst *iargs [1];
1697 MonoInst *conv;
1698 GSList *l;
1700 /* Convert the call into a call returning an int */
1701 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1702 memcpy (call2, call, sizeof (MonoCallInst));
1703 switch (ins->opcode) {
1704 case OP_FCALL:
1705 call2->inst.opcode = OP_CALL;
1706 break;
1707 case OP_FCALL_REG:
1708 call2->inst.opcode = OP_CALL_REG;
1709 break;
1710 case OP_FCALL_MEMBASE:
1711 call2->inst.opcode = OP_CALL_MEMBASE;
1712 break;
1713 default:
1714 g_assert_not_reached ();
1716 call2->inst.dreg = mono_alloc_ireg (cfg);
1717 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1719 /* Remap OUTARG_VT instructions referencing this call */
1720 for (l = call->outarg_vts; l; l = l->next)
1721 ((MonoInst*)(l->data))->inst_p0 = call2;
1723 /* FIXME: Optimize this */
1725 /* Emit an r4->r8 conversion */
1726 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1727 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1728 conv->dreg = ins->dreg;
1730 /* The call sequence might include fp ins */
1731 restart = TRUE;
1732 } else {
1733 switch (ins->opcode) {
1734 case OP_FCALL:
1735 ins->opcode = OP_LCALL;
1736 break;
1737 case OP_FCALL_REG:
1738 ins->opcode = OP_LCALL_REG;
1739 break;
1740 case OP_FCALL_MEMBASE:
1741 ins->opcode = OP_LCALL_MEMBASE;
1742 break;
1743 default:
1744 g_assert_not_reached ();
1747 break;
1749 case OP_FCOMPARE: {
1750 MonoJitICallInfo *info;
1751 MonoInst *iargs [2];
1752 MonoInst *call, *cmp, *br;
1754 /* Convert fcompare+fbcc to icall+icompare+beq */
1756 if (!ins->next) {
1757 /* The branch might be optimized away */
1758 NULLIFY_INS (ins);
1759 break;
1762 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1763 if (!info) {
1764 /* The branch might be optimized away */
1765 NULLIFY_INS (ins);
1766 break;
1769 /* Create dummy MonoInst's for the arguments */
1770 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1771 iargs [0]->dreg = ins->sreg1;
1772 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1773 iargs [1]->dreg = ins->sreg2;
1775 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1777 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1778 cmp->sreg1 = call->dreg;
1779 cmp->inst_imm = 0;
1780 MONO_ADD_INS (cfg->cbb, cmp);
1782 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1783 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1784 br->inst_true_bb = ins->next->inst_true_bb;
1785 br->inst_false_bb = ins->next->inst_false_bb;
1786 MONO_ADD_INS (cfg->cbb, br);
1788 /* The call sequence might include fp ins */
1789 restart = TRUE;
1791 /* Skip fbcc or fccc */
1792 NULLIFY_INS (ins->next);
1793 break;
1795 case OP_FCEQ:
1796 case OP_FCGT:
1797 case OP_FCGT_UN:
1798 case OP_FCLT:
1799 case OP_FCLT_UN: {
1800 MonoJitICallInfo *info;
1801 MonoInst *iargs [2];
1802 MonoInst *call;
1804 /* Convert fccc to icall+icompare+iceq */
1806 info = mono_find_jit_opcode_emulation (ins->opcode);
1807 g_assert (info);
1809 /* Create dummy MonoInst's for the arguments */
1810 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1811 iargs [0]->dreg = ins->sreg1;
1812 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1813 iargs [1]->dreg = ins->sreg2;
1815 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1817 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1818 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1820 /* The call sequence might include fp ins */
1821 restart = TRUE;
1822 break;
1824 case OP_CKFINITE: {
1825 MonoInst *iargs [2];
1826 MonoInst *call, *cmp;
1828 /* Convert to icall+icompare+cond_exc+move */
1830 /* Create dummy MonoInst's for the arguments */
1831 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1832 iargs [0]->dreg = ins->sreg1;
1834 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1836 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1837 cmp->sreg1 = call->dreg;
1838 cmp->inst_imm = 1;
1839 MONO_ADD_INS (cfg->cbb, cmp);
1841 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1843 /* Do the assignment if the value is finite */
1844 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1846 restart = TRUE;
1847 break;
1849 default:
1850 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1851 mono_print_ins (ins);
1852 g_assert_not_reached ();
1854 break;
1857 g_assert (cfg->cbb == first_bb);
1859 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1860 /* Replace the original instruction with the new code sequence */
1862 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1863 first_bb->code = first_bb->last_ins = NULL;
1864 first_bb->in_count = first_bb->out_count = 0;
1865 cfg->cbb = first_bb;
1867 else
1868 prev = ins;
1872 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1875 mono_decompose_long_opts (cfg);
1878 #endif
1880 void
1881 mono_local_emulate_ops (MonoCompile *cfg)
1883 MonoBasicBlock *bb;
1884 gboolean inlined_wrapper = FALSE;
1886 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1887 MonoInst *ins;
1889 MONO_BB_FOR_EACH_INS (bb, ins) {
1890 int op_noimm = mono_op_imm_to_op (ins->opcode);
1891 MonoJitICallInfo *info;
1894 * These opcodes don't have logical equivalence to the emulating native
1895 * function. They are decomposed in specific fashion in mono_decompose_soft_float.
1897 if (MONO_HAS_CUSTOM_EMULATION (ins))
1898 continue;
1901 * Emulation can't handle _IMM ops. If this is an imm opcode we need
1902 * to check whether its non-imm counterpart is emulated and, if so,
1903 * decompose it back to its non-imm counterpart.
1905 if (op_noimm != -1)
1906 info = mono_find_jit_opcode_emulation (op_noimm);
1907 else
1908 info = mono_find_jit_opcode_emulation (ins->opcode);
1910 if (info) {
1911 MonoInst **args;
1912 MonoInst *call;
1913 MonoBasicBlock *first_bb;
1915 /* Create dummy MonoInst's for the arguments */
1916 g_assert (!info->sig->hasthis);
1917 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1919 if (op_noimm != -1)
1920 mono_decompose_op_imm (cfg, bb, ins);
1922 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1923 if (info->sig->param_count > 0) {
1924 int sregs [MONO_MAX_SRC_REGS];
1925 int num_sregs, i;
1926 num_sregs = mono_inst_get_src_registers (ins, sregs);
1927 g_assert (num_sregs == info->sig->param_count);
1928 for (i = 0; i < num_sregs; ++i) {
1929 MONO_INST_NEW (cfg, args [i], OP_ARG);
1930 args [i]->dreg = sregs [i];
1934 /* We emit the call on a separate dummy basic block */
1935 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1936 first_bb = cfg->cbb;
1938 call = mono_emit_jit_icall_by_info (cfg, bb->real_offset, info, args);
1939 call->dreg = ins->dreg;
1941 /* Replace ins with the emitted code and do the necessary bb linking */
1942 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1943 MonoInst *saved_prev = ins->prev;
1945 mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1946 first_bb->code = first_bb->last_ins = NULL;
1947 first_bb->in_count = first_bb->out_count = 0;
1948 cfg->cbb = first_bb;
1950 /* ins is hanging, continue scanning the emitted code */
1951 ins = saved_prev;
1952 } else {
1953 g_error ("Failed to emit emulation code");
1955 inlined_wrapper = TRUE;
1961 * Avoid rerunning these passes by emitting directly the exception checkpoint
1962 * at IR level, instead of inlining the icall wrapper. FIXME
1964 if (inlined_wrapper) {
1965 if (!COMPILE_LLVM (cfg))
1966 mono_decompose_long_opts (cfg);
1967 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1968 mono_local_cprop (cfg);
1972 #else /* !DISABLE_JIT */
1974 MONO_EMPTY_SOURCE_FILE (decompose);
1976 #endif /* !DISABLE_JIT */