Remove obsolete Microsoft.Vsa and Microsoft.JScript
[mono-project/dkf.git] / mono / mini / decompose.c
blob89d17c3328c1f093460248cc1ea08559ba7a0d47
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);
24 * mono_decompose_opcode:
26 * Decompose complex opcodes into ones closer to opcodes supported by
27 * the given architecture.
28 * Returns a MonoInst which represents the result of the decomposition, and can
29 * be pushed on the IL stack. This is needed because the original instruction is
30 * nullified.
31 * Sets the cfg exception if an opcode is not supported.
33 MonoInst*
34 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
36 MonoInst *repl = NULL;
37 int type = ins->type;
38 int dreg = ins->dreg;
40 /* FIXME: Instead of = NOP, don't emit the original ins at all */
42 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
43 mono_arch_decompose_opts (cfg, ins);
44 #endif
47 * The code below assumes that we are called immediately after emitting
48 * ins. This means we can emit code using the normal code generation
49 * macros.
51 switch (ins->opcode) {
52 /* this doesn't make sense on ppc and other architectures */
53 #if !defined(MONO_ARCH_NO_IOV_CHECK)
54 case OP_IADD_OVF:
55 if (COMPILE_LLVM (cfg))
56 break;
57 ins->opcode = OP_IADDCC;
58 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
59 break;
60 case OP_IADD_OVF_UN:
61 if (COMPILE_LLVM (cfg))
62 break;
63 ins->opcode = OP_IADDCC;
64 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
65 break;
66 case OP_ISUB_OVF:
67 if (COMPILE_LLVM (cfg))
68 break;
69 ins->opcode = OP_ISUBCC;
70 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
71 break;
72 case OP_ISUB_OVF_UN:
73 if (COMPILE_LLVM (cfg))
74 break;
75 ins->opcode = OP_ISUBCC;
76 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
77 break;
78 #endif
79 case OP_ICONV_TO_OVF_I1:
80 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
81 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
82 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
83 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
84 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
85 NULLIFY_INS (ins);
86 break;
87 case OP_ICONV_TO_OVF_I1_UN:
88 /* probe values between 0 to 127 */
89 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
90 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
91 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
92 NULLIFY_INS (ins);
93 break;
94 case OP_ICONV_TO_OVF_U1:
95 case OP_ICONV_TO_OVF_U1_UN:
96 /* probe value to be within 0 to 255 */
97 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
98 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
99 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
100 NULLIFY_INS (ins);
101 break;
102 case OP_ICONV_TO_OVF_I2:
103 /* Probe value to be within -32768 and 32767 */
104 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
105 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
106 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
107 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
108 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
109 NULLIFY_INS (ins);
110 break;
111 case OP_ICONV_TO_OVF_I2_UN:
112 /* Convert uint value into short, value within 0 and 32767 */
113 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
114 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
115 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
116 NULLIFY_INS (ins);
117 break;
118 case OP_ICONV_TO_OVF_U2:
119 case OP_ICONV_TO_OVF_U2_UN:
120 /* Probe value to be within 0 and 65535 */
121 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
122 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
123 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
124 NULLIFY_INS (ins);
125 break;
126 case OP_ICONV_TO_OVF_U4:
127 case OP_ICONV_TO_OVF_I4_UN:
128 #if SIZEOF_REGISTER == 4
129 case OP_ICONV_TO_OVF_U:
130 case OP_ICONV_TO_OVF_I_UN:
131 #endif
132 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
133 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
134 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
135 NULLIFY_INS (ins);
136 break;
137 case OP_ICONV_TO_I4:
138 case OP_ICONV_TO_U4:
139 case OP_ICONV_TO_OVF_I4:
140 case OP_ICONV_TO_OVF_U4_UN:
141 #if SIZEOF_REGISTER == 4
142 case OP_ICONV_TO_OVF_I:
143 case OP_ICONV_TO_OVF_U_UN:
144 #endif
145 ins->opcode = OP_MOVE;
146 break;
147 case OP_ICONV_TO_I:
148 #if SIZEOF_REGISTER == 8
149 ins->opcode = OP_SEXT_I4;
150 #else
151 ins->opcode = OP_MOVE;
152 #endif
153 break;
154 case OP_ICONV_TO_U:
155 #if SIZEOF_REGISTER == 8
156 ins->opcode = OP_ZEXT_I4;
157 #else
158 ins->opcode = OP_MOVE;
159 #endif
160 break;
162 case OP_FCONV_TO_R8:
163 ins->opcode = OP_FMOVE;
164 break;
166 case OP_FCONV_TO_OVF_I1_UN:
167 case OP_FCONV_TO_OVF_I2_UN:
168 case OP_FCONV_TO_OVF_I4_UN:
169 case OP_FCONV_TO_OVF_I8_UN:
170 case OP_FCONV_TO_OVF_U1_UN:
171 case OP_FCONV_TO_OVF_U2_UN:
172 case OP_FCONV_TO_OVF_U4_UN:
173 case OP_FCONV_TO_OVF_U8_UN:
174 case OP_FCONV_TO_OVF_I_UN:
175 case OP_FCONV_TO_OVF_U_UN:
176 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
177 cfg->exception_message = g_strdup_printf ("float conv.ovf.un opcodes not supported.");
178 break;
180 /* Long opcodes on 64 bit machines */
181 #if SIZEOF_REGISTER == 8
182 case OP_LCONV_TO_I4:
183 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
184 NULLIFY_INS (ins);
185 break;
186 case OP_LCONV_TO_I8:
187 case OP_LCONV_TO_I:
188 case OP_LCONV_TO_U8:
189 case OP_LCONV_TO_U:
190 ins->opcode = OP_MOVE;
191 break;
192 case OP_ICONV_TO_I8:
193 ins->opcode = OP_SEXT_I4;
194 break;
195 case OP_ICONV_TO_U8:
196 ins->opcode = OP_ZEXT_I4;
197 break;
198 case OP_LCONV_TO_U4:
199 /* Clean out the upper word */
200 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
201 NULLIFY_INS (ins);
202 break;
203 case OP_LADD_OVF:
204 if (COMPILE_LLVM (cfg))
205 break;
206 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
207 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
208 NULLIFY_INS (ins);
209 break;
210 case OP_LADD_OVF_UN:
211 if (COMPILE_LLVM (cfg))
212 break;
213 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
214 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
215 NULLIFY_INS (ins);
216 break;
217 #ifndef __mono_ppc64__
218 case OP_LSUB_OVF:
219 if (COMPILE_LLVM (cfg))
220 break;
221 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
222 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
223 NULLIFY_INS (ins);
224 break;
225 case OP_LSUB_OVF_UN:
226 if (COMPILE_LLVM (cfg))
227 break;
228 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
229 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
230 NULLIFY_INS (ins);
231 break;
232 #endif
234 case OP_ICONV_TO_OVF_I8:
235 case OP_ICONV_TO_OVF_I:
236 ins->opcode = OP_SEXT_I4;
237 break;
238 case OP_ICONV_TO_OVF_U8:
239 case OP_ICONV_TO_OVF_U:
240 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
241 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
242 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
243 NULLIFY_INS (ins);
244 break;
245 case OP_ICONV_TO_OVF_I8_UN:
246 case OP_ICONV_TO_OVF_U8_UN:
247 case OP_ICONV_TO_OVF_I_UN:
248 case OP_ICONV_TO_OVF_U_UN:
249 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
250 /* Clean out the upper word */
251 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
252 NULLIFY_INS (ins);
253 break;
254 case OP_LCONV_TO_OVF_I1:
255 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
256 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
257 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
258 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
259 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
260 NULLIFY_INS (ins);
261 break;
262 case OP_LCONV_TO_OVF_I1_UN:
263 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
264 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
265 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
266 NULLIFY_INS (ins);
267 break;
268 case OP_LCONV_TO_OVF_U1:
269 /* probe value to be within 0 to 255 */
270 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
271 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
272 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
273 NULLIFY_INS (ins);
274 break;
275 case OP_LCONV_TO_OVF_U1_UN:
276 /* probe value to be within 0 to 255 */
277 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
278 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
279 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
280 NULLIFY_INS (ins);
281 break;
282 case OP_LCONV_TO_OVF_I2:
283 /* Probe value to be within -32768 and 32767 */
284 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
285 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
286 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
287 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
288 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
289 NULLIFY_INS (ins);
290 break;
291 case OP_LCONV_TO_OVF_I2_UN:
292 /* Probe value to be within 0 and 32767 */
293 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
294 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
295 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
296 NULLIFY_INS (ins);
297 break;
298 case OP_LCONV_TO_OVF_U2:
299 /* Probe value to be within 0 and 65535 */
300 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
301 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
302 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
303 NULLIFY_INS (ins);
304 break;
305 case OP_LCONV_TO_OVF_U2_UN:
306 /* Probe value to be within 0 and 65535 */
307 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
308 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
309 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
310 NULLIFY_INS (ins);
311 break;
312 case OP_LCONV_TO_OVF_I4:
313 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
314 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
315 /* The int cast is needed for the VS compiler. See Compiler Warning (level 2) C4146. */
316 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
317 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
318 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
319 NULLIFY_INS (ins);
320 break;
321 case OP_LCONV_TO_OVF_I4_UN:
322 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
323 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
324 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
325 NULLIFY_INS (ins);
326 break;
327 case OP_LCONV_TO_OVF_U4:
328 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
329 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
330 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
331 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
332 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
333 NULLIFY_INS (ins);
334 break;
335 case OP_LCONV_TO_OVF_U4_UN:
336 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
337 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
338 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
339 NULLIFY_INS (ins);
340 break;
341 case OP_LCONV_TO_OVF_I:
342 case OP_LCONV_TO_OVF_U_UN:
343 case OP_LCONV_TO_OVF_U8_UN:
344 case OP_LCONV_TO_OVF_I8:
345 ins->opcode = OP_MOVE;
346 break;
347 case OP_LCONV_TO_OVF_I_UN:
348 case OP_LCONV_TO_OVF_I8_UN:
349 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
350 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
351 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
352 NULLIFY_INS (ins);
353 break;
354 case OP_LCONV_TO_OVF_U8:
355 case OP_LCONV_TO_OVF_U:
356 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
357 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
358 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
359 NULLIFY_INS (ins);
360 break;
361 #endif
363 default: {
364 MonoJitICallInfo *info;
366 info = mono_find_jit_opcode_emulation (ins->opcode);
367 if (info) {
368 MonoInst **args;
369 MonoInst *call;
371 /* Create dummy MonoInst's for the arguments */
372 g_assert (!info->sig->hasthis);
373 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
375 args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
376 if (info->sig->param_count > 0) {
377 int sregs [MONO_MAX_SRC_REGS];
378 int num_sregs, i;
379 num_sregs = mono_inst_get_src_registers (ins, sregs);
380 g_assert (num_sregs == info->sig->param_count);
381 for (i = 0; i < num_sregs; ++i) {
382 MONO_INST_NEW (cfg, args [i], OP_ARG);
383 args [i]->dreg = sregs [i];
387 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
388 call->dreg = ins->dreg;
390 NULLIFY_INS (ins);
392 break;
396 if (ins->opcode == OP_NOP) {
397 if (repl) {
398 repl->type = type;
399 return repl;
400 } else {
401 /* Use the last emitted instruction */
402 ins = cfg->cbb->last_ins;
403 g_assert (ins);
404 ins->type = type;
405 g_assert (ins->dreg == dreg);
406 return ins;
408 } else {
409 return ins;
413 #if SIZEOF_REGISTER == 4
414 static int lbr_decomp [][2] = {
415 {0, 0}, /* BEQ */
416 {OP_IBGT, OP_IBGE_UN}, /* BGE */
417 {OP_IBGT, OP_IBGT_UN}, /* BGT */
418 {OP_IBLT, OP_IBLE_UN}, /* BLE */
419 {OP_IBLT, OP_IBLT_UN}, /* BLT */
420 {0, 0}, /* BNE_UN */
421 {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
422 {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
423 {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
424 {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
427 static int lcset_decomp [][2] = {
428 {0, 0}, /* CEQ */
429 {OP_IBLT, OP_IBLE_UN}, /* CGT */
430 {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
431 {OP_IBGT, OP_IBGE_UN}, /* CLT */
432 {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
434 #endif
437 * mono_decompose_long_opts:
439 * Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
441 void
442 mono_decompose_long_opts (MonoCompile *cfg)
444 #if SIZEOF_REGISTER == 4
445 MonoBasicBlock *bb, *first_bb;
448 * Some opcodes, like lcall can't be decomposed so the rest of the JIT
449 * needs to be able to handle long vregs.
452 /* reg + 1 contains the ls word, reg + 2 contains the ms word */
455 * Create a dummy bblock and emit code into it so we can use the normal
456 * code generation macros.
458 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
459 first_bb = cfg->cbb;
461 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
462 MonoInst *tree = bb->code;
463 MonoInst *prev = NULL;
466 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
469 tree = bb->code;
470 cfg->cbb->code = cfg->cbb->last_ins = NULL;
472 while (tree) {
474 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
475 mono_arch_decompose_long_opts (cfg, tree);
476 #endif
478 switch (tree->opcode) {
479 case OP_I8CONST:
480 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
481 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
482 break;
483 case OP_LMOVE:
484 case OP_LCONV_TO_U8:
485 case OP_LCONV_TO_I8:
486 case OP_LCONV_TO_OVF_U8_UN:
487 case OP_LCONV_TO_OVF_I8:
488 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
489 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
490 break;
491 case OP_STOREI8_MEMBASE_REG:
492 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
493 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
494 break;
495 case OP_LOADI8_MEMBASE:
496 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
497 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
498 break;
500 case OP_ICONV_TO_I8: {
501 guint32 tmpreg = alloc_ireg (cfg);
503 /* branchless code:
504 * low = reg;
505 * tmp = low > -1 ? 1: 0;
506 * high = tmp - 1; if low is zero or pos high becomes 0, else -1
508 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
509 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
510 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
511 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
512 break;
514 case OP_ICONV_TO_U8:
515 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
516 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
517 break;
518 case OP_ICONV_TO_OVF_I8:
519 /* a signed 32 bit num always fits in a signed 64 bit one */
520 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
521 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
522 break;
523 case OP_ICONV_TO_OVF_U8:
524 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
525 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
526 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
527 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
528 break;
529 case OP_ICONV_TO_OVF_I8_UN:
530 case OP_ICONV_TO_OVF_U8_UN:
531 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
532 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
533 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
534 break;
535 case OP_LCONV_TO_I1:
536 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
537 break;
538 case OP_LCONV_TO_U1:
539 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
540 break;
541 case OP_LCONV_TO_I2:
542 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
543 break;
544 case OP_LCONV_TO_U2:
545 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
546 break;
547 case OP_LCONV_TO_I4:
548 case OP_LCONV_TO_U4:
549 case OP_LCONV_TO_I:
550 case OP_LCONV_TO_U:
551 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
552 break;
553 case OP_LCONV_TO_R8:
554 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
555 break;
556 case OP_LCONV_TO_R4:
557 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
558 break;
559 case OP_LCONV_TO_R_UN:
560 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
561 break;
562 case OP_LCONV_TO_OVF_I1: {
563 MonoBasicBlock *is_negative, *end_label;
565 NEW_BBLOCK (cfg, is_negative);
566 NEW_BBLOCK (cfg, end_label);
568 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
569 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
570 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
571 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
573 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
574 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
576 /* Positive */
577 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
578 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
579 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
581 /* Negative */
582 MONO_START_BB (cfg, is_negative);
583 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
584 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
586 MONO_START_BB (cfg, end_label);
588 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
589 break;
591 case OP_LCONV_TO_OVF_I1_UN:
592 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
593 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
595 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
596 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
597 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
598 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
599 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
600 break;
601 case OP_LCONV_TO_OVF_U1:
602 case OP_LCONV_TO_OVF_U1_UN:
603 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
604 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
606 /* probe value to be within 0 to 255 */
607 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
608 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
609 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
610 break;
611 case OP_LCONV_TO_OVF_I2: {
612 MonoBasicBlock *is_negative, *end_label;
614 NEW_BBLOCK (cfg, is_negative);
615 NEW_BBLOCK (cfg, end_label);
617 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
618 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
619 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
620 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
622 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
623 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
625 /* Positive */
626 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
627 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
628 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
630 /* Negative */
631 MONO_START_BB (cfg, is_negative);
632 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
633 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
634 MONO_START_BB (cfg, end_label);
636 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
637 break;
639 case OP_LCONV_TO_OVF_I2_UN:
640 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
641 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
643 /* Probe value to be within -32768 and 32767 */
644 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
645 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
646 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
647 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
648 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
649 break;
650 case OP_LCONV_TO_OVF_U2:
651 case OP_LCONV_TO_OVF_U2_UN:
652 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
653 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
655 /* Probe value to be within 0 and 65535 */
656 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
657 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
658 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
659 break;
660 case OP_LCONV_TO_OVF_I4:
661 case OP_LCONV_TO_OVF_I:
662 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
663 break;
664 case OP_LCONV_TO_OVF_U4:
665 case OP_LCONV_TO_OVF_U:
666 case OP_LCONV_TO_OVF_U4_UN:
667 case OP_LCONV_TO_OVF_U_UN:
668 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
669 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
670 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
671 break;
672 case OP_LCONV_TO_OVF_I_UN:
673 case OP_LCONV_TO_OVF_I4_UN:
674 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
675 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
676 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
677 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
678 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
679 break;
680 case OP_LCONV_TO_OVF_U8:
681 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
682 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
684 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
685 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
686 break;
687 case OP_LCONV_TO_OVF_I8_UN:
688 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
689 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
691 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
692 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
693 break;
695 case OP_LADD:
696 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
697 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
698 break;
699 case OP_LSUB:
700 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
701 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
702 break;
704 case OP_LADD_OVF:
705 /* ADC sets the condition code */
706 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
707 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
708 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
709 break;
710 case OP_LADD_OVF_UN:
711 /* ADC sets the condition code */
712 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
713 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
714 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
715 break;
716 case OP_LSUB_OVF:
717 /* SBB sets the condition code */
718 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
719 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
720 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
721 break;
722 case OP_LSUB_OVF_UN:
723 /* SBB sets the condition code */
724 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
725 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
726 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
727 break;
728 case OP_LAND:
729 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
730 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
731 break;
732 case OP_LOR:
733 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
734 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
735 break;
736 case OP_LXOR:
737 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
738 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
739 break;
740 case OP_LNOT:
741 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
742 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
743 break;
744 case OP_LNEG:
745 /* Handled in mono_arch_decompose_long_opts () */
746 g_assert_not_reached ();
747 break;
748 case OP_LMUL:
749 /* Emulated */
750 /* FIXME: Add OP_BIGMUL optimization */
751 break;
753 case OP_LADD_IMM:
754 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
755 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
756 break;
757 case OP_LSUB_IMM:
758 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
759 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
760 break;
761 case OP_LAND_IMM:
762 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
763 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
764 break;
765 case OP_LOR_IMM:
766 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
767 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
768 break;
769 case OP_LXOR_IMM:
770 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
771 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
772 break;
773 case OP_LSHR_UN_IMM:
774 if (tree->inst_c1 == 32) {
776 /* The original code had this comment: */
777 /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
778 * later apply the speedup to the left shift as well
779 * See BUG# 57957.
781 /* FIXME: Move this to the strength reduction pass */
782 /* just move the upper half to the lower and zero the high word */
783 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
784 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
786 break;
787 case OP_LSHL_IMM:
788 if (tree->inst_c1 == 32) {
789 /* just move the lower half to the upper and zero the lower word */
790 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
791 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
793 break;
795 case OP_LCOMPARE: {
796 MonoInst *next = tree->next;
798 g_assert (next);
800 switch (next->opcode) {
801 case OP_LBEQ:
802 case OP_LBNE_UN: {
803 int d1, d2;
805 /* Branchless version based on gcc code */
806 d1 = alloc_ireg (cfg);
807 d2 = alloc_ireg (cfg);
808 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
809 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
810 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
811 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
812 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
813 next->opcode = OP_NOP;
814 break;
816 case OP_LBGE:
817 case OP_LBGT:
818 case OP_LBLE:
819 case OP_LBLT:
820 case OP_LBGE_UN:
821 case OP_LBGT_UN:
822 case OP_LBLE_UN:
823 case OP_LBLT_UN:
824 /* Convert into three comparisons + branches */
825 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
826 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
827 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
828 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
829 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
830 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
831 next->opcode = OP_NOP;
832 break;
833 case OP_LCEQ: {
834 int d1, d2;
836 /* Branchless version based on gcc code */
837 d1 = alloc_ireg (cfg);
838 d2 = alloc_ireg (cfg);
839 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
840 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
841 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
843 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
844 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
845 next->opcode = OP_NOP;
846 break;
848 case OP_LCLT:
849 case OP_LCLT_UN:
850 case OP_LCGT:
851 case OP_LCGT_UN: {
852 MonoBasicBlock *set_to_0, *set_to_1;
854 NEW_BBLOCK (cfg, set_to_0);
855 NEW_BBLOCK (cfg, set_to_1);
857 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
858 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
859 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
860 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
861 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
862 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
863 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
864 MONO_START_BB (cfg, set_to_1);
865 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
866 MONO_START_BB (cfg, set_to_0);
867 next->opcode = OP_NOP;
868 break;
870 default:
871 g_assert_not_reached ();
873 break;
876 /* Not yet used, since lcompare is decomposed before local cprop */
877 case OP_LCOMPARE_IMM: {
878 MonoInst *next = tree->next;
879 guint32 low_imm = tree->inst_ls_word;
880 guint32 high_imm = tree->inst_ms_word;
881 int low_reg = tree->sreg1 + 1;
882 int high_reg = tree->sreg1 + 2;
884 g_assert (next);
886 switch (next->opcode) {
887 case OP_LBEQ:
888 case OP_LBNE_UN: {
889 int d1, d2;
891 /* Branchless version based on gcc code */
892 d1 = alloc_ireg (cfg);
893 d2 = alloc_ireg (cfg);
894 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
895 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
896 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
897 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
898 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
899 next->opcode = OP_NOP;
900 break;
903 case OP_LBGE:
904 case OP_LBGT:
905 case OP_LBLE:
906 case OP_LBLT:
907 case OP_LBGE_UN:
908 case OP_LBGT_UN:
909 case OP_LBLE_UN:
910 case OP_LBLT_UN:
911 /* Convert into three comparisons + branches */
912 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
913 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
914 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
915 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
916 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
917 MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
918 next->opcode = OP_NOP;
919 break;
920 case OP_LCEQ: {
921 int d1, d2;
923 /* Branchless version based on gcc code */
924 d1 = alloc_ireg (cfg);
925 d2 = alloc_ireg (cfg);
926 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
927 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
928 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
930 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
931 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
932 next->opcode = OP_NOP;
933 break;
935 case OP_LCLT:
936 case OP_LCLT_UN:
937 case OP_LCGT:
938 case OP_LCGT_UN: {
939 MonoBasicBlock *set_to_0, *set_to_1;
941 NEW_BBLOCK (cfg, set_to_0);
942 NEW_BBLOCK (cfg, set_to_1);
944 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
945 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
946 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
947 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
948 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
949 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
950 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
951 MONO_START_BB (cfg, set_to_1);
952 MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
953 MONO_START_BB (cfg, set_to_0);
954 next->opcode = OP_NOP;
955 break;
957 default:
958 g_assert_not_reached ();
960 break;
963 default:
964 break;
967 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
968 MonoInst *new_prev;
970 /* Replace the original instruction with the new code sequence */
972 /* Ignore the new value of prev */
973 new_prev = prev;
974 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
976 /* Process the newly added ops again since they can be long ops too */
977 if (prev)
978 tree = prev->next;
979 else
980 tree = bb->code;
982 first_bb->code = first_bb->last_ins = NULL;
983 first_bb->in_count = first_bb->out_count = 0;
984 cfg->cbb = first_bb;
986 else {
987 prev = tree;
988 tree = tree->next;
992 #endif
995 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
996 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1001 * mono_decompose_vtype_opts:
1003 * Decompose valuetype opcodes.
1005 void
1006 mono_decompose_vtype_opts (MonoCompile *cfg)
1008 MonoBasicBlock *bb, *first_bb;
1011 * Using OP_V opcodes and decomposing them later have two main benefits:
1012 * - it simplifies method_to_ir () since there is no need to special-case vtypes
1013 * everywhere.
1014 * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1015 * enabling optimizations to work on vtypes too.
1016 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1017 * can be executed anytime. It should be executed as late as possible so vtype
1018 * opcodes can be optimized by the other passes.
1019 * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1020 * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the
1021 * var to 1.
1022 * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass
1023 * when OP_VMOVE opcodes are decomposed.
1027 * Vregs have no associated type information, so we store the type of the vregs
1028 * in ins->klass.
1032 * Create a dummy bblock and emit code into it so we can use the normal
1033 * code generation macros.
1035 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1036 first_bb = cfg->cbb;
1038 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1039 MonoInst *ins;
1040 MonoInst *prev = NULL;
1041 MonoInst *src_var, *dest_var, *src, *dest;
1042 gboolean restart;
1043 int dreg;
1045 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1047 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1048 restart = TRUE;
1050 while (restart) {
1051 restart = FALSE;
1053 for (ins = bb->code; ins; ins = ins->next) {
1054 switch (ins->opcode) {
1055 case OP_VMOVE: {
1056 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1057 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1059 g_assert (ins->klass);
1061 if (!src_var)
1062 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1064 if (!dest_var)
1065 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1067 // FIXME:
1068 if (src_var->backend.is_pinvoke)
1069 dest_var->backend.is_pinvoke = 1;
1071 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1072 EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1074 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1075 break;
1077 case OP_VZERO:
1078 g_assert (ins->klass);
1080 EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1081 mini_emit_initobj (cfg, dest, NULL, ins->klass);
1082 break;
1083 case OP_STOREV_MEMBASE: {
1084 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1086 if (!src_var) {
1087 g_assert (ins->klass);
1088 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1091 EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1093 dreg = alloc_preg (cfg);
1094 EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1095 mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1096 break;
1098 case OP_LOADV_MEMBASE: {
1099 g_assert (ins->klass);
1101 dest_var = get_vreg_to_inst (cfg, ins->dreg);
1102 // FIXME:
1103 if (!dest_var)
1104 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1106 dreg = alloc_preg (cfg);
1107 EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1108 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1109 mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1110 break;
1112 case OP_OUTARG_VT: {
1113 g_assert (ins->klass);
1115 src_var = get_vreg_to_inst (cfg, ins->sreg1);
1116 if (!src_var)
1117 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1118 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1120 mono_arch_emit_outarg_vt (cfg, ins, src);
1122 /* This might be decomposed into other vtype opcodes */
1123 restart = TRUE;
1124 break;
1126 case OP_OUTARG_VTRETADDR: {
1127 MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1129 src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1130 if (!src_var)
1131 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1132 // FIXME: src_var->backend.is_pinvoke ?
1134 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1135 src->dreg = ins->dreg;
1136 break;
1138 case OP_VCALL:
1139 case OP_VCALL_REG:
1140 case OP_VCALL_MEMBASE: {
1141 MonoCallInst *call = (MonoCallInst*)ins;
1142 int size;
1144 if (call->vret_in_reg) {
1145 MonoCallInst *call2;
1147 /* Replace the vcall with an integer call */
1148 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1149 memcpy (call2, call, sizeof (MonoCallInst));
1150 switch (ins->opcode) {
1151 case OP_VCALL:
1152 call2->inst.opcode = OP_CALL;
1153 break;
1154 case OP_VCALL_REG:
1155 call2->inst.opcode = OP_CALL_REG;
1156 break;
1157 case OP_VCALL_MEMBASE:
1158 call2->inst.opcode = OP_CALL_MEMBASE;
1159 break;
1161 call2->inst.dreg = alloc_preg (cfg);
1162 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1164 /* Compute the vtype location */
1165 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1166 if (!dest_var)
1167 dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1168 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1170 /* Save the result */
1171 if (dest_var->backend.is_pinvoke)
1172 size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1173 else
1174 size = mono_type_size (dest_var->inst_vtype, NULL);
1175 switch (size) {
1176 case 1:
1177 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1178 break;
1179 case 2:
1180 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1181 break;
1182 case 4:
1183 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1184 break;
1185 case 8:
1186 #if SIZEOF_REGISTER == 4
1188 FIXME Other ABIs might return in different regs than the ones used for LCALL.
1189 FIXME It would be even nicer to be able to leverage the long decompose stuff.
1191 switch (call2->inst.opcode) {
1192 case OP_CALL:
1193 call2->inst.opcode = OP_LCALL;
1194 break;
1195 case OP_CALL_REG:
1196 call2->inst.opcode = OP_LCALL_REG;
1197 break;
1198 case OP_CALL_MEMBASE:
1199 call2->inst.opcode = OP_LCALL_MEMBASE;
1200 break;
1202 call2->inst.dreg = alloc_lreg (cfg);
1203 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1204 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1205 #else
1206 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1207 #endif
1208 break;
1209 default:
1210 /* This assumes the vtype is sizeof (gpointer) long */
1211 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1212 break;
1214 } else {
1215 switch (ins->opcode) {
1216 case OP_VCALL:
1217 ins->opcode = OP_VCALL2;
1218 break;
1219 case OP_VCALL_REG:
1220 ins->opcode = OP_VCALL2_REG;
1221 break;
1222 case OP_VCALL_MEMBASE:
1223 ins->opcode = OP_VCALL2_MEMBASE;
1224 break;
1226 ins->dreg = -1;
1228 break;
1230 default:
1231 break;
1234 g_assert (cfg->cbb == first_bb);
1236 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1237 /* Replace the original instruction with the new code sequence */
1239 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1240 first_bb->code = first_bb->last_ins = NULL;
1241 first_bb->in_count = first_bb->out_count = 0;
1242 cfg->cbb = first_bb;
1244 else
1245 prev = ins;
1249 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1253 inline static MonoInst *
1254 mono_get_domainvar (MonoCompile *cfg)
1256 if (!cfg->domainvar)
1257 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1258 return cfg->domainvar;
1262 * mono_decompose_array_access_opts:
1264 * Decompose array access opcodes.
1266 void
1267 mono_decompose_array_access_opts (MonoCompile *cfg)
1269 MonoBasicBlock *bb, *first_bb;
1272 * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it
1273 * can be executed anytime. It should be run before decompose_long
1277 * Create a dummy bblock and emit code into it so we can use the normal
1278 * code generation macros.
1280 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1281 first_bb = cfg->cbb;
1283 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1284 MonoInst *ins;
1285 MonoInst *prev = NULL;
1286 MonoInst *dest;
1287 MonoInst *iargs [3];
1288 gboolean restart;
1290 if (!bb->has_array_access)
1291 continue;
1293 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1295 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1296 restart = TRUE;
1298 while (restart) {
1299 restart = FALSE;
1301 for (ins = bb->code; ins; ins = ins->next) {
1302 switch (ins->opcode) {
1303 case OP_LDLEN:
1304 NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1305 G_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_CONSTANT_LOAD);
1306 MONO_ADD_INS (cfg->cbb, dest);
1307 break;
1308 case OP_BOUNDS_CHECK:
1309 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1310 if (COMPILE_LLVM (cfg))
1311 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1312 else
1313 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1314 break;
1315 case OP_NEWARR:
1316 if (cfg->opt & MONO_OPT_SHARED) {
1317 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1318 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1319 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1320 iargs [2]->dreg = ins->sreg1;
1322 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1323 dest->dreg = ins->dreg;
1324 } else {
1325 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1326 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1328 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1329 NEW_VTABLECONST (cfg, iargs [0], vtable);
1330 MONO_ADD_INS (cfg->cbb, iargs [0]);
1331 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1332 iargs [1]->dreg = ins->sreg1;
1334 if (managed_alloc)
1335 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1336 else
1337 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1338 dest->dreg = ins->dreg;
1340 break;
1341 case OP_STRLEN:
1342 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1343 ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
1344 break;
1345 default:
1346 break;
1349 g_assert (cfg->cbb == first_bb);
1351 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1352 /* Replace the original instruction with the new code sequence */
1354 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1355 first_bb->code = first_bb->last_ins = NULL;
1356 first_bb->in_count = first_bb->out_count = 0;
1357 cfg->cbb = first_bb;
1359 else
1360 prev = ins;
1364 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1368 typedef union {
1369 guint32 vali [2];
1370 gint64 vall;
1371 double vald;
1372 } DVal;
1374 #ifdef MONO_ARCH_SOFT_FLOAT
1377 * mono_decompose_soft_float:
1379 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1380 * similar to long support on 32 bit platforms. 32 bit float values require special
1381 * handling when used as locals, arguments, and in calls.
1382 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1384 void
1385 mono_decompose_soft_float (MonoCompile *cfg)
1387 MonoBasicBlock *bb, *first_bb;
1390 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1394 * Create a dummy bblock and emit code into it so we can use the normal
1395 * code generation macros.
1397 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1398 first_bb = cfg->cbb;
1400 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1401 MonoInst *ins;
1402 MonoInst *prev = NULL;
1403 gboolean restart;
1405 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1407 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1408 restart = TRUE;
1410 while (restart) {
1411 restart = FALSE;
1413 for (ins = bb->code; ins; ins = ins->next) {
1414 const char *spec = INS_INFO (ins->opcode);
1416 /* Most fp operations are handled automatically by opcode emulation */
1418 switch (ins->opcode) {
1419 case OP_R8CONST: {
1420 DVal d;
1421 d.vald = *(double*)ins->inst_p0;
1422 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1423 break;
1425 case OP_R4CONST: {
1426 DVal d;
1427 /* We load the r8 value */
1428 d.vald = *(float*)ins->inst_p0;
1429 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1430 break;
1432 case OP_FMOVE:
1433 ins->opcode = OP_LMOVE;
1434 break;
1435 case OP_FGETLOW32:
1436 ins->opcode = OP_MOVE;
1437 ins->sreg1 = ins->sreg1 + 1;
1438 break;
1439 case OP_FGETHIGH32:
1440 ins->opcode = OP_MOVE;
1441 ins->sreg1 = ins->sreg1 + 2;
1442 break;
1443 case OP_SETFRET: {
1444 int reg = ins->sreg1;
1446 ins->opcode = OP_SETLRET;
1447 ins->dreg = -1;
1448 ins->sreg1 = reg + 1;
1449 ins->sreg2 = reg + 2;
1450 break;
1452 case OP_LOADR8_MEMBASE:
1453 ins->opcode = OP_LOADI8_MEMBASE;
1454 break;
1455 case OP_STORER8_MEMBASE_REG:
1456 ins->opcode = OP_STOREI8_MEMBASE_REG;
1457 break;
1458 case OP_STORER4_MEMBASE_REG: {
1459 MonoInst *iargs [2];
1460 int addr_reg;
1462 /* Arg 1 is the double value */
1463 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1464 iargs [0]->dreg = ins->sreg1;
1466 /* Arg 2 is the address to store to */
1467 addr_reg = mono_alloc_preg (cfg);
1468 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1469 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1470 restart = TRUE;
1471 break;
1473 case OP_LOADR4_MEMBASE: {
1474 MonoInst *iargs [1];
1475 MonoInst *conv;
1476 int addr_reg;
1478 addr_reg = mono_alloc_preg (cfg);
1479 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1480 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1481 conv->dreg = ins->dreg;
1482 break;
1484 case OP_FCALL:
1485 case OP_FCALL_REG:
1486 case OP_FCALL_MEMBASE: {
1487 MonoCallInst *call = (MonoCallInst*)ins;
1488 if (call->signature->ret->type == MONO_TYPE_R4) {
1489 MonoCallInst *call2;
1490 MonoInst *iargs [1];
1491 MonoInst *conv;
1493 /* Convert the call into a call returning an int */
1494 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1495 memcpy (call2, call, sizeof (MonoCallInst));
1496 switch (ins->opcode) {
1497 case OP_FCALL:
1498 call2->inst.opcode = OP_CALL;
1499 break;
1500 case OP_FCALL_REG:
1501 call2->inst.opcode = OP_CALL_REG;
1502 break;
1503 case OP_FCALL_MEMBASE:
1504 call2->inst.opcode = OP_CALL_MEMBASE;
1505 break;
1506 default:
1507 g_assert_not_reached ();
1509 call2->inst.dreg = mono_alloc_ireg (cfg);
1510 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1512 /* FIXME: Optimize this */
1514 /* Emit an r4->r8 conversion */
1515 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1516 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1517 conv->dreg = ins->dreg;
1519 /* The call sequence might include fp ins */
1520 restart = TRUE;
1521 } else {
1522 switch (ins->opcode) {
1523 case OP_FCALL:
1524 ins->opcode = OP_LCALL;
1525 break;
1526 case OP_FCALL_REG:
1527 ins->opcode = OP_LCALL_REG;
1528 break;
1529 case OP_FCALL_MEMBASE:
1530 ins->opcode = OP_LCALL_MEMBASE;
1531 break;
1532 default:
1533 g_assert_not_reached ();
1536 break;
1538 case OP_FCOMPARE: {
1539 MonoJitICallInfo *info;
1540 MonoInst *iargs [2];
1541 MonoInst *call, *cmp, *br;
1543 /* Convert fcompare+fbcc to icall+icompare+beq */
1545 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1546 g_assert (info);
1548 /* Create dummy MonoInst's for the arguments */
1549 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1550 iargs [0]->dreg = ins->sreg1;
1551 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1552 iargs [1]->dreg = ins->sreg2;
1554 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1556 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1557 cmp->sreg1 = call->dreg;
1558 cmp->inst_imm = 0;
1559 MONO_ADD_INS (cfg->cbb, cmp);
1561 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1562 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1563 br->inst_true_bb = ins->next->inst_true_bb;
1564 br->inst_false_bb = ins->next->inst_false_bb;
1565 MONO_ADD_INS (cfg->cbb, br);
1567 /* The call sequence might include fp ins */
1568 restart = TRUE;
1570 /* Skip fbcc or fccc */
1571 NULLIFY_INS (ins->next);
1572 break;
1574 case OP_FCEQ:
1575 case OP_FCGT:
1576 case OP_FCGT_UN:
1577 case OP_FCLT:
1578 case OP_FCLT_UN: {
1579 MonoJitICallInfo *info;
1580 MonoInst *iargs [2];
1581 MonoInst *call;
1583 /* Convert fccc to icall+icompare+iceq */
1585 info = mono_find_jit_opcode_emulation (ins->opcode);
1586 g_assert (info);
1588 /* Create dummy MonoInst's for the arguments */
1589 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1590 iargs [0]->dreg = ins->sreg1;
1591 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1592 iargs [1]->dreg = ins->sreg2;
1594 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1596 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1597 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1599 /* The call sequence might include fp ins */
1600 restart = TRUE;
1601 break;
1603 case OP_CKFINITE: {
1604 MonoInst *iargs [2];
1605 MonoInst *call, *cmp;
1607 /* Convert to icall+icompare+cond_exc+move */
1609 /* Create dummy MonoInst's for the arguments */
1610 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1611 iargs [0]->dreg = ins->sreg1;
1613 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1615 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1616 cmp->sreg1 = call->dreg;
1617 cmp->inst_imm = 1;
1618 MONO_ADD_INS (cfg->cbb, cmp);
1620 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1622 /* Do the assignment if the value is finite */
1623 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1625 restart = TRUE;
1626 break;
1628 default:
1629 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1630 mono_print_ins (ins);
1631 g_assert_not_reached ();
1633 break;
1636 g_assert (cfg->cbb == first_bb);
1638 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1639 /* Replace the original instruction with the new code sequence */
1641 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1642 first_bb->code = first_bb->last_ins = NULL;
1643 first_bb->in_count = first_bb->out_count = 0;
1644 cfg->cbb = first_bb;
1646 else
1647 prev = ins;
1651 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1654 mono_decompose_long_opts (cfg);
1657 #endif
1659 #endif /* DISABLE_JIT */