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