2009-04-16 Rodrigo Kumpera <rkumpera@novell.com>
[mono.git] / mono / mini / decompose.c
1 /*
2  * decompose.c: Functions to decompose complex IR instructions into simpler ones.
3  *
4  * Author:
5  *   Zoltan Varga (vargaz@gmail.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include "mini.h"
11 #include "ir-emit.h"
12
13 #ifndef DISABLE_JIT
14
15 /* FIXME: This conflicts with the definition in mini.c, so it cannot be moved to mini.h */
16 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
17 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
18 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
19
20 /*
21  * mono_decompose_opcode:
22  *
23  *   Decompose complex opcodes into ones closer to opcodes supported by
24  * the given architecture.
25  * Returns a MonoInst which represents the result of the decomposition, and can
26  * be pushed on the IL stack. This is needed because the original instruction is
27  * nullified.
28  */
29 MonoInst*
30 mono_decompose_opcode (MonoCompile *cfg, MonoInst *ins)
31 {
32         MonoInst *repl = NULL;
33         int type = ins->type;
34         int dreg = ins->dreg;
35
36         /* FIXME: Instead of = NOP, don't emit the original ins at all */
37
38 #ifdef MONO_ARCH_HAVE_DECOMPOSE_OPTS
39         mono_arch_decompose_opts (cfg, ins);
40 #endif
41
42         /*
43          * The code below assumes that we are called immediately after emitting 
44          * ins. This means we can emit code using the normal code generation
45          * macros.
46          */
47         switch (ins->opcode) {
48         /* this doesn't make sense on ppc and other architectures */
49 #if !defined(MONO_ARCH_NO_IOV_CHECK)
50         case OP_IADD_OVF:
51                 if (COMPILE_LLVM (cfg))
52                         break;
53                 ins->opcode = OP_IADDCC;
54                 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
55                 break;
56         case OP_IADD_OVF_UN:
57                 if (COMPILE_LLVM (cfg))
58                         break;
59                 ins->opcode = OP_IADDCC;
60                 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
61                 break;
62         case OP_ISUB_OVF:
63                 if (COMPILE_LLVM (cfg))
64                         break;
65                 ins->opcode = OP_ISUBCC;
66                 MONO_EMIT_NEW_COND_EXC (cfg, IOV, "OverflowException");
67                 break;
68         case OP_ISUB_OVF_UN:
69                 if (COMPILE_LLVM (cfg))
70                         break;
71                 ins->opcode = OP_ISUBCC;
72                 MONO_EMIT_NEW_COND_EXC (cfg, IC, "OverflowException");
73                 break;
74 #endif
75         case OP_ICONV_TO_OVF_I1:
76                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
77                 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
78                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -128);
79                 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
80                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
81                 NULLIFY_INS (ins);
82                 break;
83         case OP_ICONV_TO_OVF_I1_UN:
84                 /* probe values between 0 to 127 */
85                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 127);
86                 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
87                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, ins->dreg, ins->sreg1);
88                 NULLIFY_INS (ins);
89                 break;
90         case OP_ICONV_TO_OVF_U1:
91         case OP_ICONV_TO_OVF_U1_UN:
92                 /* probe value to be within 0 to 255 */
93                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
94                 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
95                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xff);
96                 NULLIFY_INS (ins);
97                 break;
98         case OP_ICONV_TO_OVF_I2:
99                 /* Probe value to be within -32768 and 32767 */
100                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
101                 MONO_EMIT_NEW_COND_EXC (cfg, IGT, "OverflowException");
102                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, -32768);
103                 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
104                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
105                 NULLIFY_INS (ins);
106                 break;
107         case OP_ICONV_TO_OVF_I2_UN:
108                 /* Convert uint value into short, value within 0 and 32767 */
109                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 32767);
110                 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
111                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, ins->dreg, ins->sreg1);
112                 NULLIFY_INS (ins);
113                 break;
114         case OP_ICONV_TO_OVF_U2:
115         case OP_ICONV_TO_OVF_U2_UN:
116                 /* Probe value to be within 0 and 65535 */
117                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0xffff);
118                 MONO_EMIT_NEW_COND_EXC (cfg, IGT_UN, "OverflowException");
119                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, ins->dreg, ins->sreg1, 0xffff);
120                 NULLIFY_INS (ins);
121                 break;
122         case OP_ICONV_TO_OVF_U4:
123         case OP_ICONV_TO_OVF_I4_UN:
124 #if SIZEOF_REGISTER == 4
125         case OP_ICONV_TO_OVF_U:
126         case OP_ICONV_TO_OVF_I_UN:
127 #endif
128                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0);
129                 MONO_EMIT_NEW_COND_EXC (cfg, ILT, "OverflowException");
130                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
131                 NULLIFY_INS (ins);
132                 break;
133         case OP_ICONV_TO_I4:
134         case OP_ICONV_TO_U4:
135         case OP_ICONV_TO_OVF_I4:
136 #if SIZEOF_REGISTER == 4
137         case OP_ICONV_TO_OVF_I:
138         case OP_ICONV_TO_OVF_U_UN:
139 #endif
140                 ins->opcode = OP_MOVE;
141                 break;
142         case OP_ICONV_TO_I:
143 #if SIZEOF_REGISTER == 8
144                 ins->opcode = OP_SEXT_I4;
145 #else
146                 ins->opcode = OP_MOVE;
147 #endif
148                 break;
149         case OP_ICONV_TO_U:
150 #if SIZEOF_REGISTER == 8
151                 ins->opcode = OP_ZEXT_I4;
152 #else
153                 ins->opcode = OP_MOVE;
154 #endif
155                 break;
156
157         case OP_FCONV_TO_R8:
158                 ins->opcode = OP_FMOVE;
159                 break;
160
161                 /* Long opcodes on 64 bit machines */
162 #if SIZEOF_REGISTER == 8
163         case OP_LCONV_TO_I4:
164                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_LSHR_IMM, ins->dreg, ins->sreg1, 0);
165                 NULLIFY_INS (ins);
166                 break;
167         case OP_LCONV_TO_I8:
168         case OP_LCONV_TO_I:
169         case OP_LCONV_TO_U8:
170         case OP_LCONV_TO_U:
171                 ins->opcode = OP_MOVE;
172                 break;
173         case OP_ICONV_TO_I8:
174                 ins->opcode = OP_SEXT_I4;
175                 break;
176         case OP_ICONV_TO_U8:
177                 ins->opcode = OP_ZEXT_I4;
178                 break;
179         case OP_LCONV_TO_U4:
180                 /* Clean out the upper word */
181                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
182                 NULLIFY_INS (ins);
183                 break;
184 #if defined(__mono_ppc__) && !defined(__mono_ppc64__)
185         case OP_LADD_OVF:
186                 /* ADC sets the condition code */
187                 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
188                 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
189                 NULLIFY_INS (ins);
190                 g_assert_not_reached ();
191                 break;
192         case OP_LADD_OVF_UN:
193                 /* ADC sets the condition code */
194                 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
195                 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
196                 NULLIFY_INS (ins);
197                 g_assert_not_reached ();
198                 break;
199         case OP_LSUB_OVF:
200                 /* SBB sets the condition code */
201                 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
202                 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
203                 NULLIFY_INS (ins);
204                 g_assert_not_reached ();
205                 break;
206         case OP_LSUB_OVF_UN:
207                 /* SBB sets the condition code */
208                 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, ins->dreg + 1, ins->sreg1 + 1, ins->sreg2 + 1);
209                 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, ins->dreg + 2, ins->sreg1 + 2, ins->sreg2 + 2);
210                 NULLIFY_INS (ins);
211                 g_assert_not_reached ();
212                 break;
213 #else
214         case OP_LADD_OVF:
215                 if (COMPILE_LLVM (cfg))
216                         break;
217                 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
218                 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
219                 NULLIFY_INS (ins);
220                 break;
221         case OP_LADD_OVF_UN:
222                 if (COMPILE_LLVM (cfg))
223                         break;
224                 EMIT_NEW_BIALU (cfg, repl, OP_ADDCC, ins->dreg, ins->sreg1, ins->sreg2);
225                 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
226                 NULLIFY_INS (ins);
227                 break;
228 #ifndef __mono_ppc64__
229         case OP_LSUB_OVF:
230                 if (COMPILE_LLVM (cfg))
231                         break;
232                 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
233                 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
234                 NULLIFY_INS (ins);
235                 break;
236         case OP_LSUB_OVF_UN:
237                 if (COMPILE_LLVM (cfg))
238                         break;
239                 EMIT_NEW_BIALU (cfg, repl, OP_SUBCC, ins->dreg, ins->sreg1, ins->sreg2);
240                 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
241                 NULLIFY_INS (ins);
242                 break;
243 #endif
244 #endif
245                 
246         case OP_ICONV_TO_OVF_I8:
247         case OP_ICONV_TO_OVF_I:
248                 ins->opcode = OP_SEXT_I4;
249                 break;
250         case OP_ICONV_TO_OVF_U8:
251         case OP_ICONV_TO_OVF_U:
252                 MONO_EMIT_NEW_COMPARE_IMM (cfg,ins->sreg1, 0);
253                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
254                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, ins->dreg, ins->sreg1);
255                 NULLIFY_INS (ins);
256                 break;
257         case OP_ICONV_TO_OVF_I8_UN:
258         case OP_ICONV_TO_OVF_U8_UN:
259         case OP_ICONV_TO_OVF_I_UN:
260         case OP_ICONV_TO_OVF_U_UN:
261                 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
262                 /* Clean out the upper word */
263                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, ins->dreg, ins->sreg1, 0);
264                 NULLIFY_INS (ins);
265                 break;
266         case OP_LCONV_TO_OVF_I1:
267                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
268                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
269                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -128);
270                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
271                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
272                 NULLIFY_INS (ins);
273                 break;
274         case OP_LCONV_TO_OVF_I1_UN:
275                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 127);
276                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
277                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I1, ins->dreg, ins->sreg1);
278                 NULLIFY_INS (ins);
279                 break;
280         case OP_LCONV_TO_OVF_U1:
281                 /* probe value to be within 0 to 255 */
282                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
283                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
284                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
285                 NULLIFY_INS (ins);
286                 break;
287         case OP_LCONV_TO_OVF_U1_UN:
288                 /* probe value to be within 0 to 255 */
289                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 255);
290                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
291                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xff);
292                 NULLIFY_INS (ins);
293                 break;
294         case OP_LCONV_TO_OVF_I2:
295                 /* Probe value to be within -32768 and 32767 */
296                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
297                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
298                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, -32768);
299                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
300                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
301                 NULLIFY_INS (ins);
302                 break;
303         case OP_LCONV_TO_OVF_I2_UN:
304                 /* Probe value to be within 0 and 32767 */
305                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 32767);
306                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
307                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I2, ins->dreg, ins->sreg1);
308                 NULLIFY_INS (ins);
309                 break;
310         case OP_LCONV_TO_OVF_U2:
311                 /* Probe value to be within 0 and 65535 */
312                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
313                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
314                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
315                 NULLIFY_INS (ins);
316                 break;
317         case OP_LCONV_TO_OVF_U2_UN:
318                 /* Probe value to be within 0 and 65535 */
319                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffff);
320                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
321                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, ins->dreg, ins->sreg1, 0xffff);
322                 NULLIFY_INS (ins);
323                 break;
324         case OP_LCONV_TO_OVF_I4:
325                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
326                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
327                 /* The int cast is needed for the VS compiler.  See Compiler Warning (level 2) C4146. */
328                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, ((int)-2147483648));
329                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
330                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
331                 NULLIFY_INS (ins);
332                 break;
333         case OP_LCONV_TO_OVF_I4_UN:
334                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0x7fffffff);
335                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
336                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
337                 NULLIFY_INS (ins);
338                 break;
339         case OP_LCONV_TO_OVF_U4:
340                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffffUL);
341                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
342                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
343                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
344                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
345                 NULLIFY_INS (ins);
346                 break;
347         case OP_LCONV_TO_OVF_U4_UN:
348                 MONO_EMIT_NEW_COMPARE_IMM (cfg, ins->sreg1, 0xffffffff);
349                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
350                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
351                 NULLIFY_INS (ins);
352                 break;
353         case OP_LCONV_TO_OVF_I:
354         case OP_LCONV_TO_OVF_U_UN:
355         case OP_LCONV_TO_OVF_U8_UN:
356                 ins->opcode = OP_MOVE;
357                 break;
358         case OP_LCONV_TO_OVF_I_UN:
359         case OP_LCONV_TO_OVF_I8_UN:
360                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
361                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
362                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
363                 NULLIFY_INS (ins);
364                 break;
365         case OP_LCONV_TO_OVF_U8:
366         case OP_LCONV_TO_OVF_U:
367                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ins->sreg1, 0);
368                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
369                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ins->dreg, ins->sreg1);
370                 NULLIFY_INS (ins);
371                 break;
372 #endif
373
374         default: {
375                 MonoJitICallInfo *info;
376
377                 info = mono_find_jit_opcode_emulation (ins->opcode);
378                 if (info) {
379                         MonoInst **args;
380                         MonoInst *call;
381
382                         /* Create dummy MonoInst's for the arguments */
383                         g_assert (!info->sig->hasthis);
384                         g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
385
386                         args = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
387                         if (info->sig->param_count > 0) {
388                                 int sregs [MONO_MAX_SRC_REGS];
389                                 int num_sregs, i;
390                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
391                                 g_assert (num_sregs == info->sig->param_count);
392                                 for (i = 0; i < num_sregs; ++i) {
393                                         MONO_INST_NEW (cfg, args [i], OP_ARG);
394                                         args [i]->dreg = sregs [i];
395                                 }
396                         }
397
398                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
399                         call->dreg = ins->dreg;
400
401                         NULLIFY_INS (ins);
402                 }
403                 break;
404         }
405         }
406
407         if (ins->opcode == OP_NOP) {
408                 if (repl) {
409                         repl->type = type;
410                         return repl;
411                 } else {
412                         /* Use the last emitted instruction */
413                         ins = cfg->cbb->last_ins;
414                         g_assert (ins);
415                         ins->type = type;
416                         g_assert (ins->dreg == dreg);
417                         return ins;
418                 }
419         } else {
420                 return ins;
421         }
422 }
423
424 #if SIZEOF_REGISTER == 4
425 static int lbr_decomp [][2] = {
426         {0, 0}, /* BEQ */
427         {OP_IBGT, OP_IBGE_UN}, /* BGE */
428         {OP_IBGT, OP_IBGT_UN}, /* BGT */
429         {OP_IBLT, OP_IBLE_UN}, /* BLE */
430         {OP_IBLT, OP_IBLT_UN}, /* BLT */
431         {0, 0}, /* BNE_UN */
432         {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
433         {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
434         {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
435         {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
436 };
437
438 static int lcset_decomp [][2] = {
439         {0, 0}, /* CEQ */
440         {OP_IBLT, OP_IBLE_UN}, /* CGT */
441         {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
442         {OP_IBGT, OP_IBGE_UN}, /* CLT */
443         {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
444 };
445 #endif
446
447 /**
448  * mono_decompose_long_opts:
449  *
450  *  Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
451  */
452 void
453 mono_decompose_long_opts (MonoCompile *cfg)
454 {
455 #if SIZEOF_REGISTER == 4
456         MonoBasicBlock *bb, *first_bb;
457
458         /*
459          * Some opcodes, like lcall can't be decomposed so the rest of the JIT
460          * needs to be able to handle long vregs.
461          */
462
463         /* reg + 1 contains the ls word, reg + 2 contains the ms word */
464
465         /**
466          * Create a dummy bblock and emit code into it so we can use the normal 
467          * code generation macros.
468          */
469         cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
470         first_bb = cfg->cbb;
471
472         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
473                 MonoInst *tree = bb->code;      
474                 MonoInst *prev = NULL;
475
476                    /*
477                 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
478                 */
479
480                 tree = bb->code;
481                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
482
483                 while (tree) {
484
485 #ifdef MONO_ARCH_HAVE_DECOMPOSE_LONG_OPTS
486                         mono_arch_decompose_long_opts (cfg, tree);
487 #endif
488
489                         switch (tree->opcode) {
490                         case OP_I8CONST:
491                                 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, tree->inst_ls_word);
492                                 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, tree->inst_ms_word);
493                                 break;
494                         case OP_LMOVE:
495                         case OP_LCONV_TO_U8:
496                         case OP_LCONV_TO_I8:
497                         case OP_LCONV_TO_OVF_U8_UN:
498                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
499                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
500                                 break;
501                         case OP_STOREI8_MEMBASE_REG:
502                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, tree->sreg1 + 2);
503                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, tree->sreg1 + 1);
504                                 break;
505                         case OP_LOADI8_MEMBASE:
506                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 2, tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
507                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tree->dreg + 1, tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
508                                 break;
509
510                         case OP_ICONV_TO_I8: {
511                                 guint32 tmpreg = alloc_ireg (cfg);
512
513                                 /* branchless code:
514                                  * low = reg;
515                                  * tmp = low > -1 ? 1: 0;
516                                  * high = tmp - 1; if low is zero or pos high becomes 0, else -1
517                                  */
518                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
519                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, tree->dreg + 1, -1);
520                                 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
521                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, tree->dreg + 2, tmpreg, 1);
522                                 break;
523                         }
524                         case OP_ICONV_TO_U8:
525                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
526                                 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
527                                 break;
528                         case OP_ICONV_TO_OVF_I8:
529                                 /* a signed 32 bit num always fits in a signed 64 bit one */
530                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, tree->dreg + 2, tree->sreg1, 31);
531                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
532                                 break;
533                         case OP_ICONV_TO_OVF_U8:
534                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
535                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
536                                 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
537                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
538                                 break;
539                         case OP_ICONV_TO_OVF_I8_UN:
540                         case OP_ICONV_TO_OVF_U8_UN:
541                                 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
542                                 MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
543                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1);
544                                 break;
545                         case OP_LCONV_TO_I1:
546                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
547                                 break;
548                         case OP_LCONV_TO_U1:
549                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, tree->sreg1 + 1);
550                                 break;
551                         case OP_LCONV_TO_I2:
552                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
553                                 break;
554                         case OP_LCONV_TO_U2:
555                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, tree->sreg1 + 1);
556                                 break;
557                         case OP_LCONV_TO_I4:
558                         case OP_LCONV_TO_U4:
559                         case OP_LCONV_TO_I:
560                         case OP_LCONV_TO_U:
561                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
562                                 break;
563                         case OP_LCONV_TO_R8:
564                                 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
565                                 break;
566                         case OP_LCONV_TO_R4:
567                                 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
568                                 break;
569                         case OP_LCONV_TO_R_UN:
570                                 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
571                                 break;
572                         case OP_LCONV_TO_OVF_I1: {
573                                 MonoBasicBlock *is_negative, *end_label;
574
575                                 NEW_BBLOCK (cfg, is_negative);
576                                 NEW_BBLOCK (cfg, end_label);
577
578                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
579                                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
580                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
581                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
582
583                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
584                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
585
586                                 /* Positive */
587                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
588                                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
589                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
590
591                                 /* Negative */
592                                 MONO_START_BB (cfg, is_negative);
593                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
594                                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
595
596                                 MONO_START_BB (cfg, end_label);
597
598                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
599                                 break;
600                         }
601                         case OP_LCONV_TO_OVF_I1_UN:
602                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
603                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
604
605                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 127);
606                                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
607                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -128);
608                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
609                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, tree->sreg1 + 1);
610                                 break;
611                         case OP_LCONV_TO_OVF_U1:
612                         case OP_LCONV_TO_OVF_U1_UN:
613                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
614                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
615
616                                 /* probe value to be within 0 to 255 */
617                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 255);
618                                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
619                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xff);
620                                 break;
621                         case OP_LCONV_TO_OVF_I2: {
622                                 MonoBasicBlock *is_negative, *end_label;
623
624                                 NEW_BBLOCK (cfg, is_negative);
625                                 NEW_BBLOCK (cfg, end_label);
626
627                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
628                                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
629                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, -1);
630                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
631
632                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
633                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
634
635                                 /* Positive */
636                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
637                                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
638                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
639
640                                 /* Negative */
641                                 MONO_START_BB (cfg, is_negative);
642                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
643                                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
644                                 MONO_START_BB (cfg, end_label);
645
646                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
647                                 break;
648                         }
649                         case OP_LCONV_TO_OVF_I2_UN:
650                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
651                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
652
653                                 /* Probe value to be within -32768 and 32767 */
654                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 32767);
655                                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
656                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, -32768);
657                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
658                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, tree->sreg1 + 1);
659                                 break;
660                         case OP_LCONV_TO_OVF_U2:
661                         case OP_LCONV_TO_OVF_U2_UN:
662                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
663                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
664
665                                 /* Probe value to be within 0 and 65535 */
666                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1 + 1, 0xffff);
667                                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
668                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, tree->sreg1 + 1, 0xffff);
669                                 break;
670                         case OP_LCONV_TO_OVF_I4:
671                         case OP_LCONV_TO_OVF_I:
672                                 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, tree->sreg1 + 1, tree->sreg1 + 2);
673                                 break;
674                         case OP_LCONV_TO_OVF_U4:
675                         case OP_LCONV_TO_OVF_U:
676                         case OP_LCONV_TO_OVF_U4_UN:
677                         case OP_LCONV_TO_OVF_U_UN:
678                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
679                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
680                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
681                                 break;
682                         case OP_LCONV_TO_OVF_I_UN:
683                         case OP_LCONV_TO_OVF_I4_UN:
684                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
685                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
686                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 1, 0);
687                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
688                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, tree->sreg1 + 1);
689                                 break;
690                         case OP_LCONV_TO_OVF_U8:
691                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
692                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
693
694                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
695                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
696                                 break;
697                         case OP_LCONV_TO_OVF_I8_UN:
698                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tree->sreg1 + 2, 0);
699                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
700
701                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 1);
702                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 2);
703                                 break;
704
705                         case OP_LADD:
706                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
707                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
708                                 break;
709                         case OP_LSUB:
710                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
711                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
712                                 break;
713
714 #if defined(__ppc__) || defined(__powerpc__)
715                         case OP_LADD_OVF:
716                                 /* ADC sets the condition code */
717                                 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
718                                 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
719                                 break;
720                         case OP_LADD_OVF_UN:
721                                 /* ADC sets the condition code */
722                                 MONO_EMIT_NEW_BIALU (cfg, OP_ADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
723                                 MONO_EMIT_NEW_BIALU (cfg, OP_ADD_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
724                                 break;
725                         case OP_LSUB_OVF:
726                                 /* SBB sets the condition code */
727                                 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
728                                 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
729                                 break;
730                         case OP_LSUB_OVF_UN:
731                                 /* SBB sets the condition code */
732                                 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
733                                 MONO_EMIT_NEW_BIALU (cfg, OP_SUB_OVF_UN_CARRY, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
734                                 break;
735 #else
736                         case OP_LADD_OVF:
737                                 /* ADC sets the condition code */
738                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
739                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
740                                 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
741                                 break;
742                         case OP_LADD_OVF_UN:
743                                 /* ADC sets the condition code */
744                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
745                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
746                                 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
747                                 break;
748                         case OP_LSUB_OVF:
749                                 /* SBB sets the condition code */
750                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
751                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
752                                 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
753                                 break;
754                         case OP_LSUB_OVF_UN:
755                                 /* SBB sets the condition code */
756                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
757                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
758                                 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
759                                 break;
760 #endif
761                         case OP_LAND:
762                                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
763                                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
764                                 break;
765                         case OP_LOR:
766                                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
767                                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
768                                 break;
769                         case OP_LXOR:
770                                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 1, tree->sreg1 + 1, tree->sreg2 + 1);
771                                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, tree->dreg + 2, tree->sreg1 + 2, tree->sreg2 + 2);
772                                 break;
773                         case OP_LNOT:
774                                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
775                                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
776                                 break;
777                         case OP_LNEG:
778                                 /* 
779                                  * FIXME: The original version in inssel-long32.brg does not work
780                                  * on x86, and the x86 version might not work on other archs ?
781                                  */
782                                 /* FIXME: Move these to mono_arch_decompose_long_opts () */
783 #if defined(__i386__)
784                                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 1, tree->sreg1 + 1);
785                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
786                                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, tree->dreg + 2, tree->dreg + 2);
787 #elif defined(__sparc__)
788                                 MONO_EMIT_NEW_BIALU (cfg, OP_SUBCC, tree->dreg + 1, 0, tree->sreg1 + 1);
789                                 MONO_EMIT_NEW_BIALU (cfg, OP_SBB, tree->dreg + 2, 0, tree->sreg1 + 2);
790 #elif defined(__arm__)
791                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, tree->dreg + 1, tree->sreg1 + 1, 0);
792                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, tree->dreg + 2, tree->sreg1 + 2, 0);
793 #elif defined(__ppc__) || defined(__powerpc__)
794                                 /* This is the old version from inssel-long32.brg */
795                                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 1, tree->sreg1 + 1);
796                                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, tree->dreg + 2, tree->sreg1 + 2);
797                                 /* ADC sets the condition codes */
798                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 1, tree->dreg + 1, 1);
799                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->dreg + 2, 0);
800 #else
801                                 NOT_IMPLEMENTED;
802 #endif
803                                 break;
804                         case OP_LMUL:
805                                 /* Emulated */
806                                 /* FIXME: Add OP_BIGMUL optimization */
807                                 break;
808
809                         case OP_LADD_IMM:
810                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
811                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
812                                 break;
813                         case OP_LSUB_IMM:
814                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
815                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
816                                 break;
817                         case OP_LAND_IMM:
818                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
819                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
820                                 break;
821                         case OP_LOR_IMM:
822                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
823                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
824                                 break;
825                         case OP_LXOR_IMM:
826                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 1, tree->sreg1 + 1, tree->inst_ls_word);
827                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, tree->dreg + 2, tree->sreg1 + 2, tree->inst_ms_word);
828                                 break;
829                         case OP_LSHR_UN_IMM:
830                                 if (tree->inst_c1 == 32) {
831
832                                         /* The original code had this comment: */
833                                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
834                                          * later apply the speedup to the left shift as well
835                                          * See BUG# 57957.
836                                          */
837                                         /* FIXME: Move this to the strength reduction pass */
838                                         /* just move the upper half to the lower and zero the high word */
839                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 1, tree->sreg1 + 2);
840                                         MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 2, 0);
841                                 }
842                                 break;
843                         case OP_LSHL_IMM:
844                                 if (tree->inst_c1 == 32) {
845                                         /* just move the lower half to the upper and zero the lower word */
846                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg + 2, tree->sreg1 + 1);
847                                         MONO_EMIT_NEW_ICONST (cfg, tree->dreg + 1, 0);
848                                 }
849                                 break;
850
851                         case OP_LCOMPARE: {
852                                 MonoInst *next = tree->next;
853
854                                 g_assert (next);
855
856                                 switch (next->opcode) {
857                                 case OP_LBEQ:
858                                 case OP_LBNE_UN: {
859                                         int d1, d2;
860
861                                         /* Branchless version based on gcc code */
862                                         d1 = alloc_ireg (cfg);
863                                         d2 = alloc_ireg (cfg);
864                                         MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
865                                         MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
866                                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
867                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
868                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
869                                         next->opcode = OP_NOP;
870                                         break;
871                                 }
872                                 case OP_LBGE:
873                                 case OP_LBGT:
874                                 case OP_LBLE:
875                                 case OP_LBLT:
876                                 case OP_LBGE_UN:
877                                 case OP_LBGT_UN:
878                                 case OP_LBLE_UN:
879                                 case OP_LBLT_UN:
880                                         /* Convert into three comparisons + branches */
881                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
882                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
883                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
884                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
885                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
886                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
887                                         next->opcode = OP_NOP;
888                                         break;
889                                 case OP_LCEQ: {
890                                         int d1, d2;
891         
892                                         /* Branchless version based on gcc code */
893                                         d1 = alloc_ireg (cfg);
894                                         d2 = alloc_ireg (cfg);
895                                         MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, tree->sreg1 + 1, tree->sreg2 + 1);
896                                         MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, tree->sreg1 + 2, tree->sreg2 + 2);
897                                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
898
899                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
900                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
901                                         next->opcode = OP_NOP;
902                                         break;
903                                 }
904                                 case OP_LCLT:
905                                 case OP_LCLT_UN:
906                                 case OP_LCGT:
907                                 case OP_LCGT_UN: {
908                                         MonoBasicBlock *set_to_0, *set_to_1;
909         
910                                         NEW_BBLOCK (cfg, set_to_0);
911                                         NEW_BBLOCK (cfg, set_to_1);
912
913                                         MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
914                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
915                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
916                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 2, tree->sreg2 + 2);
917                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
918                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, tree->sreg1 + 1, tree->sreg2 + 1);
919                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
920                                         MONO_START_BB (cfg, set_to_1);
921                                         MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
922                                         MONO_START_BB (cfg, set_to_0);
923                                         next->opcode = OP_NOP;
924                                         break;  
925                                 }
926                                 default:
927                                         g_assert_not_reached ();
928                                 }
929                                 break;
930                         }
931
932                         /* Not yet used, since lcompare is decomposed before local cprop */
933                         case OP_LCOMPARE_IMM: {
934                                 MonoInst *next = tree->next;
935                                 guint32 low_imm = tree->inst_ls_word;
936                                 guint32 high_imm = tree->inst_ms_word;
937                                 int low_reg = tree->sreg1 + 1;
938                                 int high_reg = tree->sreg1 + 2;
939
940                                 g_assert (next);
941
942                                 switch (next->opcode) {
943                                 case OP_LBEQ:
944                                 case OP_LBNE_UN: {
945                                         int d1, d2;
946
947                                         /* Branchless version based on gcc code */
948                                         d1 = alloc_ireg (cfg);
949                                         d2 = alloc_ireg (cfg);
950                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
951                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
952                                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
953                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
954                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
955                                         next->opcode = OP_NOP;
956                                         break;
957                                 }
958
959                                 case OP_LBGE:
960                                 case OP_LBGT:
961                                 case OP_LBLE:
962                                 case OP_LBLT:
963                                 case OP_LBGE_UN:
964                                 case OP_LBGT_UN:
965                                 case OP_LBLE_UN:
966                                 case OP_LBLT_UN:
967                                         /* Convert into three comparisons + branches */
968                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
969                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
970                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
971                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
972                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
973                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
974                                         next->opcode = OP_NOP;
975                                         break;
976                                 case OP_LCEQ: {
977                                         int d1, d2;
978         
979                                         /* Branchless version based on gcc code */
980                                         d1 = alloc_ireg (cfg);
981                                         d2 = alloc_ireg (cfg);
982                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
983                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
984                                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
985
986                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
987                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
988                                         next->opcode = OP_NOP;
989                                         break;
990                                 }
991                                 case OP_LCLT:
992                                 case OP_LCLT_UN:
993                                 case OP_LCGT:
994                                 case OP_LCGT_UN: {
995                                         MonoBasicBlock *set_to_0, *set_to_1;
996         
997                                         NEW_BBLOCK (cfg, set_to_0);
998                                         NEW_BBLOCK (cfg, set_to_1);
999
1000                                         MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1001                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1002                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1003                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1004                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1005                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1006                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1007                                         MONO_START_BB (cfg, set_to_1);
1008                                         MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1009                                         MONO_START_BB (cfg, set_to_0);
1010                                         next->opcode = OP_NOP;
1011                                         break;  
1012                                 }
1013                                 default:
1014                                         g_assert_not_reached ();
1015                                 }
1016                                 break;
1017                         }
1018
1019                         default:
1020                                 break;
1021                         }
1022
1023                         if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1024                                 MonoInst *new_prev;
1025
1026                                 /* Replace the original instruction with the new code sequence */
1027
1028                                 /* Ignore the new value of prev */
1029                                 new_prev = prev;
1030                                 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1031
1032                                 /* Process the newly added ops again since they can be long ops too */
1033                                 if (prev)
1034                                         tree = prev->next;
1035                                 else
1036                                         tree = bb->code;
1037
1038                                 first_bb->code = first_bb->last_ins = NULL;
1039                                 first_bb->in_count = first_bb->out_count = 0;
1040                                 cfg->cbb = first_bb;
1041                         }
1042                         else {
1043                                 prev = tree;
1044                                 tree = tree->next;
1045                         }
1046                 }
1047         }
1048 #endif
1049
1050         /*
1051         for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1052                 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1053         */
1054 }
1055
1056 /**
1057  * mono_decompose_vtype_opts:
1058  *
1059  *  Decompose valuetype opcodes.
1060  */
1061 void
1062 mono_decompose_vtype_opts (MonoCompile *cfg)
1063 {
1064         MonoBasicBlock *bb, *first_bb;
1065
1066         /**
1067          * Using OP_V opcodes and decomposing them later have two main benefits:
1068          * - it simplifies method_to_ir () since there is no need to special-case vtypes
1069          *   everywhere.
1070          * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1071          *   enabling optimizations to work on vtypes too.
1072          * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it 
1073          * can be executed anytime. It should be executed as late as possible so vtype
1074          * opcodes can be optimized by the other passes.
1075          * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1076          * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the 
1077          * var to 1.
1078          * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass 
1079          * when OP_VMOVE opcodes are decomposed.
1080          */
1081
1082         /* 
1083          * Vregs have no associated type information, so we store the type of the vregs
1084          * in ins->klass.
1085          */
1086
1087         /**
1088          * Create a dummy bblock and emit code into it so we can use the normal 
1089          * code generation macros.
1090          */
1091         cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1092         first_bb = cfg->cbb;
1093
1094         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1095                 MonoInst *ins;
1096                 MonoInst *prev = NULL;
1097                 MonoInst *src_var, *dest_var, *src, *dest;
1098                 gboolean restart;
1099                 int dreg;
1100
1101                 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1102
1103                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1104                 restart = TRUE;
1105
1106                 while (restart) {
1107                         restart = FALSE;
1108
1109                         for (ins = bb->code; ins; ins = ins->next) {
1110                                 switch (ins->opcode) {
1111                                 case OP_VMOVE: {
1112                                         src_var = get_vreg_to_inst (cfg, ins->sreg1);
1113                                         dest_var = get_vreg_to_inst (cfg, ins->dreg);
1114
1115                                         g_assert (ins->klass);
1116
1117                                         if (!src_var)
1118                                                 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1119
1120                                         if (!dest_var)
1121                                                 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1122
1123                                         // FIXME:
1124                                         if (src_var->backend.is_pinvoke)
1125                                                 dest_var->backend.is_pinvoke = 1;
1126
1127                                         EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1128                                         EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1129
1130                                         mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1131                                         break;
1132                                 }
1133                                 case OP_VZERO:
1134                                         g_assert (ins->klass);
1135
1136                                         EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1137                                         mini_emit_initobj (cfg, dest, NULL, ins->klass);
1138                                         break;
1139                                 case OP_STOREV_MEMBASE: {
1140                                         src_var = get_vreg_to_inst (cfg, ins->sreg1);
1141
1142                                         if (!src_var) {
1143                                                 g_assert (ins->klass);
1144                                                 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1145                                         }
1146
1147                                         EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1148
1149                                         dreg = alloc_preg (cfg);
1150                                         EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1151                                         mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1152                                         break;
1153                                 }
1154                                 case OP_LOADV_MEMBASE: {
1155                                         g_assert (ins->klass);
1156
1157                                         dest_var = get_vreg_to_inst (cfg, ins->dreg);
1158                                         // FIXME:
1159                                         if (!dest_var)
1160                                                 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1161
1162                                         dreg = alloc_preg (cfg);
1163                                         EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1164                                         EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1165                                         mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1166                                         break;
1167                                 }
1168                                 case OP_OUTARG_VT: {
1169                                         g_assert (ins->klass);
1170
1171                                         src_var = get_vreg_to_inst (cfg, ins->sreg1);
1172                                         if (!src_var)
1173                                                 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1174                                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1175
1176                                         mono_arch_emit_outarg_vt (cfg, ins, src);
1177
1178                                         /* This might be decomposed into other vtype opcodes */
1179                                         restart = TRUE;
1180                                         break;
1181                                 }
1182                                 case OP_OUTARG_VTRETADDR: {
1183                                         MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1184
1185                                         src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1186                                         if (!src_var)
1187                                                 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1188                                         // FIXME: src_var->backend.is_pinvoke ?
1189
1190                                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1191                                         src->dreg = ins->dreg;
1192                                         break;
1193                                 }
1194                                 case OP_VCALL:
1195                                 case OP_VCALL_REG:
1196                                 case OP_VCALL_MEMBASE: {
1197                                         MonoCallInst *call = (MonoCallInst*)ins;
1198                                         int size;
1199
1200                                         if (call->vret_in_reg) {
1201                                                 MonoCallInst *call2;
1202
1203                                                 /* Replace the vcall with an integer call */
1204                                                 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1205                                                 memcpy (call2, call, sizeof (MonoCallInst));
1206                                                 switch (ins->opcode) {
1207                                                 case OP_VCALL:
1208                                                         call2->inst.opcode = OP_CALL;
1209                                                         break;
1210                                                 case OP_VCALL_REG:
1211                                                         call2->inst.opcode = OP_CALL_REG;
1212                                                         break;
1213                                                 case OP_VCALL_MEMBASE:
1214                                                         call2->inst.opcode = OP_CALL_MEMBASE;
1215                                                         break;
1216                                                 }
1217                                                 call2->inst.dreg = alloc_preg (cfg);
1218                                                 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1219
1220                                                 /* Compute the vtype location */
1221                                                 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1222                                                 if (!dest_var)
1223                                                         dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1224                                                 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1225
1226                                                 /* Save the result */
1227                                                 if (dest_var->backend.is_pinvoke)
1228                                                         size = mono_class_native_size (dest->inst_vtype->data.klass, NULL);
1229                                                 else
1230                                                         size = mono_type_size (dest_var->inst_vtype, NULL);
1231                                                 switch (size) {
1232                                                 case 1:
1233                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1234                                                         break;
1235                                                 case 2:
1236                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1237                                                         break;
1238                                                 case 4:
1239                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1240                                                         break;
1241                                                 case 8:
1242 #if SIZEOF_REGISTER == 4
1243                                                         /*
1244                                                         FIXME It would be nice to fix the operding of OP_CALL to make it possible to use numbering voodoo
1245                                                         FIXME It would be even nicer to be able to leverage the long decompose stuff.
1246                                                         */
1247                                                         switch (call2->inst.opcode) {
1248                                                         case OP_CALL:
1249                                                                 call2->inst.opcode = OP_LCALL;
1250                                                                 break;
1251                                                         case OP_CALL_REG:
1252                                                                 call2->inst.opcode = OP_LCALL_REG;
1253                                                                 break;
1254                                                         case OP_CALL_MEMBASE:
1255                                                                 call2->inst.opcode = OP_LCALL_MEMBASE;
1256                                                                 break;
1257                                                         }
1258                                                         call2->inst.dreg = alloc_lreg (cfg);
1259                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, call2->inst.dreg + 2);
1260                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, call2->inst.dreg + 1);
1261 #else
1262                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1263 #endif
1264                                                         break;
1265                                                 default:
1266                                                         /* This assumes the vtype is sizeof (gpointer) long */
1267                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1268                                                         break;
1269                                                 }
1270                                         } else {
1271                                                 switch (ins->opcode) {
1272                                                 case OP_VCALL:
1273                                                         ins->opcode = OP_VCALL2;
1274                                                         break;
1275                                                 case OP_VCALL_REG:
1276                                                         ins->opcode = OP_VCALL2_REG;
1277                                                         break;
1278                                                 case OP_VCALL_MEMBASE:
1279                                                         ins->opcode = OP_VCALL2_MEMBASE;
1280                                                         break;
1281                                                 }
1282                                                 ins->dreg = -1;
1283                                         }
1284                                         break;
1285                                 }
1286                                 default:
1287                                         break;
1288                                 }
1289
1290                                 g_assert (cfg->cbb == first_bb);
1291
1292                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1293                                         /* Replace the original instruction with the new code sequence */
1294
1295                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1296                                         first_bb->code = first_bb->last_ins = NULL;
1297                                         first_bb->in_count = first_bb->out_count = 0;
1298                                         cfg->cbb = first_bb;
1299                                 }
1300                                 else
1301                                         prev = ins;
1302                         }
1303                 }
1304
1305                 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1306         }
1307 }
1308
1309 #endif /* DISABLE_JIT */