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