2010-04-06 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / decompose.c
blob8fa6bb3eb3c00b8d2165ed54cc2eef8dcee851d6
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_FAULT (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1305 G_STRUCT_OFFSET (MonoArray, max_length));
1306 MONO_ADD_INS (cfg->cbb, dest);
1307 break;
1308 case OP_BOUNDS_CHECK:
1309 MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1310 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1311 break;
1312 case OP_NEWARR:
1313 if (cfg->opt & MONO_OPT_SHARED) {
1314 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1315 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1316 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1317 iargs [2]->dreg = ins->sreg1;
1319 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1320 dest->dreg = ins->dreg;
1321 } else {
1322 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1323 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1325 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1326 NEW_VTABLECONST (cfg, iargs [0], vtable);
1327 MONO_ADD_INS (cfg->cbb, iargs [0]);
1328 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1329 iargs [1]->dreg = ins->sreg1;
1331 if (managed_alloc)
1332 dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1333 else
1334 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1335 dest->dreg = ins->dreg;
1337 break;
1338 case OP_STRLEN:
1339 MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1340 ins->sreg1, G_STRUCT_OFFSET (MonoString, length));
1341 break;
1342 default:
1343 break;
1346 g_assert (cfg->cbb == first_bb);
1348 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1349 /* Replace the original instruction with the new code sequence */
1351 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1352 first_bb->code = first_bb->last_ins = NULL;
1353 first_bb->in_count = first_bb->out_count = 0;
1354 cfg->cbb = first_bb;
1356 else
1357 prev = ins;
1361 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1365 typedef union {
1366 guint32 vali [2];
1367 gint64 vall;
1368 double vald;
1369 } DVal;
1371 #ifdef MONO_ARCH_SOFT_FLOAT
1374 * mono_decompose_soft_float:
1376 * Soft float support on ARM. We store each double value in a pair of integer vregs,
1377 * similar to long support on 32 bit platforms. 32 bit float values require special
1378 * handling when used as locals, arguments, and in calls.
1379 * One big problem with soft-float is that there are few r4 test cases in our test suite.
1381 void
1382 mono_decompose_soft_float (MonoCompile *cfg)
1384 MonoBasicBlock *bb, *first_bb;
1387 * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1391 * Create a dummy bblock and emit code into it so we can use the normal
1392 * code generation macros.
1394 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1395 first_bb = cfg->cbb;
1397 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1398 MonoInst *ins;
1399 MonoInst *prev = NULL;
1400 gboolean restart;
1402 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1404 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1405 restart = TRUE;
1407 while (restart) {
1408 restart = FALSE;
1410 for (ins = bb->code; ins; ins = ins->next) {
1411 const char *spec = INS_INFO (ins->opcode);
1413 /* Most fp operations are handled automatically by opcode emulation */
1415 switch (ins->opcode) {
1416 case OP_R8CONST: {
1417 DVal d;
1418 d.vald = *(double*)ins->inst_p0;
1419 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1420 break;
1422 case OP_R4CONST: {
1423 DVal d;
1424 /* We load the r8 value */
1425 d.vald = *(float*)ins->inst_p0;
1426 MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1427 break;
1429 case OP_FMOVE:
1430 ins->opcode = OP_LMOVE;
1431 break;
1432 case OP_FGETLOW32:
1433 ins->opcode = OP_MOVE;
1434 ins->sreg1 = ins->sreg1 + 1;
1435 break;
1436 case OP_FGETHIGH32:
1437 ins->opcode = OP_MOVE;
1438 ins->sreg1 = ins->sreg1 + 2;
1439 break;
1440 case OP_SETFRET: {
1441 int reg = ins->sreg1;
1443 ins->opcode = OP_SETLRET;
1444 ins->dreg = -1;
1445 ins->sreg1 = reg + 1;
1446 ins->sreg2 = reg + 2;
1447 break;
1449 case OP_LOADR8_MEMBASE:
1450 ins->opcode = OP_LOADI8_MEMBASE;
1451 break;
1452 case OP_STORER8_MEMBASE_REG:
1453 ins->opcode = OP_STOREI8_MEMBASE_REG;
1454 break;
1455 case OP_STORER4_MEMBASE_REG: {
1456 MonoInst *iargs [2];
1457 int addr_reg;
1459 /* Arg 1 is the double value */
1460 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1461 iargs [0]->dreg = ins->sreg1;
1463 /* Arg 2 is the address to store to */
1464 addr_reg = mono_alloc_preg (cfg);
1465 EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1466 mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1467 restart = TRUE;
1468 break;
1470 case OP_LOADR4_MEMBASE: {
1471 MonoInst *iargs [1];
1472 MonoInst *conv;
1473 int addr_reg;
1475 addr_reg = mono_alloc_preg (cfg);
1476 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1477 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1478 conv->dreg = ins->dreg;
1479 break;
1481 case OP_FCALL:
1482 case OP_FCALL_REG:
1483 case OP_FCALL_MEMBASE: {
1484 MonoCallInst *call = (MonoCallInst*)ins;
1485 if (call->signature->ret->type == MONO_TYPE_R4) {
1486 MonoCallInst *call2;
1487 MonoInst *iargs [1];
1488 MonoInst *conv;
1490 /* Convert the call into a call returning an int */
1491 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1492 memcpy (call2, call, sizeof (MonoCallInst));
1493 switch (ins->opcode) {
1494 case OP_FCALL:
1495 call2->inst.opcode = OP_CALL;
1496 break;
1497 case OP_FCALL_REG:
1498 call2->inst.opcode = OP_CALL_REG;
1499 break;
1500 case OP_FCALL_MEMBASE:
1501 call2->inst.opcode = OP_CALL_MEMBASE;
1502 break;
1503 default:
1504 g_assert_not_reached ();
1506 call2->inst.dreg = mono_alloc_ireg (cfg);
1507 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1509 /* FIXME: Optimize this */
1511 /* Emit an r4->r8 conversion */
1512 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1513 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1514 conv->dreg = ins->dreg;
1516 /* The call sequence might include fp ins */
1517 restart = TRUE;
1518 } else {
1519 switch (ins->opcode) {
1520 case OP_FCALL:
1521 ins->opcode = OP_LCALL;
1522 break;
1523 case OP_FCALL_REG:
1524 ins->opcode = OP_LCALL_REG;
1525 break;
1526 case OP_FCALL_MEMBASE:
1527 ins->opcode = OP_LCALL_MEMBASE;
1528 break;
1529 default:
1530 g_assert_not_reached ();
1533 break;
1535 case OP_FCOMPARE: {
1536 MonoJitICallInfo *info;
1537 MonoInst *iargs [2];
1538 MonoInst *call, *cmp, *br;
1540 /* Convert fcompare+fbcc to icall+icompare+beq */
1542 info = mono_find_jit_opcode_emulation (ins->next->opcode);
1543 g_assert (info);
1545 /* Create dummy MonoInst's for the arguments */
1546 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1547 iargs [0]->dreg = ins->sreg1;
1548 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1549 iargs [1]->dreg = ins->sreg2;
1551 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1553 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1554 cmp->sreg1 = call->dreg;
1555 cmp->inst_imm = 0;
1556 MONO_ADD_INS (cfg->cbb, cmp);
1558 MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1559 br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1560 br->inst_true_bb = ins->next->inst_true_bb;
1561 br->inst_false_bb = ins->next->inst_false_bb;
1562 MONO_ADD_INS (cfg->cbb, br);
1564 /* The call sequence might include fp ins */
1565 restart = TRUE;
1567 /* Skip fbcc or fccc */
1568 NULLIFY_INS (ins->next);
1569 break;
1571 case OP_FCEQ:
1572 case OP_FCGT:
1573 case OP_FCGT_UN:
1574 case OP_FCLT:
1575 case OP_FCLT_UN: {
1576 MonoJitICallInfo *info;
1577 MonoInst *iargs [2];
1578 MonoInst *call;
1580 /* Convert fccc to icall+icompare+iceq */
1582 info = mono_find_jit_opcode_emulation (ins->opcode);
1583 g_assert (info);
1585 /* Create dummy MonoInst's for the arguments */
1586 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1587 iargs [0]->dreg = ins->sreg1;
1588 MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1589 iargs [1]->dreg = ins->sreg2;
1591 call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1593 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1594 MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1596 /* The call sequence might include fp ins */
1597 restart = TRUE;
1598 break;
1600 case OP_CKFINITE: {
1601 MonoInst *iargs [2];
1602 MonoInst *call, *cmp;
1604 /* Convert to icall+icompare+cond_exc+move */
1606 /* Create dummy MonoInst's for the arguments */
1607 MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1608 iargs [0]->dreg = ins->sreg1;
1610 call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1612 MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1613 cmp->sreg1 = call->dreg;
1614 cmp->inst_imm = 1;
1615 MONO_ADD_INS (cfg->cbb, cmp);
1617 MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1619 /* Do the assignment if the value is finite */
1620 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1622 restart = TRUE;
1623 break;
1625 default:
1626 if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1627 mono_print_ins (ins);
1628 g_assert_not_reached ();
1630 break;
1633 g_assert (cfg->cbb == first_bb);
1635 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1636 /* Replace the original instruction with the new code sequence */
1638 mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1639 first_bb->code = first_bb->last_ins = NULL;
1640 first_bb->in_count = first_bb->out_count = 0;
1641 cfg->cbb = first_bb;
1643 else
1644 prev = ins;
1648 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1651 mono_decompose_long_opts (cfg);
1654 #endif
1656 #endif /* DISABLE_JIT */