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