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