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