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