Pinvoke symbols according to the new moonlight naming convention.
[mono-project.git] / mono / mini / decompose.c
blob34e9ee967676146508274945390a747edc07d900
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 */
10 #include "mini.h"
11 #include "ir-emit.h"
12 #include "jit-icalls.h"
14 #include <mono/metadata/gc-internal.h>
16 #ifndef DISABLE_JIT
18 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
19 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
20 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
21 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
23 /* Decompose complex long opcodes on 64 bit machines or when using LLVM */
24 static gboolean
25 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
27 MonoInst *repl = NULL;
29 *repl_ins = NULL;
31 switch (ins->opcode) {
32 case OP_LCONV_TO_I4:
33 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
34 NULLIFY_INS (ins);
35 break;
36 case OP_LCONV_TO_I8:
37 case OP_LCONV_TO_I:
38 case OP_LCONV_TO_U8:
39 case OP_LCONV_TO_U:
40 ins->opcode = OP_MOVE;
41 break;
42 case OP_ICONV_TO_I8:
43 ins->opcode = OP_SEXT_I4;
44 break;
45 case OP_ICONV_TO_U8:
46 ins->opcode = OP_ZEXT_I4;
47 break;
48 case OP_LCONV_TO_U4:
49 /* Clean out the upper word */
50 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
51 NULLIFY_INS (ins);
52 break;
53 case OP_LADD_OVF:
54 if (COMPILE_LLVM (cfg))
55 break;
56 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
57 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
58 NULLIFY_INS (ins);
59 break;
60 case OP_LADD_OVF_UN:
61 if (COMPILE_LLVM (cfg))
62 break;
63 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
64 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
65 NULLIFY_INS (ins);
66 break;
67 #ifndef __mono_ppc64__
68 case OP_LSUB_OVF:
69 if (COMPILE_LLVM (cfg))
70 break;
71 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
72 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
73 NULLIFY_INS (ins);
74 break;
75 case OP_LSUB_OVF_UN:
76 if (COMPILE_LLVM (cfg))
77 break;
78 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
79 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
80 NULLIFY_INS (ins);
81 break;
82 #endif
84 case OP_ICONV_TO_OVF_I8:
85 case OP_ICONV_TO_OVF_I:
86 ins->opcode = OP_SEXT_I4;
87 break;
88 case OP_ICONV_TO_OVF_U8:
89 case OP_ICONV_TO_OVF_U:
90 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
91 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
92 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
93 NULLIFY_INS (ins);
94 break;
95 case OP_ICONV_TO_OVF_I8_UN:
96 case OP_ICONV_TO_OVF_U8_UN:
97 case OP_ICONV_TO_OVF_I_UN:
98 case OP_ICONV_TO_OVF_U_UN:
99 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
100 /* Clean out the upper word */
101 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
102 NULLIFY_INS (ins);
103 break;
104 case OP_LCONV_TO_OVF_I1:
105 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
106 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
107 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
108 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
109 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
110 NULLIFY_INS (ins);
111 break;
112 case OP_LCONV_TO_OVF_I1_UN:
113 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
114 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
115 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
116 NULLIFY_INS (ins);
117 break;
118 case OP_LCONV_TO_OVF_U1:
119 /* probe value to be within 0 to 255 */
120 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
121 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
122 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
123 NULLIFY_INS (ins);
124 break;
125 case OP_LCONV_TO_OVF_U1_UN:
126 /* probe value to be within 0 to 255 */
127 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
128 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
129 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
130 NULLIFY_INS (ins);
131 break;
132 case OP_LCONV_TO_OVF_I2:
133 /* Probe value to be within -32768 and 32767 */
134 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
135 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
136 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
137 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
138 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
139 NULLIFY_INS (ins);
140 break;
141 case OP_LCONV_TO_OVF_I2_UN:
142 /* Probe value to be within 0 and 32767 */
143 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
144 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
145 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
146 NULLIFY_INS (ins);
147 break;
148 case OP_LCONV_TO_OVF_U2:
149 /* Probe value to be within 0 and 65535 */
150 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
151 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
152 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
153 NULLIFY_INS (ins);
154 break;
155 case OP_LCONV_TO_OVF_U2_UN:
156 /* Probe value to be within 0 and 65535 */
157 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
158 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
159 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
160 NULLIFY_INS (ins);
161 break;
162 case OP_LCONV_TO_OVF_I4:
163 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
164 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
165 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
166 #if SIZEOF_REGISTER == 8
167 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
168 #else
169 g_assert (COMPILE_LLVM (cfg));
170 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
171 #endif
172 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
173 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
174 NULLIFY_INS (ins);
175 break;
176 case OP_LCONV_TO_OVF_I4_UN:
177 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
178 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
179 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
180 NULLIFY_INS (ins);
181 break;
182 case OP_LCONV_TO_OVF_U4:
183 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
184 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
185 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
186 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
187 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
188 NULLIFY_INS (ins);
189 break;
190 case OP_LCONV_TO_OVF_U4_UN:
191 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
192 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
193 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
194 NULLIFY_INS (ins);
195 break;
196 case OP_LCONV_TO_OVF_I:
197 case OP_LCONV_TO_OVF_U_UN:
198 case OP_LCONV_TO_OVF_U8_UN:
199 case OP_LCONV_TO_OVF_I8:
200 ins->opcode = OP_MOVE;
201 break;
202 case OP_LCONV_TO_OVF_I_UN:
203 case OP_LCONV_TO_OVF_I8_UN:
204 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
205 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
206 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
207 NULLIFY_INS (ins);
208 break;
209 case OP_LCONV_TO_OVF_U8:
210 case OP_LCONV_TO_OVF_U:
211 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
212 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
213 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
214 NULLIFY_INS (ins);
215 break;
216 default:
217 return FALSE;
220 *repl_ins = repl;
221 return TRUE;
225 * mono_decompose_opcode:
227 * Decompose complex opcodes into ones closer to opcodes supported by
228 * the given architecture.
229 * Returns a MonoInst which represents the result of the decomposition, and can
230 * be pushed on the IL stack. This is needed because the original instruction is
231 * nullified.
232 * Sets the cfg exception if an opcode is not supported.
234 MonoInst*
235 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
237 MonoInst *repl = NULL;
238 int type = ins->type;
239 int dreg = ins->dreg;
241 /* FIXME: Instead of = NOP, don't emit the original ins at all */
243 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
244 mono_arch_decompose_opts (cfg, ins);
245 #endif
248 * The code below assumes that we are called immediately after emitting
249 * ins. This means we can emit code using the normal code generation
250 * macros.
252 switch (ins->opcode) {
253 /* this doesn't make sense on ppc and other architectures */
254 #if !defined(MONO_ARCH_NO_IOV_CHECK)
255 case OP_IADD_OVF:
256 if (COMPILE_LLVM (cfg))
257 break;
258 ins->opcode = OP_IADDCC;
259 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
260 break;
261 case OP_IADD_OVF_UN:
262 if (COMPILE_LLVM (cfg))
263 break;
264 ins->opcode = OP_IADDCC;
265 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
266 break;
267 case OP_ISUB_OVF:
268 if (COMPILE_LLVM (cfg))
269 break;
270 ins->opcode = OP_ISUBCC;
271 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
272 break;
273 case OP_ISUB_OVF_UN:
274 if (COMPILE_LLVM (cfg))
275 break;
276 ins->opcode = OP_ISUBCC;
277 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
278 break;
279 #endif
280 case OP_ICONV_TO_OVF_I1:
281 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
282 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
283 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
284 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
285 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
286 NULLIFY_INS (ins);
287 break;
288 case OP_ICONV_TO_OVF_I1_UN:
289 /* probe values between 0 to 127 */
290 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
291 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
292 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
293 NULLIFY_INS (ins);
294 break;
295 case OP_ICONV_TO_OVF_U1:
296 case OP_ICONV_TO_OVF_U1_UN:
297 /* probe value to be within 0 to 255 */
298 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
299 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
300 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
301 NULLIFY_INS (ins);
302 break;
303 case OP_ICONV_TO_OVF_I2:
304 /* Probe value to be within -32768 and 32767 */
305 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
306 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
307 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
308 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
309 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
310 NULLIFY_INS (ins);
311 break;
312 case OP_ICONV_TO_OVF_I2_UN:
313 /* Convert uint value into short, value within 0 and 32767 */
314 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
315 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
316 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
317 NULLIFY_INS (ins);
318 break;
319 case OP_ICONV_TO_OVF_U2:
320 case OP_ICONV_TO_OVF_U2_UN:
321 /* Probe value to be within 0 and 65535 */
322 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
323 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
324 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
325 NULLIFY_INS (ins);
326 break;
327 case OP_ICONV_TO_OVF_U4:
328 case OP_ICONV_TO_OVF_I4_UN:
329 #if SIZEOF_REGISTER == 4
330 case OP_ICONV_TO_OVF_U:
331 case OP_ICONV_TO_OVF_I_UN:
332 #endif
333 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
334 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
335 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
336 NULLIFY_INS (ins);
337 break;
338 case OP_ICONV_TO_I4:
339 case OP_ICONV_TO_U4:
340 case OP_ICONV_TO_OVF_I4:
341 case OP_ICONV_TO_OVF_U4_UN:
342 #if SIZEOF_REGISTER == 4
343 case OP_ICONV_TO_OVF_I:
344 case OP_ICONV_TO_OVF_U_UN:
345 #endif
346 ins->opcode = OP_MOVE;
347 break;
348 case OP_ICONV_TO_I:
349 #if SIZEOF_REGISTER == 8
350 ins->opcode = OP_SEXT_I4;
351 #else
352 ins->opcode = OP_MOVE;
353 #endif
354 break;
355 case OP_ICONV_TO_U:
356 #if SIZEOF_REGISTER == 8
357 ins->opcode = OP_ZEXT_I4;
358 #else
359 ins->opcode = OP_MOVE;
360 #endif
361 break;
363 case OP_FCONV_TO_R8:
364 ins->opcode = OP_FMOVE;
365 break;
367 case OP_FCONV_TO_OVF_I1_UN:
368 case OP_FCONV_TO_OVF_I2_UN:
369 case OP_FCONV_TO_OVF_I4_UN:
370 case OP_FCONV_TO_OVF_I8_UN:
371 case OP_FCONV_TO_OVF_U1_UN:
372 case OP_FCONV_TO_OVF_U2_UN:
373 case OP_FCONV_TO_OVF_U4_UN:
374 case OP_FCONV_TO_OVF_U8_UN:
375 case OP_FCONV_TO_OVF_I_UN:
376 case OP_FCONV_TO_OVF_U_UN:
377 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
378 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
379 break;
381 default: {
382 MonoJitICallInfo *info;
384 #if SIZEOF_REGISTER == 8
385 if (decompose_long_opcode (cfg, ins, &repl))
386 break;
387 #else
388 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
389 break;
390 #endif
392 info = mono_find_jit_opcode_emulation (ins->opcode);
393 if (info) {
394 MonoInst **args;
395 MonoInst *call;
397 /* Create dummy MonoInst's for the arguments */
398 g_assert (!info->sig->hasthis);
399 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
401 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
402 if (info->sig->param_count > 0) {
403 int sregs [MONO_MAX_SRC_REGS];
404 int num_sregs, i;
405 num_sregs = mono_inst_get_src_registers (ins, sregs);
406 g_assert (num_sregs == info->sig->param_count);
407 for (i = 0; i < num_sregs; ++i) {
408 MONO_INST_NEW (cfg, args [i], OP_ARG);
409 args [i]->dreg = sregs [i];
413 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
414 call->dreg = ins->dreg;
416 NULLIFY_INS (ins);
418 break;
422 if (ins->opcode == OP_NOP) {
423 if (repl) {
424 repl->type = type;
425 return repl;
426 } else {
427 /* Use the last emitted instruction */
428 ins = cfg->cbb->last_ins;
429 g_assert (ins);
430 ins->type = type;
431 g_assert (ins->dreg == dreg);
432 return ins;
434 } else {
435 return ins;
439 #if SIZEOF_REGISTER == 4
440 static int lbr_decomp [][2] = {
441 {0, 0}, /* BEQ */
442 {OP_IBGT, OP_IBGE_UN}, /* BGE */
443 {OP_IBGT, OP_IBGT_UN}, /* BGT */
444 {OP_IBLT, OP_IBLE_UN}, /* BLE */
445 {OP_IBLT, OP_IBLT_UN}, /* BLT */
446 {0, 0}, /* BNE_UN */
447 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
448 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
449 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
450 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
453 static int lcset_decomp [][2] = {
454 {0, 0}, /* CEQ */
455 {OP_IBLT, OP_IBLE_UN}, /* CGT */
456 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
457 {OP_IBGT, OP_IBGE_UN}, /* CLT */
458 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
460 #endif
463 * mono_decompose_long_opts:
465 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
467 void
468 mono_decompose_long_opts (MonoCompile *cfg)
470 #if SIZEOF_REGISTER == 4
471 MonoBasicBlock *bb, *first_bb;
474 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
475 * needs to be able to handle long vregs.
478 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
481 * Create a dummy bblock and emit code into it so we can use the normal
482 * code generation macros.
484 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
485 first_bb = cfg->cbb;
487 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
488 MonoInst *tree = bb->code;
489 MonoInst *prev = NULL;
492 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
495 tree = bb->code;
496 cfg->cbb->code = cfg->cbb->last_ins = NULL;
498 while (tree) {
500 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
501 mono_arch_decompose_long_opts (cfg, tree);
502 #endif
504 switch (tree->opcode) {
505 case OP_I8CONST:
506 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
507 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
508 break;
509 case OP_LMOVE:
510 case OP_LCONV_TO_U8:
511 case OP_LCONV_TO_I8:
512 case OP_LCONV_TO_OVF_U8_UN:
513 case OP_LCONV_TO_OVF_I8:
514 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
515 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
516 break;
517 case OP_STOREI8_MEMBASE_REG:
518 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
519 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
520 break;
521 case OP_LOADI8_MEMBASE:
522 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
523 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
524 break;
526 case OP_ICONV_TO_I8: {
527 guint32 tmpreg = alloc_ireg (cfg);
529 /* branchless code:
530 * low = reg;
531 * tmp = low > -1 ? 1: 0;
532 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
534 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
535 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
536 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
537 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
538 break;
540 case OP_ICONV_TO_U8:
541 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
542 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
543 break;
544 case OP_ICONV_TO_OVF_I8:
545 /* a signed 32 bit num always fits in a signed 64 bit one */
546 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
547 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
548 break;
549 case OP_ICONV_TO_OVF_U8:
550 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
551 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
552 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
553 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
554 break;
555 case OP_ICONV_TO_OVF_I8_UN:
556 case OP_ICONV_TO_OVF_U8_UN:
557 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
558 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
559 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
560 break;
561 case OP_LCONV_TO_I1:
562 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
563 break;
564 case OP_LCONV_TO_U1:
565 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
566 break;
567 case OP_LCONV_TO_I2:
568 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
569 break;
570 case OP_LCONV_TO_U2:
571 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
572 break;
573 case OP_LCONV_TO_I4:
574 case OP_LCONV_TO_U4:
575 case OP_LCONV_TO_I:
576 case OP_LCONV_TO_U:
577 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
578 break;
579 case OP_LCONV_TO_R8:
580 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
581 break;
582 case OP_LCONV_TO_R4:
583 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
584 break;
585 case OP_LCONV_TO_R_UN:
586 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
587 break;
588 case OP_LCONV_TO_OVF_I1: {
589 MonoBasicBlock *is_negative, *end_label;
591 NEW_BBLOCK (cfg, is_negative);
592 NEW_BBLOCK (cfg, end_label);
594 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
595 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
596 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
597 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
599 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
600 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
602 /* Positive */
603 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
604 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
605 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
607 /* Negative */
608 MONO_START_BB (cfg, is_negative);
609 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
610 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
612 MONO_START_BB (cfg, end_label);
614 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
615 break;
617 case OP_LCONV_TO_OVF_I1_UN:
618 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
619 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
621 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
622 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
623 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
624 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
625 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
626 break;
627 case OP_LCONV_TO_OVF_U1:
628 case OP_LCONV_TO_OVF_U1_UN:
629 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
630 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
632 /* probe value to be within 0 to 255 */
633 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
634 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
635 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
636 break;
637 case OP_LCONV_TO_OVF_I2: {
638 MonoBasicBlock *is_negative, *end_label;
640 NEW_BBLOCK (cfg, is_negative);
641 NEW_BBLOCK (cfg, end_label);
643 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
644 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
645 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
646 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
648 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
649 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
651 /* Positive */
652 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
653 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
654 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
656 /* Negative */
657 MONO_START_BB (cfg, is_negative);
658 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
659 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
660 MONO_START_BB (cfg, end_label);
662 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
663 break;
665 case OP_LCONV_TO_OVF_I2_UN:
666 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
667 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
669 /* Probe value to be within -32768 and 32767 */
670 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
671 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
672 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
673 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
674 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
675 break;
676 case OP_LCONV_TO_OVF_U2:
677 case OP_LCONV_TO_OVF_U2_UN:
678 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
679 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
681 /* Probe value to be within 0 and 65535 */
682 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
683 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
684 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
685 break;
686 case OP_LCONV_TO_OVF_I4:
687 case OP_LCONV_TO_OVF_I:
688 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
689 break;
690 case OP_LCONV_TO_OVF_U4:
691 case OP_LCONV_TO_OVF_U:
692 case OP_LCONV_TO_OVF_U4_UN:
693 case OP_LCONV_TO_OVF_U_UN:
694 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
695 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
696 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
697 break;
698 case OP_LCONV_TO_OVF_I_UN:
699 case OP_LCONV_TO_OVF_I4_UN:
700 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
701 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
702 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
703 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
704 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
705 break;
706 case OP_LCONV_TO_OVF_U8:
707 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
708 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
710 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
711 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
712 break;
713 case OP_LCONV_TO_OVF_I8_UN:
714 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
715 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
717 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
718 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
719 break;
721 case OP_LADD:
722 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
723 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
724 break;
725 case OP_LSUB:
726 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
727 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
728 break;
730 case OP_LADD_OVF:
731 /* ADC sets the condition code */
732 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
733 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
734 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
735 break;
736 case OP_LADD_OVF_UN:
737 /* ADC sets the condition code */
738 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
739 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
740 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
741 break;
742 case OP_LSUB_OVF:
743 /* SBB sets the condition code */
744 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
745 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
746 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
747 break;
748 case OP_LSUB_OVF_UN:
749 /* SBB sets the condition code */
750 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
751 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
752 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
753 break;
754 case OP_LAND:
755 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
756 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
757 break;
758 case OP_LOR:
759 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
760 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
761 break;
762 case OP_LXOR:
763 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
764 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
765 break;
766 case OP_LNOT:
767 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
768 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
769 break;
770 case OP_LNEG:
771 /* Handled in mono_arch_decompose_long_opts () */
772 g_assert_not_reached ();
773 break;
774 case OP_LMUL:
775 /* Emulated */
776 /* FIXME: Add OP_BIGMUL optimization */
777 break;
779 case OP_LADD_IMM:
780 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
782 break;
783 case OP_LSUB_IMM:
784 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
785 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
786 break;
787 case OP_LAND_IMM:
788 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
789 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
790 break;
791 case OP_LOR_IMM:
792 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
793 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
794 break;
795 case OP_LXOR_IMM:
796 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
797 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
798 break;
799 case OP_LSHR_UN_IMM:
800 if (tree->inst_c1 == 32) {
802 /* The original code had this comment: */
803 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
804 * later apply the speedup to the left shift as well
805 * See BUG# 57957.
807 /* FIXME: Move this to the strength reduction pass */
808 /* just move the upper half to the lower and zero the high word */
809 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
810 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
812 break;
813 case OP_LSHL_IMM:
814 if (tree->inst_c1 == 32) {
815 /* just move the lower half to the upper and zero the lower word */
816 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
817 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
819 break;
821 case OP_LCOMPARE: {
822 MonoInst *next = tree->next;
824 g_assert (next);
826 switch (next->opcode) {
827 case OP_LBEQ:
828 case OP_LBNE_UN: {
829 int d1, d2;
831 /* Branchless version based on gcc code */
832 d1 = alloc_ireg (cfg);
833 d2 = alloc_ireg (cfg);
834 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
835 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
836 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
837 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
838 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
839 next->opcode = OP_NOP;
840 break;
842 case OP_LBGE:
843 case OP_LBGT:
844 case OP_LBLE:
845 case OP_LBLT:
846 case OP_LBGE_UN:
847 case OP_LBGT_UN:
848 case OP_LBLE_UN:
849 case OP_LBLT_UN:
850 /* Convert into three comparisons + branches */
851 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
852 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
853 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
854 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
855 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
856 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
857 next->opcode = OP_NOP;
858 break;
859 case OP_LCEQ: {
860 int d1, d2;
862 /* Branchless version based on gcc code */
863 d1 = alloc_ireg (cfg);
864 d2 = alloc_ireg (cfg);
865 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
866 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
867 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
869 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
870 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
871 next->opcode = OP_NOP;
872 break;
874 case OP_LCLT:
875 case OP_LCLT_UN:
876 case OP_LCGT:
877 case OP_LCGT_UN: {
878 MonoBasicBlock *set_to_0, *set_to_1;
880 NEW_BBLOCK (cfg, set_to_0);
881 NEW_BBLOCK (cfg, set_to_1);
883 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
884 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
885 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
886 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
887 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
888 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
889 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
890 MONO_START_BB (cfg, set_to_1);
891 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
892 MONO_START_BB (cfg, set_to_0);
893 next->opcode = OP_NOP;
894 break;
896 default:
897 g_assert_not_reached ();
899 break;
902 /* Not yet used, since lcompare is decomposed before local cprop */
903 case OP_LCOMPARE_IMM: {
904 MonoInst *next = tree->next;
905 guint32 low_imm = tree->inst_ls_word;
906 guint32 high_imm = tree->inst_ms_word;
907 int low_reg = tree->sreg1 + 1;
908 int high_reg = tree->sreg1 + 2;
910 g_assert (next);
912 switch (next->opcode) {
913 case OP_LBEQ:
914 case OP_LBNE_UN: {
915 int d1, d2;
917 /* Branchless version based on gcc code */
918 d1 = alloc_ireg (cfg);
919 d2 = alloc_ireg (cfg);
920 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
922 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
923 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
924 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
925 next->opcode = OP_NOP;
926 break;
929 case OP_LBGE:
930 case OP_LBGT:
931 case OP_LBLE:
932 case OP_LBLT:
933 case OP_LBGE_UN:
934 case OP_LBGT_UN:
935 case OP_LBLE_UN:
936 case OP_LBLT_UN:
937 /* Convert into three comparisons + branches */
938 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
939 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
940 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
941 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
942 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
943 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
944 next->opcode = OP_NOP;
945 break;
946 case OP_LCEQ: {
947 int d1, d2;
949 /* Branchless version based on gcc code */
950 d1 = alloc_ireg (cfg);
951 d2 = alloc_ireg (cfg);
952 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
953 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
954 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
956 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
957 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
958 next->opcode = OP_NOP;
959 break;
961 case OP_LCLT:
962 case OP_LCLT_UN:
963 case OP_LCGT:
964 case OP_LCGT_UN: {
965 MonoBasicBlock *set_to_0, *set_to_1;
967 NEW_BBLOCK (cfg, set_to_0);
968 NEW_BBLOCK (cfg, set_to_1);
970 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
971 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
972 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
973 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
974 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
975 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
976 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
977 MONO_START_BB (cfg, set_to_1);
978 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
979 MONO_START_BB (cfg, set_to_0);
980 next->opcode = OP_NOP;
981 break;
983 default:
984 g_assert_not_reached ();
986 break;
989 default:
990 break;
993 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
994 MonoInst *new_prev;
996 /* Replace the original instruction with the new code sequence */
998 /* Ignore the new value of prev */
999 new_prev = prev;
1000 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1002 /* Process the newly added ops again since they can be long ops too */
1003 if (prev)
1004 tree = prev->next;
1005 else
1006 tree = bb->code;
1008 first_bb->code = first_bb->last_ins = NULL;
1009 first_bb->in_count = first_bb->out_count = 0;
1010 cfg->cbb = first_bb;
1012 else {
1013 prev = tree;
1014 tree = tree->next;
1018 #endif
1021 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1022 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1027 * mono_decompose_vtype_opts:
1029 * Decompose valuetype opcodes.
1031 void
1032 mono_decompose_vtype_opts (MonoCompile *cfg)
1034 MonoBasicBlock *bb, *first_bb;
1037 * Using OP_V opcodes and decomposing them later have two main benefits:
1038 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1039 * everywhere.
1040 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1041 * enabling optimizations to work on vtypes too.
1042 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1043 * can be executed anytime. It should be executed as late as possible so vtype
1044 * opcodes can be optimized by the other passes.
1045 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1046 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1047 * var to 1.
1048 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1049 * when OP_VMOVE opcodes are decomposed.
1053 * Vregs have no associated type information, so we store the type of the vregs
1054 * in ins->klass.
1058 * Create a dummy bblock and emit code into it so we can use the normal
1059 * code generation macros.
1061 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1062 first_bb = cfg->cbb;
1064 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1065 MonoInst *ins;
1066 MonoInst *prev = NULL;
1067 MonoInst *src_var, *dest_var, *src, *dest;
1068 gboolean restart;
1069 int dreg;
1071 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1073 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1074 restart = TRUE;
1076 while (restart) {
1077 restart = FALSE;
1079 for (ins = bb->code; ins; ins = ins->next) {
1080 switch (ins->opcode) {
1081 case OP_VMOVE: {
1082 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1083 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1085 g_assert (ins->klass);
1087 if (!src_var)
1088 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1090 if (!dest_var)
1091 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1093 // FIXME:
1094 if (src_var->backend.is_pinvoke)
1095 dest_var->backend.is_pinvoke = 1;
1097 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1098 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1100 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1101 break;
1103 case OP_VZERO:
1104 g_assert (ins->klass);
1106 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1107 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1109 if (cfg->compute_gc_maps) {
1110 MonoInst *tmp;
1113 * Tell the GC map code that the vtype is considered live after
1114 * the initialization.
1116 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1117 tmp->inst_c1 = ins->dreg;
1118 MONO_ADD_INS (cfg->cbb, tmp);
1120 break;
1121 case OP_STOREV_MEMBASE: {
1122 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1124 if (!src_var) {
1125 g_assert (ins->klass);
1126 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1129 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1131 dreg = alloc_preg (cfg);
1132 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1133 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1134 break;
1136 case OP_LOADV_MEMBASE: {
1137 g_assert (ins->klass);
1139 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1140 // FIXME:
1141 if (!dest_var)
1142 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1144 dreg = alloc_preg (cfg);
1145 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1146 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1147 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1148 break;
1150 case OP_OUTARG_VT: {
1151 g_assert (ins->klass);
1153 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1154 if (!src_var)
1155 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1156 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1158 mono_arch_emit_outarg_vt (cfg, ins, src);
1160 /* This might be decomposed into other vtype opcodes */
1161 restart = TRUE;
1162 break;
1164 case OP_OUTARG_VTRETADDR: {
1165 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1167 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1168 if (!src_var)
1169 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1170 // FIXME: src_var->backend.is_pinvoke ?
1172 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1173 src->dreg = ins->dreg;
1174 break;
1176 case OP_VCALL:
1177 case OP_VCALL_REG:
1178 case OP_VCALL_MEMBASE: {
1179 MonoCallInst *call = (MonoCallInst*)ins;
1180 int size;
1182 if (call->vret_in_reg) {
1183 MonoCallInst *call2;
1185 /* Replace the vcall with an integer call */
1186 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1187 memcpy (call2, call, sizeof (MonoCallInst));
1188 switch (ins->opcode) {
1189 case OP_VCALL:
1190 call2->inst.opcode = OP_CALL;
1191 break;
1192 case OP_VCALL_REG:
1193 call2->inst.opcode = OP_CALL_REG;
1194 break;
1195 case OP_VCALL_MEMBASE:
1196 call2->inst.opcode = OP_CALL_MEMBASE;
1197 break;
1199 call2->inst.dreg = alloc_preg (cfg);
1200 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1202 /* Compute the vtype location */
1203 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1204 if (!dest_var)
1205 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1206 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1208 /* Save the result */
1209 if (dest_var->backend.is_pinvoke)
1210 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1211 else
1212 size = mono_type_size (dest_var->inst_vtype, NULL);
1213 switch (size) {
1214 case 1:
1215 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1216 break;
1217 case 2:
1218 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1219 break;
1220 case 4:
1221 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1222 break;
1223 case 8:
1224 #if SIZEOF_REGISTER == 4
1226 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1227 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1229 switch (call2->inst.opcode) {
1230 case OP_CALL:
1231 call2->inst.opcode = OP_LCALL;
1232 break;
1233 case OP_CALL_REG:
1234 call2->inst.opcode = OP_LCALL_REG;
1235 break;
1236 case OP_CALL_MEMBASE:
1237 call2->inst.opcode = OP_LCALL_MEMBASE;
1238 break;
1240 call2->inst.dreg = alloc_lreg (cfg);
1241 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1242 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1243 #else
1244 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1245 #endif
1246 break;
1247 default:
1248 /* This assumes the vtype is sizeof (gpointer) long */
1249 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1250 break;
1252 } else {
1253 switch (ins->opcode) {
1254 case OP_VCALL:
1255 ins->opcode = OP_VCALL2;
1256 break;
1257 case OP_VCALL_REG:
1258 ins->opcode = OP_VCALL2_REG;
1259 break;
1260 case OP_VCALL_MEMBASE:
1261 ins->opcode = OP_VCALL2_MEMBASE;
1262 break;
1264 ins->dreg = -1;
1266 break;
1268 default:
1269 break;
1272 g_assert (cfg->cbb == first_bb);
1274 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1275 /* Replace the original instruction with the new code sequence */
1277 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1278 first_bb->code = first_bb->last_ins = NULL;
1279 first_bb->in_count = first_bb->out_count = 0;
1280 cfg->cbb = first_bb;
1282 else
1283 prev = ins;
1287 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1291 inline static MonoInst *
1292 mono_get_domainvar (MonoCompile *cfg)
1294 if (!cfg->domainvar)
1295 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1296 return cfg->domainvar;
1300 * mono_decompose_array_access_opts:
1302 * Decompose array access opcodes.
1304 void
1305 mono_decompose_array_access_opts (MonoCompile *cfg)
1307 MonoBasicBlock *bb, *first_bb;
1310 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1311 * can be executed anytime. It should be run before decompose_long
1315 * Create a dummy bblock and emit code into it so we can use the normal
1316 * code generation macros.
1318 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1319 first_bb = cfg->cbb;
1321 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1322 MonoInst *ins;
1323 MonoInst *prev = NULL;
1324 MonoInst *dest;
1325 MonoInst *iargs [3];
1326 gboolean restart;
1328 if (!bb->has_array_access)
1329 continue;
1331 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1333 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1334 restart = TRUE;
1336 while (restart) {
1337 restart = FALSE;
1339 for (ins = bb->code; ins; ins = ins->next) {
1340 switch (ins->opcode) {
1341 case OP_LDLEN:
1342 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1343 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_CONSTANT_LOAD);
1344 MONO_ADD_INS (cfg->cbb, dest);
1345 break;
1346 case OP_BOUNDS_CHECK:
1347 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1348 if (COMPILE_LLVM (cfg))
1349 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1350 else
1351 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1352 break;
1353 case OP_NEWARR:
1354 if (cfg->opt & MONO_OPT_SHARED) {
1355 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1356 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1357 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1358 iargs [2]->dreg = ins->sreg1;
1360 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1361 dest->dreg = ins->dreg;
1362 } else {
1363 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1364 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1366 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1367 NEW_VTABLECONST (cfg, iargs [0], vtable);
1368 MONO_ADD_INS (cfg->cbb, iargs [0]);
1369 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1370 iargs [1]->dreg = ins->sreg1;
1372 if (managed_alloc)
1373 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1374 else
1375 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1376 dest->dreg = ins->dreg;
1378 break;
1379 case OP_STRLEN:
1380 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1381 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
1382 break;
1383 default:
1384 break;
1387 g_assert (cfg->cbb == first_bb);
1389 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1390 /* Replace the original instruction with the new code sequence */
1392 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1393 first_bb->code = first_bb->last_ins = NULL;
1394 first_bb->in_count = first_bb->out_count = 0;
1395 cfg->cbb = first_bb;
1397 else
1398 prev = ins;
1402 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1406 typedef union {
1407 guint32 vali [2];
1408 gint64 vall;
1409 double vald;
1410 } DVal;
1412 #ifdef MONO_ARCH_SOFT_FLOAT
1415 * mono_decompose_soft_float:
1417 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1418 * similar to long support on 32 bit platforms. 32 bit float values require special
1419 * handling when used as locals, arguments, and in calls.
1420 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1422 void
1423 mono_decompose_soft_float (MonoCompile *cfg)
1425 MonoBasicBlock *bb, *first_bb;
1428 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1432 * Create a dummy bblock and emit code into it so we can use the normal
1433 * code generation macros.
1435 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1436 first_bb = cfg->cbb;
1438 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1439 MonoInst *ins;
1440 MonoInst *prev = NULL;
1441 gboolean restart;
1443 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1445 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1446 restart = TRUE;
1448 while (restart) {
1449 restart = FALSE;
1451 for (ins = bb->code; ins; ins = ins->next) {
1452 const char *spec = INS_INFO (ins->opcode);
1454 /* Most fp operations are handled automatically by opcode emulation */
1456 switch (ins->opcode) {
1457 case OP_R8CONST: {
1458 DVal d;
1459 d.vald = *(double*)ins->inst_p0;
1460 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1461 break;
1463 case OP_R4CONST: {
1464 DVal d;
1465 /* We load the r8 value */
1466 d.vald = *(float*)ins->inst_p0;
1467 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1468 break;
1470 case OP_FMOVE:
1471 ins->opcode = OP_LMOVE;
1472 break;
1473 case OP_FGETLOW32:
1474 ins->opcode = OP_MOVE;
1475 ins->sreg1 = ins->sreg1 + 1;
1476 break;
1477 case OP_FGETHIGH32:
1478 ins->opcode = OP_MOVE;
1479 ins->sreg1 = ins->sreg1 + 2;
1480 break;
1481 case OP_SETFRET: {
1482 int reg = ins->sreg1;
1484 ins->opcode = OP_SETLRET;
1485 ins->dreg = -1;
1486 ins->sreg1 = reg + 1;
1487 ins->sreg2 = reg + 2;
1488 break;
1490 case OP_LOADR8_MEMBASE:
1491 ins->opcode = OP_LOADI8_MEMBASE;
1492 break;
1493 case OP_STORER8_MEMBASE_REG:
1494 ins->opcode = OP_STOREI8_MEMBASE_REG;
1495 break;
1496 case OP_STORER4_MEMBASE_REG: {
1497 MonoInst *iargs [2];
1498 int addr_reg;
1500 /* Arg 1 is the double value */
1501 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1502 iargs [0]->dreg = ins->sreg1;
1504 /* Arg 2 is the address to store to */
1505 addr_reg = mono_alloc_preg (cfg);
1506 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1507 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1508 restart = TRUE;
1509 break;
1511 case OP_LOADR4_MEMBASE: {
1512 MonoInst *iargs [1];
1513 MonoInst *conv;
1514 int addr_reg;
1516 addr_reg = mono_alloc_preg (cfg);
1517 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1518 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1519 conv->dreg = ins->dreg;
1520 break;
1522 case OP_FCALL:
1523 case OP_FCALL_REG:
1524 case OP_FCALL_MEMBASE: {
1525 MonoCallInst *call = (MonoCallInst*)ins;
1526 if (call->signature->ret->type == MONO_TYPE_R4) {
1527 MonoCallInst *call2;
1528 MonoInst *iargs [1];
1529 MonoInst *conv;
1530 GSList *l;
1532 /* Convert the call into a call returning an int */
1533 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1534 memcpy (call2, call, sizeof (MonoCallInst));
1535 switch (ins->opcode) {
1536 case OP_FCALL:
1537 call2->inst.opcode = OP_CALL;
1538 break;
1539 case OP_FCALL_REG:
1540 call2->inst.opcode = OP_CALL_REG;
1541 break;
1542 case OP_FCALL_MEMBASE:
1543 call2->inst.opcode = OP_CALL_MEMBASE;
1544 break;
1545 default:
1546 g_assert_not_reached ();
1548 call2->inst.dreg = mono_alloc_ireg (cfg);
1549 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1551 /* Remap OUTARG_VT instructions referencing this call */
1552 for (l = call->outarg_vts; l; l = l->next)
1553 ((MonoInst*)(l->data))->inst_p0 = call2;
1555 /* FIXME: Optimize this */
1557 /* Emit an r4->r8 conversion */
1558 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1559 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1560 conv->dreg = ins->dreg;
1562 /* The call sequence might include fp ins */
1563 restart = TRUE;
1564 } else {
1565 switch (ins->opcode) {
1566 case OP_FCALL:
1567 ins->opcode = OP_LCALL;
1568 break;
1569 case OP_FCALL_REG:
1570 ins->opcode = OP_LCALL_REG;
1571 break;
1572 case OP_FCALL_MEMBASE:
1573 ins->opcode = OP_LCALL_MEMBASE;
1574 break;
1575 default:
1576 g_assert_not_reached ();
1579 break;
1581 case OP_FCOMPARE: {
1582 MonoJitICallInfo *info;
1583 MonoInst *iargs [2];
1584 MonoInst *call, *cmp, *br;
1586 /* Convert fcompare+fbcc to icall+icompare+beq */
1588 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1589 g_assert (info);
1591 /* Create dummy MonoInst's for the arguments */
1592 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1593 iargs [0]->dreg = ins->sreg1;
1594 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1595 iargs [1]->dreg = ins->sreg2;
1597 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1599 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1600 cmp->sreg1 = call->dreg;
1601 cmp->inst_imm = 0;
1602 MONO_ADD_INS (cfg->cbb, cmp);
1604 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1605 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1606 br->inst_true_bb = ins->next->inst_true_bb;
1607 br->inst_false_bb = ins->next->inst_false_bb;
1608 MONO_ADD_INS (cfg->cbb, br);
1610 /* The call sequence might include fp ins */
1611 restart = TRUE;
1613 /* Skip fbcc or fccc */
1614 NULLIFY_INS (ins->next);
1615 break;
1617 case OP_FCEQ:
1618 case OP_FCGT:
1619 case OP_FCGT_UN:
1620 case OP_FCLT:
1621 case OP_FCLT_UN: {
1622 MonoJitICallInfo *info;
1623 MonoInst *iargs [2];
1624 MonoInst *call;
1626 /* Convert fccc to icall+icompare+iceq */
1628 info = mono_find_jit_opcode_emulation (ins->opcode);
1629 g_assert (info);
1631 /* Create dummy MonoInst's for the arguments */
1632 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1633 iargs [0]->dreg = ins->sreg1;
1634 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1635 iargs [1]->dreg = ins->sreg2;
1637 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1639 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1640 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1642 /* The call sequence might include fp ins */
1643 restart = TRUE;
1644 break;
1646 case OP_CKFINITE: {
1647 MonoInst *iargs [2];
1648 MonoInst *call, *cmp;
1650 /* Convert to icall+icompare+cond_exc+move */
1652 /* Create dummy MonoInst's for the arguments */
1653 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1654 iargs [0]->dreg = ins->sreg1;
1656 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1658 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1659 cmp->sreg1 = call->dreg;
1660 cmp->inst_imm = 1;
1661 MONO_ADD_INS (cfg->cbb, cmp);
1663 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1665 /* Do the assignment if the value is finite */
1666 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1668 restart = TRUE;
1669 break;
1671 default:
1672 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1673 mono_print_ins (ins);
1674 g_assert_not_reached ();
1676 break;
1679 g_assert (cfg->cbb == first_bb);
1681 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1682 /* Replace the original instruction with the new code sequence */
1684 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1685 first_bb->code = first_bb->last_ins = NULL;
1686 first_bb->in_count = first_bb->out_count = 0;
1687 cfg->cbb = first_bb;
1689 else
1690 prev = ins;
1694 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1697 mono_decompose_long_opts (cfg);
1700 #endif
1702 #endif /* DISABLE_JIT */