29f2e348017cabd5ca9768b998ffcda681056d63
[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                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
1401                                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (vtable, 1);
1402
1403                                                 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1404                                                 NEW_VTABLECONST (cfg, iargs [0], vtable);
1405                                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
1406                                                 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1407                                                 iargs [1]->dreg = ins->sreg1;
1408
1409                                                 if (managed_alloc)
1410                                                         dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1411                                                 else
1412                                                         dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
1413                                                 dest->dreg = ins->dreg;
1414                                         }
1415                                         break;
1416                                 case OP_STRLEN:
1417                                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1418                                                                                                                  ins->sreg1, G_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_CONSTANT_LOAD);
1419                                         break;
1420                                 default:
1421                                         break;
1422                                 }
1423
1424                                 g_assert (cfg->cbb == first_bb);
1425
1426                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1427                                         /* Replace the original instruction with the new code sequence */
1428
1429                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1430                                         first_bb->code = first_bb->last_ins = NULL;
1431                                         first_bb->in_count = first_bb->out_count = 0;
1432                                         cfg->cbb = first_bb;
1433                                 }
1434                                 else
1435                                         prev = ins;
1436                         }
1437                 }
1438
1439                 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1440         }
1441 }
1442
1443 typedef union {
1444         guint32 vali [2];
1445         gint64 vall;
1446         double vald;
1447 } DVal;
1448
1449 #ifdef MONO_ARCH_SOFT_FLOAT
1450
1451 /**
1452  * mono_decompose_soft_float:
1453  *
1454  *  Soft float support on ARM. We store each double value in a pair of integer vregs,
1455  * similar to long support on 32 bit platforms. 32 bit float values require special
1456  * handling when used as locals, arguments, and in calls.
1457  * One big problem with soft-float is that there are few r4 test cases in our test suite.
1458  */
1459 void
1460 mono_decompose_soft_float (MonoCompile *cfg)
1461 {
1462         MonoBasicBlock *bb, *first_bb;
1463
1464         /*
1465          * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1466          */
1467
1468         /**
1469          * Create a dummy bblock and emit code into it so we can use the normal 
1470          * code generation macros.
1471          */
1472         cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1473         first_bb = cfg->cbb;
1474
1475         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1476                 MonoInst *ins;
1477                 MonoInst *prev = NULL;
1478                 gboolean restart;
1479
1480                 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1481
1482                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1483                 restart = TRUE;
1484
1485                 while (restart) {
1486                         restart = FALSE;
1487
1488                         for (ins = bb->code; ins; ins = ins->next) {
1489                                 const char *spec = INS_INFO (ins->opcode);
1490
1491                                 /* Most fp operations are handled automatically by opcode emulation */
1492
1493                                 switch (ins->opcode) {
1494                                 case OP_R8CONST: {
1495                                         DVal d;
1496                                         d.vald = *(double*)ins->inst_p0;
1497                                         MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1498                                         break;
1499                                 }
1500                                 case OP_R4CONST: {
1501                                         DVal d;
1502                                         /* We load the r8 value */
1503                                         d.vald = *(float*)ins->inst_p0;
1504                                         MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1505                                         break;
1506                                 }
1507                                 case OP_FMOVE:
1508                                         ins->opcode = OP_LMOVE;
1509                                         break;
1510                                 case OP_FGETLOW32:
1511                                         ins->opcode = OP_MOVE;
1512                                         ins->sreg1 = ins->sreg1 + 1;
1513                                         break;
1514                                 case OP_FGETHIGH32:
1515                                         ins->opcode = OP_MOVE;
1516                                         ins->sreg1 = ins->sreg1 + 2;
1517                                         break;
1518                                 case OP_SETFRET: {
1519                                         int reg = ins->sreg1;
1520
1521                                         ins->opcode = OP_SETLRET;
1522                                         ins->dreg = -1;
1523                                         ins->sreg1 = reg + 1;
1524                                         ins->sreg2 = reg + 2;
1525                                         break;
1526                                 }
1527                                 case OP_LOADR8_MEMBASE:
1528                                         ins->opcode = OP_LOADI8_MEMBASE;
1529                                         break;
1530                                 case OP_STORER8_MEMBASE_REG:
1531                                         ins->opcode = OP_STOREI8_MEMBASE_REG;
1532                                         break;
1533                                 case OP_STORER4_MEMBASE_REG: {
1534                                         MonoInst *iargs [2];
1535                                         int addr_reg;
1536
1537                                         /* Arg 1 is the double value */
1538                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1539                                         iargs [0]->dreg = ins->sreg1;
1540
1541                                         /* Arg 2 is the address to store to */
1542                                         addr_reg = mono_alloc_preg (cfg);
1543                                         EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1544                                         mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1545                                         restart = TRUE;
1546                                         break;
1547                                 }
1548                                 case OP_LOADR4_MEMBASE: {
1549                                         MonoInst *iargs [1];
1550                                         MonoInst *conv;
1551                                         int addr_reg;
1552
1553                                         addr_reg = mono_alloc_preg (cfg);
1554                                         EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1555                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1556                                         conv->dreg = ins->dreg;
1557                                         break;
1558                                 }                                       
1559                                 case OP_FCALL:
1560                                 case OP_FCALL_REG:
1561                                 case OP_FCALL_MEMBASE: {
1562                                         MonoCallInst *call = (MonoCallInst*)ins;
1563                                         if (call->signature->ret->type == MONO_TYPE_R4) {
1564                                                 MonoCallInst *call2;
1565                                                 MonoInst *iargs [1];
1566                                                 MonoInst *conv;
1567                                                 GSList *l;
1568
1569                                                 /* Convert the call into a call returning an int */
1570                                                 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1571                                                 memcpy (call2, call, sizeof (MonoCallInst));
1572                                                 switch (ins->opcode) {
1573                                                 case OP_FCALL:
1574                                                         call2->inst.opcode = OP_CALL;
1575                                                         break;
1576                                                 case OP_FCALL_REG:
1577                                                         call2->inst.opcode = OP_CALL_REG;
1578                                                         break;
1579                                                 case OP_FCALL_MEMBASE:
1580                                                         call2->inst.opcode = OP_CALL_MEMBASE;
1581                                                         break;
1582                                                 default:
1583                                                         g_assert_not_reached ();
1584                                                 }
1585                                                 call2->inst.dreg = mono_alloc_ireg (cfg);
1586                                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1587
1588                                                 /* Remap OUTARG_VT instructions referencing this call */
1589                                                 for (l = call->outarg_vts; l; l = l->next)
1590                                                         ((MonoInst*)(l->data))->inst_p0 = call2;
1591
1592                                                 /* FIXME: Optimize this */
1593
1594                                                 /* Emit an r4->r8 conversion */
1595                                                 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1596                                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1597                                                 conv->dreg = ins->dreg;
1598
1599                                                 /* The call sequence might include fp ins */
1600                                                 restart = TRUE;
1601                                         } else {
1602                                                 switch (ins->opcode) {
1603                                                 case OP_FCALL:
1604                                                         ins->opcode = OP_LCALL;
1605                                                         break;
1606                                                 case OP_FCALL_REG:
1607                                                         ins->opcode = OP_LCALL_REG;
1608                                                         break;
1609                                                 case OP_FCALL_MEMBASE:
1610                                                         ins->opcode = OP_LCALL_MEMBASE;
1611                                                         break;
1612                                                 default:
1613                                                         g_assert_not_reached ();
1614                                                 }
1615                                         }
1616                                         break;
1617                                 }
1618                                 case OP_FCOMPARE: {
1619                                         MonoJitICallInfo *info;
1620                                         MonoInst *iargs [2];
1621                                         MonoInst *call, *cmp, *br;
1622
1623                                         /* Convert fcompare+fbcc to icall+icompare+beq */
1624
1625                                         if (!ins->next) {
1626                                                 /* The branch might be optimized away */
1627                                                 NULLIFY_INS (ins);
1628                                                 break;
1629                                         }
1630
1631                                         info = mono_find_jit_opcode_emulation (ins->next->opcode);
1632                                         if (!info) {
1633                                                 /* The branch might be optimized away */
1634                                                 NULLIFY_INS (ins);
1635                                                 break;
1636                                         }
1637
1638                                         /* Create dummy MonoInst's for the arguments */
1639                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1640                                         iargs [0]->dreg = ins->sreg1;
1641                                         MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1642                                         iargs [1]->dreg = ins->sreg2;
1643
1644                                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1645
1646                                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1647                                         cmp->sreg1 = call->dreg;
1648                                         cmp->inst_imm = 0;
1649                                         MONO_ADD_INS (cfg->cbb, cmp);
1650                                         
1651                                         MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1652                                         br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1653                                         br->inst_true_bb = ins->next->inst_true_bb;
1654                                         br->inst_false_bb = ins->next->inst_false_bb;
1655                                         MONO_ADD_INS (cfg->cbb, br);
1656
1657                                         /* The call sequence might include fp ins */
1658                                         restart = TRUE;
1659
1660                                         /* Skip fbcc or fccc */
1661                                         NULLIFY_INS (ins->next);
1662                                         break;
1663                                 }
1664                                 case OP_FCEQ:
1665                                 case OP_FCGT:
1666                                 case OP_FCGT_UN:
1667                                 case OP_FCLT:
1668                                 case OP_FCLT_UN: {
1669                                         MonoJitICallInfo *info;
1670                                         MonoInst *iargs [2];
1671                                         MonoInst *call;
1672
1673                                         /* Convert fccc to icall+icompare+iceq */
1674
1675                                         info = mono_find_jit_opcode_emulation (ins->opcode);
1676                                         g_assert (info);
1677
1678                                         /* Create dummy MonoInst's for the arguments */
1679                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1680                                         iargs [0]->dreg = ins->sreg1;
1681                                         MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1682                                         iargs [1]->dreg = ins->sreg2;
1683
1684                                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1685
1686                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1687                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1688
1689                                         /* The call sequence might include fp ins */
1690                                         restart = TRUE;
1691                                         break;
1692                                 }
1693                                 case OP_CKFINITE: {
1694                                         MonoInst *iargs [2];
1695                                         MonoInst *call, *cmp;
1696
1697                                         /* Convert to icall+icompare+cond_exc+move */
1698
1699                                         /* Create dummy MonoInst's for the arguments */
1700                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1701                                         iargs [0]->dreg = ins->sreg1;
1702
1703                                         call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1704
1705                                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1706                                         cmp->sreg1 = call->dreg;
1707                                         cmp->inst_imm = 1;
1708                                         MONO_ADD_INS (cfg->cbb, cmp);
1709
1710                                         MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1711
1712                                         /* Do the assignment if the value is finite */
1713                                         MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1714
1715                                         restart = TRUE;
1716                                         break;
1717                                 }
1718                                 default:
1719                                         if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1720                                                 mono_print_ins (ins);
1721                                                 g_assert_not_reached ();
1722                                         }
1723                                         break;
1724                                 }
1725
1726                                 g_assert (cfg->cbb == first_bb);
1727
1728                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1729                                         /* Replace the original instruction with the new code sequence */
1730
1731                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1732                                         first_bb->code = first_bb->last_ins = NULL;
1733                                         first_bb->in_count = first_bb->out_count = 0;
1734                                         cfg->cbb = first_bb;
1735                                 }
1736                                 else
1737                                         prev = ins;
1738                         }
1739                 }
1740
1741                 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1742         }
1743
1744         mono_decompose_long_opts (cfg);
1745 }
1746
1747 #endif
1748
1749 #endif /* DISABLE_JIT */