update rx (mobile builds).
[mono-project.git] / mono / mini / decompose.c
blob5398896b18365dd1ec42e03f947df14c29889b35
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 */
11 #include "mini.h"
12 #include "ir-emit.h"
13 #include "jit-icalls.h"
15 #include <mono/metadata/gc-internal.h>
17 #ifndef DISABLE_JIT
19 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
20 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
21 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
22 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
24 /* Decompose complex long opcodes on 64 bit machines or when using LLVM */
25 static gboolean
26 decompose_long_opcode (MonoCompile *cfg, MonoInst *ins, MonoInst **repl_ins)
28 MonoInst *repl = NULL;
30 *repl_ins = NULL;
32 switch (ins->opcode) {
33 case OP_LCONV_TO_I4:
34 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
35 NULLIFY_INS (ins);
36 break;
37 case OP_LCONV_TO_I8:
38 case OP_LCONV_TO_I:
39 case OP_LCONV_TO_U8:
40 case OP_LCONV_TO_U:
41 ins->opcode = OP_MOVE;
42 break;
43 case OP_ICONV_TO_I8:
44 ins->opcode = OP_SEXT_I4;
45 break;
46 case OP_ICONV_TO_U8:
47 ins->opcode = OP_ZEXT_I4;
48 break;
49 case OP_LCONV_TO_U4:
50 /* Clean out the upper word */
51 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
52 NULLIFY_INS (ins);
53 break;
54 case OP_LADD_OVF:
55 if (COMPILE_LLVM (cfg))
56 break;
57 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
58 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
59 NULLIFY_INS (ins);
60 break;
61 case OP_LADD_OVF_UN:
62 if (COMPILE_LLVM (cfg))
63 break;
64 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
65 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
66 NULLIFY_INS (ins);
67 break;
68 #ifndef __mono_ppc64__
69 case OP_LSUB_OVF:
70 if (COMPILE_LLVM (cfg))
71 break;
72 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
73 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
74 NULLIFY_INS (ins);
75 break;
76 case OP_LSUB_OVF_UN:
77 if (COMPILE_LLVM (cfg))
78 break;
79 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
80 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
81 NULLIFY_INS (ins);
82 break;
83 #endif
85 case OP_ICONV_TO_OVF_I8:
86 case OP_ICONV_TO_OVF_I:
87 ins->opcode = OP_SEXT_I4;
88 break;
89 case OP_ICONV_TO_OVF_U8:
90 case OP_ICONV_TO_OVF_U:
91 MONO_EMIT_NEW_LCOMPARE_IMM (cfg,ins->sreg1, 0);
92 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
93 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
94 NULLIFY_INS (ins);
95 break;
96 case OP_ICONV_TO_OVF_I8_UN:
97 case OP_ICONV_TO_OVF_U8_UN:
98 case OP_ICONV_TO_OVF_I_UN:
99 case OP_ICONV_TO_OVF_U_UN:
100 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
101 /* Clean out the upper word */
102 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
103 NULLIFY_INS (ins);
104 break;
105 case OP_LCONV_TO_OVF_I1:
106 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
107 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
108 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -128);
109 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
110 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
111 NULLIFY_INS (ins);
112 break;
113 case OP_LCONV_TO_OVF_I1_UN:
114 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 127);
115 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
116 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
117 NULLIFY_INS (ins);
118 break;
119 case OP_LCONV_TO_OVF_U1:
120 /* probe value to be within 0 to 255 */
121 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
122 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
123 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
124 NULLIFY_INS (ins);
125 break;
126 case OP_LCONV_TO_OVF_U1_UN:
127 /* probe value to be within 0 to 255 */
128 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 255);
129 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
130 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
131 NULLIFY_INS (ins);
132 break;
133 case OP_LCONV_TO_OVF_I2:
134 /* Probe value to be within -32768 and 32767 */
135 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
136 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
137 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -32768);
138 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
139 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
140 NULLIFY_INS (ins);
141 break;
142 case OP_LCONV_TO_OVF_I2_UN:
143 /* Probe value to be within 0 and 32767 */
144 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 32767);
145 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
146 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
147 NULLIFY_INS (ins);
148 break;
149 case OP_LCONV_TO_OVF_U2:
150 /* Probe value to be within 0 and 65535 */
151 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
152 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
153 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
154 NULLIFY_INS (ins);
155 break;
156 case OP_LCONV_TO_OVF_U2_UN:
157 /* Probe value to be within 0 and 65535 */
158 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffff);
159 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
160 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
161 NULLIFY_INS (ins);
162 break;
163 case OP_LCONV_TO_OVF_I4:
164 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
165 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
166 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
167 #if SIZEOF_REGISTER == 8
168 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
169 #else
170 g_assert (COMPILE_LLVM (cfg));
171 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, -2147483648LL);
172 #endif
173 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
174 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
175 NULLIFY_INS (ins);
176 break;
177 case OP_LCONV_TO_OVF_I4_UN:
178 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
179 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
180 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
181 NULLIFY_INS (ins);
182 break;
183 case OP_LCONV_TO_OVF_U4:
184 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
185 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
186 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
187 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
188 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
189 NULLIFY_INS (ins);
190 break;
191 case OP_LCONV_TO_OVF_U4_UN:
192 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
193 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
194 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
195 NULLIFY_INS (ins);
196 break;
197 case OP_LCONV_TO_OVF_I:
198 case OP_LCONV_TO_OVF_U_UN:
199 case OP_LCONV_TO_OVF_U8_UN:
200 case OP_LCONV_TO_OVF_I8:
201 ins->opcode = OP_MOVE;
202 break;
203 case OP_LCONV_TO_OVF_I_UN:
204 case OP_LCONV_TO_OVF_I8_UN:
205 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
206 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
207 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
208 NULLIFY_INS (ins);
209 break;
210 case OP_LCONV_TO_OVF_U8:
211 case OP_LCONV_TO_OVF_U:
212 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg1, 0);
213 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
214 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
215 NULLIFY_INS (ins);
216 break;
217 default:
218 return FALSE;
221 *repl_ins = repl;
222 return TRUE;
226 * mono_decompose_opcode:
228 * Decompose complex opcodes into ones closer to opcodes supported by
229 * the given architecture.
230 * Returns a MonoInst which represents the result of the decomposition, and can
231 * be pushed on the IL stack. This is needed because the original instruction is
232 * nullified.
233 * Sets the cfg exception if an opcode is not supported.
235 MonoInst*
236 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
238 MonoInst *repl = NULL;
239 int type = ins->type;
240 int dreg = ins->dreg;
242 /* FIXME: Instead of = NOP, don't emit the original ins at all */
244 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
245 mono_arch_decompose_opts (cfg, ins);
246 #endif
249 * The code below assumes that we are called immediately after emitting
250 * ins. This means we can emit code using the normal code generation
251 * macros.
253 switch (ins->opcode) {
254 /* this doesn't make sense on ppc and other architectures */
255 #if !defined(MONO_ARCH_NO_IOV_CHECK)
256 case OP_IADD_OVF:
257 if (COMPILE_LLVM (cfg))
258 break;
259 ins->opcode = OP_IADDCC;
260 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
261 break;
262 case OP_IADD_OVF_UN:
263 if (COMPILE_LLVM (cfg))
264 break;
265 ins->opcode = OP_IADDCC;
266 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
267 break;
268 case OP_ISUB_OVF:
269 if (COMPILE_LLVM (cfg))
270 break;
271 ins->opcode = OP_ISUBCC;
272 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
273 break;
274 case OP_ISUB_OVF_UN:
275 if (COMPILE_LLVM (cfg))
276 break;
277 ins->opcode = OP_ISUBCC;
278 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
279 break;
280 #endif
281 case OP_ICONV_TO_OVF_I1:
282 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
283 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
284 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
285 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
286 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
287 NULLIFY_INS (ins);
288 break;
289 case OP_ICONV_TO_OVF_I1_UN:
290 /* probe values between 0 to 127 */
291 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
292 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
293 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
294 NULLIFY_INS (ins);
295 break;
296 case OP_ICONV_TO_OVF_U1:
297 case OP_ICONV_TO_OVF_U1_UN:
298 /* probe value to be within 0 to 255 */
299 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
300 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
301 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
302 NULLIFY_INS (ins);
303 break;
304 case OP_ICONV_TO_OVF_I2:
305 /* Probe value to be within -32768 and 32767 */
306 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
307 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
308 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
309 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
310 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
311 NULLIFY_INS (ins);
312 break;
313 case OP_ICONV_TO_OVF_I2_UN:
314 /* Convert uint value into short, value within 0 and 32767 */
315 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
316 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
317 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
318 NULLIFY_INS (ins);
319 break;
320 case OP_ICONV_TO_OVF_U2:
321 case OP_ICONV_TO_OVF_U2_UN:
322 /* Probe value to be within 0 and 65535 */
323 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
324 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
325 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
326 NULLIFY_INS (ins);
327 break;
328 case OP_ICONV_TO_OVF_U4:
329 case OP_ICONV_TO_OVF_I4_UN:
330 #if SIZEOF_REGISTER == 4
331 case OP_ICONV_TO_OVF_U:
332 case OP_ICONV_TO_OVF_I_UN:
333 #endif
334 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
335 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
336 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
337 NULLIFY_INS (ins);
338 break;
339 case OP_ICONV_TO_I4:
340 case OP_ICONV_TO_U4:
341 case OP_ICONV_TO_OVF_I4:
342 case OP_ICONV_TO_OVF_U4_UN:
343 #if SIZEOF_REGISTER == 4
344 case OP_ICONV_TO_OVF_I:
345 case OP_ICONV_TO_OVF_U_UN:
346 #endif
347 ins->opcode = OP_MOVE;
348 break;
349 case OP_ICONV_TO_I:
350 #if SIZEOF_REGISTER == 8
351 ins->opcode = OP_SEXT_I4;
352 #else
353 ins->opcode = OP_MOVE;
354 #endif
355 break;
356 case OP_ICONV_TO_U:
357 #if SIZEOF_REGISTER == 8
358 ins->opcode = OP_ZEXT_I4;
359 #else
360 ins->opcode = OP_MOVE;
361 #endif
362 break;
364 case OP_FCONV_TO_R8:
365 ins->opcode = OP_FMOVE;
366 break;
368 case OP_FCONV_TO_OVF_I1_UN:
369 case OP_FCONV_TO_OVF_I2_UN:
370 case OP_FCONV_TO_OVF_I4_UN:
371 case OP_FCONV_TO_OVF_I8_UN:
372 case OP_FCONV_TO_OVF_U1_UN:
373 case OP_FCONV_TO_OVF_U2_UN:
374 case OP_FCONV_TO_OVF_U4_UN:
375 case OP_FCONV_TO_OVF_U8_UN:
376 case OP_FCONV_TO_OVF_I_UN:
377 case OP_FCONV_TO_OVF_U_UN:
378 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
379 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
380 break;
382 default: {
383 MonoJitICallInfo *info;
385 #if SIZEOF_REGISTER == 8
386 if (decompose_long_opcode (cfg, ins, &repl))
387 break;
388 #else
389 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
390 break;
391 #endif
393 info = mono_find_jit_opcode_emulation (ins->opcode);
394 if (info) {
395 MonoInst **args;
396 MonoInst *call;
398 /* Create dummy MonoInst's for the arguments */
399 g_assert (!info->sig->hasthis);
400 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
402 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
403 if (info->sig->param_count > 0) {
404 int sregs [MONO_MAX_SRC_REGS];
405 int num_sregs, i;
406 num_sregs = mono_inst_get_src_registers (ins, sregs);
407 g_assert (num_sregs == info->sig->param_count);
408 for (i = 0; i < num_sregs; ++i) {
409 MONO_INST_NEW (cfg, args [i], OP_ARG);
410 args [i]->dreg = sregs [i];
414 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
415 call->dreg = ins->dreg;
417 NULLIFY_INS (ins);
419 break;
423 if (ins->opcode == OP_NOP) {
424 if (repl) {
425 repl->type = type;
426 return repl;
427 } else {
428 /* Use the last emitted instruction */
429 ins = cfg->cbb->last_ins;
430 g_assert (ins);
431 ins->type = type;
432 g_assert (ins->dreg == dreg);
433 return ins;
435 } else {
436 return ins;
440 #if SIZEOF_REGISTER == 4
441 static int lbr_decomp [][2] = {
442 {0, 0}, /* BEQ */
443 {OP_IBGT, OP_IBGE_UN}, /* BGE */
444 {OP_IBGT, OP_IBGT_UN}, /* BGT */
445 {OP_IBLT, OP_IBLE_UN}, /* BLE */
446 {OP_IBLT, OP_IBLT_UN}, /* BLT */
447 {0, 0}, /* BNE_UN */
448 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
449 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
450 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
451 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
454 static int lcset_decomp [][2] = {
455 {0, 0}, /* CEQ */
456 {OP_IBLT, OP_IBLE_UN}, /* CGT */
457 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
458 {OP_IBGT, OP_IBGE_UN}, /* CLT */
459 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
461 #endif
464 * mono_decompose_long_opts:
466 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
468 void
469 mono_decompose_long_opts (MonoCompile *cfg)
471 #if SIZEOF_REGISTER == 4
472 MonoBasicBlock *bb, *first_bb;
475 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
476 * needs to be able to handle long vregs.
479 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
482 * Create a dummy bblock and emit code into it so we can use the normal
483 * code generation macros.
485 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
486 first_bb = cfg->cbb;
488 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
489 MonoInst *tree = bb->code;
490 MonoInst *prev = NULL;
493 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
496 tree = bb->code;
497 cfg->cbb->code = cfg->cbb->last_ins = NULL;
499 while (tree) {
501 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
502 mono_arch_decompose_long_opts (cfg, tree);
503 #endif
505 switch (tree->opcode) {
506 case OP_I8CONST:
507 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
508 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
509 break;
510 case OP_LMOVE:
511 case OP_LCONV_TO_U8:
512 case OP_LCONV_TO_I8:
513 case OP_LCONV_TO_OVF_U8_UN:
514 case OP_LCONV_TO_OVF_I8:
515 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
516 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
517 break;
518 case OP_STOREI8_MEMBASE_REG:
519 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
520 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
521 break;
522 case OP_LOADI8_MEMBASE:
523 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
524 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
525 break;
527 case OP_ICONV_TO_I8: {
528 guint32 tmpreg = alloc_ireg (cfg);
530 /* branchless code:
531 * low = reg;
532 * tmp = low > -1 ? 1: 0;
533 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
535 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
536 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
537 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
538 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
539 break;
541 case OP_ICONV_TO_U8:
542 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
543 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
544 break;
545 case OP_ICONV_TO_OVF_I8:
546 /* a signed 32 bit num always fits in a signed 64 bit one */
547 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
548 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
549 break;
550 case OP_ICONV_TO_OVF_U8:
551 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
552 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
553 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
554 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
555 break;
556 case OP_ICONV_TO_OVF_I8_UN:
557 case OP_ICONV_TO_OVF_U8_UN:
558 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
559 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
560 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
561 break;
562 case OP_LCONV_TO_I1:
563 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
564 break;
565 case OP_LCONV_TO_U1:
566 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
567 break;
568 case OP_LCONV_TO_I2:
569 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
570 break;
571 case OP_LCONV_TO_U2:
572 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
573 break;
574 case OP_LCONV_TO_I4:
575 case OP_LCONV_TO_U4:
576 case OP_LCONV_TO_I:
577 case OP_LCONV_TO_U:
578 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
579 break;
580 case OP_LCONV_TO_R8:
581 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
582 break;
583 case OP_LCONV_TO_R4:
584 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
585 break;
586 case OP_LCONV_TO_R_UN:
587 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
588 break;
589 case OP_LCONV_TO_OVF_I1: {
590 MonoBasicBlock *is_negative, *end_label;
592 NEW_BBLOCK (cfg, is_negative);
593 NEW_BBLOCK (cfg, end_label);
595 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
596 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
597 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
598 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
600 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
601 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
603 /* Positive */
604 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
605 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
606 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
608 /* Negative */
609 MONO_START_BB (cfg, is_negative);
610 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
611 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
613 MONO_START_BB (cfg, end_label);
615 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
616 break;
618 case OP_LCONV_TO_OVF_I1_UN:
619 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
620 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
622 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
623 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
624 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
625 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
626 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
627 break;
628 case OP_LCONV_TO_OVF_U1:
629 case OP_LCONV_TO_OVF_U1_UN:
630 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
631 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
633 /* probe value to be within 0 to 255 */
634 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
635 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
636 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
637 break;
638 case OP_LCONV_TO_OVF_I2: {
639 MonoBasicBlock *is_negative, *end_label;
641 NEW_BBLOCK (cfg, is_negative);
642 NEW_BBLOCK (cfg, end_label);
644 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
645 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
646 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
647 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
649 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
650 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
652 /* Positive */
653 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
654 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
655 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
657 /* Negative */
658 MONO_START_BB (cfg, is_negative);
659 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
660 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
661 MONO_START_BB (cfg, end_label);
663 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
664 break;
666 case OP_LCONV_TO_OVF_I2_UN:
667 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
668 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
670 /* Probe value to be within -32768 and 32767 */
671 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
672 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
673 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
674 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
675 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
676 break;
677 case OP_LCONV_TO_OVF_U2:
678 case OP_LCONV_TO_OVF_U2_UN:
679 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
680 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
682 /* Probe value to be within 0 and 65535 */
683 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
684 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
685 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
686 break;
687 case OP_LCONV_TO_OVF_I4:
688 case OP_LCONV_TO_OVF_I:
689 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
690 break;
691 case OP_LCONV_TO_OVF_U4:
692 case OP_LCONV_TO_OVF_U:
693 case OP_LCONV_TO_OVF_U4_UN:
694 case OP_LCONV_TO_OVF_U_UN:
695 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
696 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
697 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
698 break;
699 case OP_LCONV_TO_OVF_I_UN:
700 case OP_LCONV_TO_OVF_I4_UN:
701 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
702 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
703 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
704 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
705 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
706 break;
707 case OP_LCONV_TO_OVF_U8:
708 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
709 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
711 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
712 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
713 break;
714 case OP_LCONV_TO_OVF_I8_UN:
715 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
716 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
718 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
719 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
720 break;
722 case OP_LADD:
723 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
724 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
725 break;
726 case OP_LSUB:
727 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
728 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
729 break;
731 case OP_LADD_OVF:
732 /* ADC sets the condition code */
733 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
734 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
735 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
736 break;
737 case OP_LADD_OVF_UN:
738 /* ADC sets the condition code */
739 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
740 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
741 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
742 break;
743 case OP_LSUB_OVF:
744 /* SBB sets the condition code */
745 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
746 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
747 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
748 break;
749 case OP_LSUB_OVF_UN:
750 /* SBB sets the condition code */
751 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
752 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
753 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
754 break;
755 case OP_LAND:
756 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
757 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
758 break;
759 case OP_LOR:
760 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
761 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
762 break;
763 case OP_LXOR:
764 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
765 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
766 break;
767 case OP_LNOT:
768 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
769 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
770 break;
771 case OP_LNEG:
772 /* Handled in mono_arch_decompose_long_opts () */
773 g_assert_not_reached ();
774 break;
775 case OP_LMUL:
776 /* Emulated */
777 /* FIXME: Add OP_BIGMUL optimization */
778 break;
780 case OP_LADD_IMM:
781 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
782 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
783 break;
784 case OP_LSUB_IMM:
785 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
786 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
787 break;
788 case OP_LAND_IMM:
789 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
790 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
791 break;
792 case OP_LOR_IMM:
793 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
794 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
795 break;
796 case OP_LXOR_IMM:
797 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
798 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
799 break;
800 case OP_LSHR_UN_IMM:
801 if (tree->inst_c1 == 32) {
803 /* The original code had this comment: */
804 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
805 * later apply the speedup to the left shift as well
806 * See BUG# 57957.
808 /* FIXME: Move this to the strength reduction pass */
809 /* just move the upper half to the lower and zero the high word */
810 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
811 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
813 break;
814 case OP_LSHL_IMM:
815 if (tree->inst_c1 == 32) {
816 /* just move the lower half to the upper and zero the lower word */
817 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
818 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
820 break;
822 case OP_LCOMPARE: {
823 MonoInst *next = tree->next;
825 g_assert (next);
827 switch (next->opcode) {
828 case OP_LBEQ:
829 case OP_LBNE_UN: {
830 int d1, d2;
832 /* Branchless version based on gcc code */
833 d1 = alloc_ireg (cfg);
834 d2 = alloc_ireg (cfg);
835 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
836 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
837 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
838 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
839 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
840 next->opcode = OP_NOP;
841 break;
843 case OP_LBGE:
844 case OP_LBGT:
845 case OP_LBLE:
846 case OP_LBLT:
847 case OP_LBGE_UN:
848 case OP_LBGT_UN:
849 case OP_LBLE_UN:
850 case OP_LBLT_UN:
851 /* Convert into three comparisons + branches */
852 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
853 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
854 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
855 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
856 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
857 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
858 next->opcode = OP_NOP;
859 break;
860 case OP_LCEQ: {
861 int d1, d2;
863 /* Branchless version based on gcc code */
864 d1 = alloc_ireg (cfg);
865 d2 = alloc_ireg (cfg);
866 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
867 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
868 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
870 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
871 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
872 next->opcode = OP_NOP;
873 break;
875 case OP_LCLT:
876 case OP_LCLT_UN:
877 case OP_LCGT:
878 case OP_LCGT_UN: {
879 MonoBasicBlock *set_to_0, *set_to_1;
881 NEW_BBLOCK (cfg, set_to_0);
882 NEW_BBLOCK (cfg, set_to_1);
884 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
885 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
886 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
887 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
888 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
889 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
890 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
891 MONO_START_BB (cfg, set_to_1);
892 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
893 MONO_START_BB (cfg, set_to_0);
894 next->opcode = OP_NOP;
895 break;
897 default:
898 g_assert_not_reached ();
900 break;
903 /* Not yet used, since lcompare is decomposed before local cprop */
904 case OP_LCOMPARE_IMM: {
905 MonoInst *next = tree->next;
906 guint32 low_imm = tree->inst_ls_word;
907 guint32 high_imm = tree->inst_ms_word;
908 int low_reg = tree->sreg1 + 1;
909 int high_reg = tree->sreg1 + 2;
911 g_assert (next);
913 switch (next->opcode) {
914 case OP_LBEQ:
915 case OP_LBNE_UN: {
916 int d1, d2;
918 /* Branchless version based on gcc code */
919 d1 = alloc_ireg (cfg);
920 d2 = alloc_ireg (cfg);
921 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
922 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
923 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
924 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
925 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
926 next->opcode = OP_NOP;
927 break;
930 case OP_LBGE:
931 case OP_LBGT:
932 case OP_LBLE:
933 case OP_LBLT:
934 case OP_LBGE_UN:
935 case OP_LBGT_UN:
936 case OP_LBLE_UN:
937 case OP_LBLT_UN:
938 /* Convert into three comparisons + branches */
939 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
940 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
941 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
942 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
943 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
944 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
945 next->opcode = OP_NOP;
946 break;
947 case OP_LCEQ: {
948 int d1, d2;
950 /* Branchless version based on gcc code */
951 d1 = alloc_ireg (cfg);
952 d2 = alloc_ireg (cfg);
953 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
954 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
955 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
957 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
958 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
959 next->opcode = OP_NOP;
960 break;
962 case OP_LCLT:
963 case OP_LCLT_UN:
964 case OP_LCGT:
965 case OP_LCGT_UN: {
966 MonoBasicBlock *set_to_0, *set_to_1;
968 NEW_BBLOCK (cfg, set_to_0);
969 NEW_BBLOCK (cfg, set_to_1);
971 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
972 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
973 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
974 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
975 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
976 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
977 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
978 MONO_START_BB (cfg, set_to_1);
979 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
980 MONO_START_BB (cfg, set_to_0);
981 next->opcode = OP_NOP;
982 break;
984 default:
985 g_assert_not_reached ();
987 break;
990 default:
991 break;
994 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
995 MonoInst *new_prev;
997 /* Replace the original instruction with the new code sequence */
999 /* Ignore the new value of prev */
1000 new_prev = prev;
1001 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1003 /* Process the newly added ops again since they can be long ops too */
1004 if (prev)
1005 tree = prev->next;
1006 else
1007 tree = bb->code;
1009 first_bb->code = first_bb->last_ins = NULL;
1010 first_bb->in_count = first_bb->out_count = 0;
1011 cfg->cbb = first_bb;
1013 else {
1014 prev = tree;
1015 tree = tree->next;
1019 #endif
1022 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1023 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1028 * mono_decompose_vtype_opts:
1030 * Decompose valuetype opcodes.
1032 void
1033 mono_decompose_vtype_opts (MonoCompile *cfg)
1035 MonoBasicBlock *bb, *first_bb;
1038 * Using OP_V opcodes and decomposing them later have two main benefits:
1039 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1040 * everywhere.
1041 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1042 * enabling optimizations to work on vtypes too.
1043 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1044 * can be executed anytime. It should be executed as late as possible so vtype
1045 * opcodes can be optimized by the other passes.
1046 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1047 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1048 * var to 1.
1049 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1050 * when OP_VMOVE opcodes are decomposed.
1054 * Vregs have no associated type information, so we store the type of the vregs
1055 * in ins->klass.
1059 * Create a dummy bblock and emit code into it so we can use the normal
1060 * code generation macros.
1062 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1063 first_bb = cfg->cbb;
1065 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1066 MonoInst *ins;
1067 MonoInst *prev = NULL;
1068 MonoInst *src_var, *dest_var, *src, *dest;
1069 gboolean restart;
1070 int dreg;
1072 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1074 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1075 restart = TRUE;
1077 while (restart) {
1078 restart = FALSE;
1080 for (ins = bb->code; ins; ins = ins->next) {
1081 switch (ins->opcode) {
1082 case OP_VMOVE: {
1083 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1084 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1086 g_assert (ins->klass);
1088 if (!src_var)
1089 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1091 if (!dest_var)
1092 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1094 // FIXME:
1095 if (src_var->backend.is_pinvoke)
1096 dest_var->backend.is_pinvoke = 1;
1098 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1099 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1101 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1102 break;
1104 case OP_VZERO:
1105 g_assert (ins->klass);
1107 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1108 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1110 if (cfg->compute_gc_maps) {
1111 MonoInst *tmp;
1114 * Tell the GC map code that the vtype is considered live after
1115 * the initialization.
1117 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1118 tmp->inst_c1 = ins->dreg;
1119 MONO_ADD_INS (cfg->cbb, tmp);
1121 break;
1122 case OP_STOREV_MEMBASE: {
1123 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1125 if (!src_var) {
1126 g_assert (ins->klass);
1127 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1130 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1132 dreg = alloc_preg (cfg);
1133 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1134 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1135 break;
1137 case OP_LOADV_MEMBASE: {
1138 g_assert (ins->klass);
1140 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1141 // FIXME-VT:
1142 // FIXME:
1143 if (!dest_var)
1144 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1146 dreg = alloc_preg (cfg);
1147 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1148 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1149 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1150 break;
1152 case OP_OUTARG_VT: {
1153 g_assert (ins->klass);
1155 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1156 if (!src_var)
1157 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1158 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1160 mono_arch_emit_outarg_vt (cfg, ins, src);
1162 /* This might be decomposed into other vtype opcodes */
1163 restart = TRUE;
1164 break;
1166 case OP_OUTARG_VTRETADDR: {
1167 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1169 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1170 if (!src_var)
1171 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1172 // FIXME: src_var->backend.is_pinvoke ?
1174 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1175 src->dreg = ins->dreg;
1176 break;
1178 case OP_VCALL:
1179 case OP_VCALL_REG:
1180 case OP_VCALL_MEMBASE: {
1181 MonoCallInst *call = (MonoCallInst*)ins;
1182 int size;
1184 if (call->vret_in_reg) {
1185 MonoCallInst *call2;
1187 /* Replace the vcall with an integer call */
1188 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1189 memcpy (call2, call, sizeof (MonoCallInst));
1190 switch (ins->opcode) {
1191 case OP_VCALL:
1192 call2->inst.opcode = OP_CALL;
1193 break;
1194 case OP_VCALL_REG:
1195 call2->inst.opcode = OP_CALL_REG;
1196 break;
1197 case OP_VCALL_MEMBASE:
1198 call2->inst.opcode = OP_CALL_MEMBASE;
1199 break;
1201 call2->inst.dreg = alloc_preg (cfg);
1202 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1204 /* Compute the vtype location */
1205 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1206 if (!dest_var)
1207 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1208 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1210 /* Save the result */
1211 if (dest_var->backend.is_pinvoke)
1212 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1213 else
1214 size = mono_type_size (dest_var->inst_vtype, NULL);
1215 switch (size) {
1216 case 1:
1217 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1218 break;
1219 case 2:
1220 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1221 break;
1222 case 4:
1223 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1224 break;
1225 case 8:
1226 #if SIZEOF_REGISTER == 4
1228 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1229 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1231 switch (call2->inst.opcode) {
1232 case OP_CALL:
1233 call2->inst.opcode = OP_LCALL;
1234 break;
1235 case OP_CALL_REG:
1236 call2->inst.opcode = OP_LCALL_REG;
1237 break;
1238 case OP_CALL_MEMBASE:
1239 call2->inst.opcode = OP_LCALL_MEMBASE;
1240 break;
1242 call2->inst.dreg = alloc_lreg (cfg);
1243 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1244 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1245 #else
1246 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1247 #endif
1248 break;
1249 default:
1250 /* This assumes the vtype is sizeof (gpointer) long */
1251 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1252 break;
1254 } else {
1255 switch (ins->opcode) {
1256 case OP_VCALL:
1257 ins->opcode = OP_VCALL2;
1258 break;
1259 case OP_VCALL_REG:
1260 ins->opcode = OP_VCALL2_REG;
1261 break;
1262 case OP_VCALL_MEMBASE:
1263 ins->opcode = OP_VCALL2_MEMBASE;
1264 break;
1266 ins->dreg = -1;
1268 break;
1270 default:
1271 break;
1274 g_assert (cfg->cbb == first_bb);
1276 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1277 /* Replace the original instruction with the new code sequence */
1279 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1280 first_bb->code = first_bb->last_ins = NULL;
1281 first_bb->in_count = first_bb->out_count = 0;
1282 cfg->cbb = first_bb;
1284 else
1285 prev = ins;
1289 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1293 inline static MonoInst *
1294 mono_get_domainvar (MonoCompile *cfg)
1296 if (!cfg->domainvar)
1297 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1298 return cfg->domainvar;
1302 * mono_decompose_array_access_opts:
1304 * Decompose array access opcodes.
1306 void
1307 mono_decompose_array_access_opts (MonoCompile *cfg)
1309 MonoBasicBlock *bb, *first_bb;
1312 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1313 * can be executed anytime. It should be run before decompose_long
1317 * Create a dummy bblock and emit code into it so we can use the normal
1318 * code generation macros.
1320 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1321 first_bb = cfg->cbb;
1323 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1324 MonoInst *ins;
1325 MonoInst *prev = NULL;
1326 MonoInst *dest;
1327 MonoInst *iargs [3];
1328 gboolean restart;
1330 if (!bb->has_array_access)
1331 continue;
1333 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1335 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1336 restart = TRUE;
1338 while (restart) {
1339 restart = FALSE;
1341 for (ins = bb->code; ins; ins = ins->next) {
1342 switch (ins->opcode) {
1343 case OP_LDLEN:
1344 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1345 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_CONSTANT_LOAD);
1346 MONO_ADD_INS (cfg->cbb, dest);
1347 break;
1348 case OP_BOUNDS_CHECK:
1349 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1350 if (COMPILE_LLVM (cfg))
1351 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1352 else
1353 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1354 break;
1355 case OP_NEWARR:
1356 if (cfg->opt & MONO_OPT_SHARED) {
1357 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1358 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1359 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1360 iargs [2]->dreg = ins->sreg1;
1362 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1363 dest->dreg = ins->dreg;
1364 } else {
1365 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1366 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1368 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1369 NEW_VTABLECONST (cfg, iargs [0], vtable);
1370 MONO_ADD_INS (cfg->cbb, iargs [0]);
1371 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1372 iargs [1]->dreg = ins->sreg1;
1374 if (managed_alloc)
1375 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1376 else
1377 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1378 dest->dreg = ins->dreg;
1380 break;
1381 case OP_STRLEN:
1382 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1383 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
1384 break;
1385 default:
1386 break;
1389 g_assert (cfg->cbb == first_bb);
1391 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1392 /* Replace the original instruction with the new code sequence */
1394 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1395 first_bb->code = first_bb->last_ins = NULL;
1396 first_bb->in_count = first_bb->out_count = 0;
1397 cfg->cbb = first_bb;
1399 else
1400 prev = ins;
1404 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1408 typedef union {
1409 guint32 vali [2];
1410 gint64 vall;
1411 double vald;
1412 } DVal;
1414 #ifdef MONO_ARCH_SOFT_FLOAT
1417 * mono_decompose_soft_float:
1419 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1420 * similar to long support on 32 bit platforms. 32 bit float values require special
1421 * handling when used as locals, arguments, and in calls.
1422 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1424 void
1425 mono_decompose_soft_float (MonoCompile *cfg)
1427 MonoBasicBlock *bb, *first_bb;
1430 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1434 * Create a dummy bblock and emit code into it so we can use the normal
1435 * code generation macros.
1437 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1438 first_bb = cfg->cbb;
1440 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1441 MonoInst *ins;
1442 MonoInst *prev = NULL;
1443 gboolean restart;
1445 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1447 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1448 restart = TRUE;
1450 while (restart) {
1451 restart = FALSE;
1453 for (ins = bb->code; ins; ins = ins->next) {
1454 const char *spec = INS_INFO (ins->opcode);
1456 /* Most fp operations are handled automatically by opcode emulation */
1458 switch (ins->opcode) {
1459 case OP_R8CONST: {
1460 DVal d;
1461 d.vald = *(double*)ins->inst_p0;
1462 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1463 break;
1465 case OP_R4CONST: {
1466 DVal d;
1467 /* We load the r8 value */
1468 d.vald = *(float*)ins->inst_p0;
1469 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1470 break;
1472 case OP_FMOVE:
1473 ins->opcode = OP_LMOVE;
1474 break;
1475 case OP_FGETLOW32:
1476 ins->opcode = OP_MOVE;
1477 ins->sreg1 = ins->sreg1 + 1;
1478 break;
1479 case OP_FGETHIGH32:
1480 ins->opcode = OP_MOVE;
1481 ins->sreg1 = ins->sreg1 + 2;
1482 break;
1483 case OP_SETFRET: {
1484 int reg = ins->sreg1;
1486 ins->opcode = OP_SETLRET;
1487 ins->dreg = -1;
1488 ins->sreg1 = reg + 1;
1489 ins->sreg2 = reg + 2;
1490 break;
1492 case OP_LOADR8_MEMBASE:
1493 ins->opcode = OP_LOADI8_MEMBASE;
1494 break;
1495 case OP_STORER8_MEMBASE_REG:
1496 ins->opcode = OP_STOREI8_MEMBASE_REG;
1497 break;
1498 case OP_STORER4_MEMBASE_REG: {
1499 MonoInst *iargs [2];
1500 int addr_reg;
1502 /* Arg 1 is the double value */
1503 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1504 iargs [0]->dreg = ins->sreg1;
1506 /* Arg 2 is the address to store to */
1507 addr_reg = mono_alloc_preg (cfg);
1508 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1509 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1510 restart = TRUE;
1511 break;
1513 case OP_LOADR4_MEMBASE: {
1514 MonoInst *iargs [1];
1515 MonoInst *conv;
1516 int addr_reg;
1518 addr_reg = mono_alloc_preg (cfg);
1519 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1520 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1521 conv->dreg = ins->dreg;
1522 break;
1524 case OP_FCALL:
1525 case OP_FCALL_REG:
1526 case OP_FCALL_MEMBASE: {
1527 MonoCallInst *call = (MonoCallInst*)ins;
1528 if (call->signature->ret->type == MONO_TYPE_R4) {
1529 MonoCallInst *call2;
1530 MonoInst *iargs [1];
1531 MonoInst *conv;
1532 GSList *l;
1534 /* Convert the call into a call returning an int */
1535 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1536 memcpy (call2, call, sizeof (MonoCallInst));
1537 switch (ins->opcode) {
1538 case OP_FCALL:
1539 call2->inst.opcode = OP_CALL;
1540 break;
1541 case OP_FCALL_REG:
1542 call2->inst.opcode = OP_CALL_REG;
1543 break;
1544 case OP_FCALL_MEMBASE:
1545 call2->inst.opcode = OP_CALL_MEMBASE;
1546 break;
1547 default:
1548 g_assert_not_reached ();
1550 call2->inst.dreg = mono_alloc_ireg (cfg);
1551 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1553 /* Remap OUTARG_VT instructions referencing this call */
1554 for (l = call->outarg_vts; l; l = l->next)
1555 ((MonoInst*)(l->data))->inst_p0 = call2;
1557 /* FIXME: Optimize this */
1559 /* Emit an r4->r8 conversion */
1560 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1561 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1562 conv->dreg = ins->dreg;
1564 /* The call sequence might include fp ins */
1565 restart = TRUE;
1566 } else {
1567 switch (ins->opcode) {
1568 case OP_FCALL:
1569 ins->opcode = OP_LCALL;
1570 break;
1571 case OP_FCALL_REG:
1572 ins->opcode = OP_LCALL_REG;
1573 break;
1574 case OP_FCALL_MEMBASE:
1575 ins->opcode = OP_LCALL_MEMBASE;
1576 break;
1577 default:
1578 g_assert_not_reached ();
1581 break;
1583 case OP_FCOMPARE: {
1584 MonoJitICallInfo *info;
1585 MonoInst *iargs [2];
1586 MonoInst *call, *cmp, *br;
1588 /* Convert fcompare+fbcc to icall+icompare+beq */
1590 if (!ins->next) {
1591 /* The branch might be optimized away */
1592 NULLIFY_INS (ins);
1593 break;
1596 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1597 if (!info) {
1598 /* The branch might be optimized away */
1599 NULLIFY_INS (ins);
1600 break;
1603 /* Create dummy MonoInst's for the arguments */
1604 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1605 iargs [0]->dreg = ins->sreg1;
1606 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1607 iargs [1]->dreg = ins->sreg2;
1609 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1611 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1612 cmp->sreg1 = call->dreg;
1613 cmp->inst_imm = 0;
1614 MONO_ADD_INS (cfg->cbb, cmp);
1616 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1617 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1618 br->inst_true_bb = ins->next->inst_true_bb;
1619 br->inst_false_bb = ins->next->inst_false_bb;
1620 MONO_ADD_INS (cfg->cbb, br);
1622 /* The call sequence might include fp ins */
1623 restart = TRUE;
1625 /* Skip fbcc or fccc */
1626 NULLIFY_INS (ins->next);
1627 break;
1629 case OP_FCEQ:
1630 case OP_FCGT:
1631 case OP_FCGT_UN:
1632 case OP_FCLT:
1633 case OP_FCLT_UN: {
1634 MonoJitICallInfo *info;
1635 MonoInst *iargs [2];
1636 MonoInst *call;
1638 /* Convert fccc to icall+icompare+iceq */
1640 info = mono_find_jit_opcode_emulation (ins->opcode);
1641 g_assert (info);
1643 /* Create dummy MonoInst's for the arguments */
1644 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1645 iargs [0]->dreg = ins->sreg1;
1646 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1647 iargs [1]->dreg = ins->sreg2;
1649 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1651 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1652 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1654 /* The call sequence might include fp ins */
1655 restart = TRUE;
1656 break;
1658 case OP_CKFINITE: {
1659 MonoInst *iargs [2];
1660 MonoInst *call, *cmp;
1662 /* Convert to icall+icompare+cond_exc+move */
1664 /* Create dummy MonoInst's for the arguments */
1665 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1666 iargs [0]->dreg = ins->sreg1;
1668 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1670 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1671 cmp->sreg1 = call->dreg;
1672 cmp->inst_imm = 1;
1673 MONO_ADD_INS (cfg->cbb, cmp);
1675 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1677 /* Do the assignment if the value is finite */
1678 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1680 restart = TRUE;
1681 break;
1683 default:
1684 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1685 mono_print_ins (ins);
1686 g_assert_not_reached ();
1688 break;
1691 g_assert (cfg->cbb == first_bb);
1693 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1694 /* Replace the original instruction with the new code sequence */
1696 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1697 first_bb->code = first_bb->last_ins = NULL;
1698 first_bb->in_count = first_bb->out_count = 0;
1699 cfg->cbb = first_bb;
1701 else
1702 prev = ins;
1706 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1709 mono_decompose_long_opts (cfg);
1712 #endif
1714 #endif /* DISABLE_JIT */