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