[sgen] Fix logging of major heap size with concurrent sweep
[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                 mono_cfg_set_exception_invalid_program (cfg, g_strdup_printf ("float conv.ovf.un opcodes not supported."));
443                 break;
444
445         case OP_IDIV:
446         case OP_IREM:
447         case OP_IDIV_UN:
448         case OP_IREM_UN:
449                 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
450                         emulate = TRUE;
451                 if (!emulate) {
452                         if (cfg->backend->need_div_check) {
453                                 int reg1 = alloc_ireg (cfg);
454                                 int reg2 = alloc_ireg (cfg);
455                                 /* b == 0 */
456                                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, 0);
457                                 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
458                                 if (ins->opcode == OP_IDIV || ins->opcode == OP_IREM) {
459                                         /* b == -1 && a == 0x80000000 */
460                                         MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg2, -1);
461                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg1, -1);
462                                         MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
463                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, reg2, -1);
464                                         MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
465                                         MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
466                                         MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
467                                 }
468                         }
469                         MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
470                         NULLIFY_INS (ins);
471                 }
472                 break;
473
474 #if SIZEOF_VOID_P == 8
475         case OP_LDIV:
476         case OP_LREM:
477         case OP_LDIV_UN:
478         case OP_LREM_UN:
479                 if (cfg->backend->emulate_div && mono_arch_opcode_needs_emulation (cfg, ins->opcode))
480                         emulate = TRUE;
481                 if (!emulate) {
482                         if (cfg->backend->need_div_check) {
483                                 int reg1 = alloc_ireg (cfg);
484                                 int reg2 = alloc_ireg (cfg);
485                                 int reg3 = alloc_ireg (cfg);
486                                 /* b == 0 */
487                                 MONO_EMIT_NEW_LCOMPARE_IMM (cfg, ins->sreg2, 0);
488                                 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
489                                 if (ins->opcode == OP_LDIV || ins->opcode == OP_LREM) {
490                                         /* b == -1 && a == 0x80000000 */
491                                         MONO_EMIT_NEW_I8CONST (cfg, reg3, -1);
492                                         MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg2, reg3);
493                                         MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg1, -1);
494                                         MONO_EMIT_NEW_I8CONST (cfg, reg3, 0x8000000000000000L);
495                                         MONO_EMIT_NEW_BIALU (cfg, OP_LCOMPARE, -1, ins->sreg1, reg3);
496                                         MONO_EMIT_NEW_UNALU (cfg, OP_LCEQ, reg2, -1);
497                                         MONO_EMIT_NEW_BIALU (cfg, OP_IAND, reg1, reg1, reg2);
498                                         MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 1);
499                                         MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
500                                 }
501                         }
502                         MONO_EMIT_NEW_BIALU (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->sreg2);
503                         NULLIFY_INS (ins);
504                 }
505                 break;
506 #endif
507
508         case OP_DIV_IMM:
509         case OP_REM_IMM:
510         case OP_IDIV_IMM:
511         case OP_IREM_IMM:
512         case OP_IDIV_UN_IMM:
513         case OP_IREM_UN_IMM:
514                 if (cfg->backend->need_div_check) {
515                         int reg1 = alloc_ireg (cfg);
516                         /* b == 0 */
517                         if (ins->inst_imm == 0) {
518                                 // FIXME: Optimize this
519                                 MONO_EMIT_NEW_ICONST (cfg, reg1, 0);
520                                 MONO_EMIT_NEW_ICOMPARE_IMM (cfg, reg1, 0);
521                                 MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "DivideByZeroException");
522                         }
523                         if ((ins->opcode == OP_DIV_IMM || ins->opcode == OP_IDIV_IMM || ins->opcode == OP_REM_IMM || ins->opcode == OP_IREM_IMM) &&
524                                 (ins->inst_imm == -1)) {
525                                         /* b == -1 && a == 0x80000000 */
526                                         MONO_EMIT_NEW_ICOMPARE_IMM (cfg, ins->sreg1, 0x80000000);
527                                         MONO_EMIT_NEW_COND_EXC (cfg, IEQ, "OverflowException");
528                         }
529                         MONO_EMIT_NEW_BIALU_IMM (cfg, ins->opcode, ins->dreg, ins->sreg1, ins->inst_imm);
530                         NULLIFY_INS (ins);
531                 } else {
532                         emulate = TRUE;
533                 }
534                 break;
535
536         default:
537                 emulate = TRUE;
538                 break;
539         }
540
541         if (emulate) {
542 #if SIZEOF_REGISTER == 8
543                 if (decompose_long_opcode (cfg, ins, &repl))
544                         emulate = FALSE;
545 #else
546                 if (COMPILE_LLVM (cfg) && decompose_long_opcode (cfg, ins, &repl))
547                         emulate = FALSE;
548 #endif
549
550                 if (emulate && mono_find_jit_opcode_emulation (ins->opcode))
551                         cfg->has_emulated_ops = TRUE;
552         }
553
554         if (ins->opcode == OP_NOP) {
555                 if (repl) {
556                         repl->type = type;
557                         return repl;
558                 } else {
559                         /* Use the last emitted instruction */
560                         ins = cfg->cbb->last_ins;
561                         g_assert (ins);
562                         ins->type = type;
563                         g_assert (ins->dreg == dreg);
564                         return ins;
565                 }
566         } else {
567                 return ins;
568         }
569 }
570
571 #if SIZEOF_REGISTER == 4
572 static int lbr_decomp [][2] = {
573         {0, 0}, /* BEQ */
574         {OP_IBGT, OP_IBGE_UN}, /* BGE */
575         {OP_IBGT, OP_IBGT_UN}, /* BGT */
576         {OP_IBLT, OP_IBLE_UN}, /* BLE */
577         {OP_IBLT, OP_IBLT_UN}, /* BLT */
578         {0, 0}, /* BNE_UN */
579         {OP_IBGT_UN, OP_IBGE_UN}, /* BGE_UN */
580         {OP_IBGT_UN, OP_IBGT_UN}, /* BGT_UN */
581         {OP_IBLT_UN, OP_IBLE_UN}, /* BLE_UN */
582         {OP_IBLT_UN, OP_IBLT_UN}, /* BLT_UN */
583 };
584
585 static int lcset_decomp [][2] = {
586         {0, 0}, /* CEQ */
587         {OP_IBLT, OP_IBLE_UN}, /* CGT */
588         {OP_IBLT_UN, OP_IBLE_UN}, /* CGT_UN */
589         {OP_IBGT, OP_IBGE_UN}, /* CLT */
590         {OP_IBGT_UN, OP_IBGE_UN}, /* CLT_UN */
591 };
592 #endif
593
594 /**
595  * mono_decompose_long_opts:
596  *
597  *  Decompose 64bit opcodes into 32bit opcodes on 32 bit platforms.
598  */
599 void
600 mono_decompose_long_opts (MonoCompile *cfg)
601 {
602 #if SIZEOF_REGISTER == 4
603         MonoBasicBlock *bb, *first_bb;
604
605         /*
606          * Some opcodes, like lcall can't be decomposed so the rest of the JIT
607          * needs to be able to handle long vregs.
608          */
609
610         /**
611          * Create a dummy bblock and emit code into it so we can use the normal 
612          * code generation macros.
613          */
614         cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
615         first_bb = cfg->cbb;
616
617         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
618                 MonoInst *tree = mono_bb_first_inst(bb, FILTER_IL_SEQ_POINT);
619                 MonoInst *prev = NULL;
620
621                    /*
622                 mono_print_bb (bb, "BEFORE LOWER_LONG_OPTS");
623                 */
624
625                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
626
627                 while (tree) {
628                         mono_arch_decompose_long_opts (cfg, tree);
629
630                         switch (tree->opcode) {
631                         case OP_I8CONST:
632                                 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), tree->inst_ls_word);
633                                 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), tree->inst_ms_word);
634                                 break;
635                         case OP_DUMMY_I8CONST:
636                                 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_LS (tree->dreg), OP_DUMMY_ICONST);
637                                 MONO_EMIT_NEW_DUMMY_INIT (cfg, MONO_LVREG_MS (tree->dreg), OP_DUMMY_ICONST);
638                                 break;
639                         case OP_LMOVE:
640                         case OP_LCONV_TO_U8:
641                         case OP_LCONV_TO_I8:
642                         case OP_LCONV_TO_OVF_U8_UN:
643                         case OP_LCONV_TO_OVF_I8:
644                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
645                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
646                                 break;
647                         case OP_STOREI8_MEMBASE_REG:
648                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_MS_WORD_OFFSET, MONO_LVREG_MS (tree->sreg1));
649                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, tree->inst_destbasereg, tree->inst_offset + MINI_LS_WORD_OFFSET, MONO_LVREG_LS (tree->sreg1));
650                                 break;
651                         case OP_LOADI8_MEMBASE:
652                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_MS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_MS_WORD_OFFSET);
653                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, MONO_LVREG_LS (tree->dreg), tree->inst_basereg, tree->inst_offset + MINI_LS_WORD_OFFSET);
654                                 break;
655
656                         case OP_ICONV_TO_I8: {
657                                 guint32 tmpreg = alloc_ireg (cfg);
658
659                                 /* branchless code:
660                                  * low = reg;
661                                  * tmp = low > -1 ? 1: 0;
662                                  * high = tmp - 1; if low is zero or pos high becomes 0, else -1
663                                  */
664                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
665                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, MONO_LVREG_LS (tree->dreg), -1);
666                                 MONO_EMIT_NEW_BIALU (cfg, OP_ICGT, tmpreg, -1, -1);
667                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, MONO_LVREG_MS (tree->dreg), tmpreg, 1);
668                                 break;
669                         }
670                         case OP_ICONV_TO_U8:
671                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
672                                 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
673                                 break;
674                         case OP_ICONV_TO_OVF_I8:
675                                 /* a signed 32 bit num always fits in a signed 64 bit one */
676                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, MONO_LVREG_MS (tree->dreg), tree->sreg1, 31);
677                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
678                                 break;
679                         case OP_ICONV_TO_OVF_U8:
680                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, tree->sreg1, 0);
681                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
682                                 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
683                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
684                                 break;
685                         case OP_ICONV_TO_OVF_I8_UN:
686                         case OP_ICONV_TO_OVF_U8_UN:
687                                 /* an unsigned 32 bit num always fits in an (un)signed 64 bit one */
688                                 MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
689                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), tree->sreg1);
690                                 break;
691                         case OP_LCONV_TO_I1:
692                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
693                                 break;
694                         case OP_LCONV_TO_U1:
695                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
696                                 break;
697                         case OP_LCONV_TO_I2:
698                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
699                                 break;
700                         case OP_LCONV_TO_U2:
701                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_U2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
702                                 break;
703                         case OP_LCONV_TO_I4:
704                         case OP_LCONV_TO_U4:
705                         case OP_LCONV_TO_I:
706                         case OP_LCONV_TO_U:
707                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
708                                 break;
709 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8
710                         case OP_LCONV_TO_R8:
711                                 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R8_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
712                                 break;
713 #endif
714 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R4
715                         case OP_LCONV_TO_R4:
716                                 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
717                                 break;
718 #endif
719 #ifndef MONO_ARCH_EMULATE_LCONV_TO_R8_UN
720                         case OP_LCONV_TO_R_UN:
721                                 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_R_UN_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
722                                 break;
723 #endif
724                         case OP_LCONV_TO_OVF_I1: {
725                                 MonoBasicBlock *is_negative, *end_label;
726
727                                 NEW_BBLOCK (cfg, is_negative);
728                                 NEW_BBLOCK (cfg, end_label);
729
730                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
731                                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
732                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
733                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
734
735                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
736                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
737
738                                 /* Positive */
739                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
740                                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
741                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
742
743                                 /* Negative */
744                                 MONO_START_BB (cfg, is_negative);
745                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
746                                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
747
748                                 MONO_START_BB (cfg, end_label);
749
750                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
751                                 break;
752                         }
753                         case OP_LCONV_TO_OVF_I1_UN:
754                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
755                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
756
757                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 127);
758                                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
759                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -128);
760                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
761                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I1, tree->dreg, MONO_LVREG_LS (tree->sreg1));
762                                 break;
763                         case OP_LCONV_TO_OVF_U1:
764                         case OP_LCONV_TO_OVF_U1_UN:
765                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
766                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
767
768                                 /* probe value to be within 0 to 255 */
769                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 255);
770                                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
771                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xff);
772                                 break;
773                         case OP_LCONV_TO_OVF_I2: {
774                                 MonoBasicBlock *is_negative, *end_label;
775
776                                 NEW_BBLOCK (cfg, is_negative);
777                                 NEW_BBLOCK (cfg, end_label);
778
779                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
780                                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
781                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), -1);
782                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
783
784                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
785                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBLT, is_negative);
786
787                                 /* Positive */
788                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
789                                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
790                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_label);
791
792                                 /* Negative */
793                                 MONO_START_BB (cfg, is_negative);
794                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
795                                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "OverflowException");
796                                 MONO_START_BB (cfg, end_label);
797
798                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
799                                 break;
800                         }
801                         case OP_LCONV_TO_OVF_I2_UN:
802                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
803                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
804
805                                 /* Probe value to be within -32768 and 32767 */
806                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 32767);
807                                 MONO_EMIT_NEW_COND_EXC (cfg, GT, "OverflowException");
808                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), -32768);
809                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
810                                 MONO_EMIT_NEW_UNALU (cfg, OP_ICONV_TO_I2, tree->dreg, MONO_LVREG_LS (tree->sreg1));
811                                 break;
812                         case OP_LCONV_TO_OVF_U2:
813                         case OP_LCONV_TO_OVF_U2_UN:
814                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
815                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
816
817                                 /* Probe value to be within 0 and 65535 */
818                                 MONO_EMIT_NEW_COMPARE_IMM (cfg, MONO_LVREG_LS (tree->sreg1), 0xffff);
819                                 MONO_EMIT_NEW_COND_EXC (cfg, GT_UN, "OverflowException");
820                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, tree->dreg, MONO_LVREG_LS (tree->sreg1), 0xffff);
821                                 break;
822                         case OP_LCONV_TO_OVF_I4:
823                         case OP_LCONV_TO_OVF_I:
824                                 MONO_EMIT_NEW_BIALU (cfg, OP_LCONV_TO_OVF_I4_2, tree->dreg, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_MS (tree->sreg1));
825                                 break;
826                         case OP_LCONV_TO_OVF_U4:
827                         case OP_LCONV_TO_OVF_U:
828                         case OP_LCONV_TO_OVF_U4_UN:
829                         case OP_LCONV_TO_OVF_U_UN:
830                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
831                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
832                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
833                                 break;
834                         case OP_LCONV_TO_OVF_I_UN:
835                         case OP_LCONV_TO_OVF_I4_UN:
836                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
837                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "OverflowException");
838                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_LS (tree->sreg1), 0);
839                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
840                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, tree->dreg, MONO_LVREG_LS (tree->sreg1));
841                                 break;
842                         case OP_LCONV_TO_OVF_U8:
843                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
844                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
845
846                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
847                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
848                                 break;
849                         case OP_LCONV_TO_OVF_I8_UN:
850                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, MONO_LVREG_MS (tree->sreg1), 0);
851                                 MONO_EMIT_NEW_COND_EXC (cfg, LT, "OverflowException");
852
853                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
854                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
855                                 break;
856
857                         case OP_LADD:
858                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
859                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
860                                 break;
861                         case OP_LSUB:
862                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
863                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
864                                 break;
865
866                         case OP_LADD_OVF:
867                                 /* ADC sets the condition code */
868                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
869                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
870                                 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
871                                 break;
872                         case OP_LADD_OVF_UN:
873                                 /* ADC sets the condition code */
874                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADDCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
875                                 MONO_EMIT_NEW_BIALU (cfg, OP_IADC, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
876                                 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
877                                 break;
878                         case OP_LSUB_OVF:
879                                 /* SBB sets the condition code */
880                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
881                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
882                                 MONO_EMIT_NEW_COND_EXC (cfg, OV, "OverflowException");
883                                 break;
884                         case OP_LSUB_OVF_UN:
885                                 /* SBB sets the condition code */
886                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISUBCC, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
887                                 MONO_EMIT_NEW_BIALU (cfg, OP_ISBB, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
888                                 MONO_EMIT_NEW_COND_EXC (cfg, C, "OverflowException");
889                                 break;
890                         case OP_LAND:
891                                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
892                                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
893                                 break;
894                         case OP_LOR:
895                                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
896                                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
897                                 break;
898                         case OP_LXOR:
899                                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
900                                 MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
901                                 break;
902                         case OP_LNOT:
903                                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
904                                 MONO_EMIT_NEW_UNALU (cfg, OP_INOT, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
905                                 break;
906                         case OP_LNEG:
907                                 /* Handled in mono_arch_decompose_long_opts () */
908                                 g_assert_not_reached ();
909                                 break;
910                         case OP_LMUL:
911                                 /* Emulated */
912                                 /* FIXME: Add OP_BIGMUL optimization */
913                                 break;
914
915                         case OP_LADD_IMM:
916                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADDCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
917                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
918                                 break;
919                         case OP_LSUB_IMM:
920                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUBCC_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
921                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SBB_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
922                                 break;
923                         case OP_LAND_IMM:
924                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
925                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
926                                 break;
927                         case OP_LOR_IMM:
928                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
929                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_OR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
930                                 break;
931                         case OP_LXOR_IMM:
932                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_LS (tree->dreg), MONO_LVREG_LS (tree->sreg1), tree->inst_ls_word);
933                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_XOR_IMM, MONO_LVREG_MS (tree->dreg), MONO_LVREG_MS (tree->sreg1), tree->inst_ms_word);
934                                 break;
935                         case OP_LSHR_UN_IMM:
936                                 if (tree->inst_c1 == 32) {
937
938                                         /* The original code had this comment: */
939                                         /* special case that gives a nice speedup and happens to workaorund a ppc jit but (for the release)
940                                          * later apply the speedup to the left shift as well
941                                          * See BUG# 57957.
942                                          */
943                                         /* FIXME: Move this to the strength reduction pass */
944                                         /* just move the upper half to the lower and zero the high word */
945                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_LS (tree->dreg), MONO_LVREG_MS (tree->sreg1));
946                                         MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_MS (tree->dreg), 0);
947                                 }
948                                 break;
949                         case OP_LSHL_IMM:
950                                 if (tree->inst_c1 == 32) {
951                                         /* just move the lower half to the upper and zero the lower word */
952                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, MONO_LVREG_MS (tree->dreg), MONO_LVREG_LS (tree->sreg1));
953                                         MONO_EMIT_NEW_ICONST (cfg, MONO_LVREG_LS (tree->dreg), 0);
954                                 }
955                                 break;
956
957                         case OP_LCOMPARE: {
958                                 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
959
960                                 g_assert (next);
961
962                                 switch (next->opcode) {
963                                 case OP_LBEQ:
964                                 case OP_LBNE_UN: {
965                                         int d1, d2;
966
967                                         /* Branchless version based on gcc code */
968                                         d1 = alloc_ireg (cfg);
969                                         d2 = alloc_ireg (cfg);
970                                         MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
971                                         MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
972                                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
973                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
974                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
975                                         NULLIFY_INS (next);
976                                         break;
977                                 }
978                                 case OP_LBGE:
979                                 case OP_LBGT:
980                                 case OP_LBLE:
981                                 case OP_LBLT:
982                                 case OP_LBGE_UN:
983                                 case OP_LBGT_UN:
984                                 case OP_LBLE_UN:
985                                 case OP_LBLT_UN:
986                                         /* Convert into three comparisons + branches */
987                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
988                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
989                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
990                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
991                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
992                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
993                                         NULLIFY_INS (next);
994                                         break;
995                                 case OP_LCEQ: {
996                                         int d1, d2;
997         
998                                         /* Branchless version based on gcc code */
999                                         d1 = alloc_ireg (cfg);
1000                                         d2 = alloc_ireg (cfg);
1001                                         MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1002                                         MONO_EMIT_NEW_BIALU (cfg, OP_IXOR, d2, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1003                                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1004
1005                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1006                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1007                                         NULLIFY_INS (next);
1008                                         break;
1009                                 }
1010                                 case OP_LCLT:
1011                                 case OP_LCLT_UN:
1012                                 case OP_LCGT:
1013                                 case OP_LCGT_UN: {
1014                                         MonoBasicBlock *set_to_0, *set_to_1;
1015         
1016                                         NEW_BBLOCK (cfg, set_to_0);
1017                                         NEW_BBLOCK (cfg, set_to_1);
1018
1019                                         MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1020                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1021                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1022                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_MS (tree->sreg1), MONO_LVREG_MS (tree->sreg2));
1023                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1024                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, MONO_LVREG_LS (tree->sreg1), MONO_LVREG_LS (tree->sreg2));
1025                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1026                                         MONO_START_BB (cfg, set_to_1);
1027                                         MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1028                                         MONO_START_BB (cfg, set_to_0);
1029                                         NULLIFY_INS (next);
1030                                         break;  
1031                                 }
1032                                 default:
1033                                         g_assert_not_reached ();
1034                                 }
1035                                 break;
1036                         }
1037
1038                         /* Not yet used, since lcompare is decomposed before local cprop */
1039                         case OP_LCOMPARE_IMM: {
1040                                 MonoInst *next = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1041                                 guint32 low_imm = tree->inst_ls_word;
1042                                 guint32 high_imm = tree->inst_ms_word;
1043                                 int low_reg = MONO_LVREG_LS (tree->sreg1);
1044                                 int high_reg = MONO_LVREG_MS (tree->sreg1);
1045
1046                                 g_assert (next);
1047
1048                                 switch (next->opcode) {
1049                                 case OP_LBEQ:
1050                                 case OP_LBNE_UN: {
1051                                         int d1, d2;
1052
1053                                         /* Branchless version based on gcc code */
1054                                         d1 = alloc_ireg (cfg);
1055                                         d2 = alloc_ireg (cfg);
1056                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1057                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1058                                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1059                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1060                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, next->opcode == OP_LBEQ ? OP_IBEQ : OP_IBNE_UN, next->inst_true_bb, next->inst_false_bb);
1061                                         NULLIFY_INS (next);
1062                                         break;
1063                                 }
1064
1065                                 case OP_LBGE:
1066                                 case OP_LBGT:
1067                                 case OP_LBLE:
1068                                 case OP_LBLT:
1069                                 case OP_LBGE_UN:
1070                                 case OP_LBGT_UN:
1071                                 case OP_LBLE_UN:
1072                                 case OP_LBLT_UN:
1073                                         /* Convert into three comparisons + branches */
1074                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1075                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lbr_decomp [next->opcode - OP_LBEQ][0], next->inst_true_bb);
1076                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1077                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, next->inst_false_bb);
1078                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1079                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, lbr_decomp [next->opcode - OP_LBEQ][1], next->inst_true_bb, next->inst_false_bb);
1080                                         NULLIFY_INS (next);
1081                                         break;
1082                                 case OP_LCEQ: {
1083                                         int d1, d2;
1084         
1085                                         /* Branchless version based on gcc code */
1086                                         d1 = alloc_ireg (cfg);
1087                                         d2 = alloc_ireg (cfg);
1088                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d1, low_reg, low_imm);
1089                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IXOR_IMM, d2, high_reg, high_imm);
1090                                         MONO_EMIT_NEW_BIALU (cfg, OP_IOR, d1, d1, d2);
1091
1092                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, d1, 0);
1093                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, next->dreg, -1);
1094                                         NULLIFY_INS (next);
1095                                         break;
1096                                 }
1097                                 case OP_LCLT:
1098                                 case OP_LCLT_UN:
1099                                 case OP_LCGT:
1100                                 case OP_LCGT_UN: {
1101                                         MonoBasicBlock *set_to_0, *set_to_1;
1102         
1103                                         NEW_BBLOCK (cfg, set_to_0);
1104                                         NEW_BBLOCK (cfg, set_to_1);
1105
1106                                         MONO_EMIT_NEW_ICONST (cfg, next->dreg, 0);
1107                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1108                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][0], set_to_0);
1109                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, high_reg, high_imm);
1110                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, set_to_1);
1111                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, low_reg, low_imm);
1112                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, lcset_decomp [next->opcode - OP_LCEQ][1], set_to_0);
1113                                         MONO_START_BB (cfg, set_to_1);
1114                                         MONO_EMIT_NEW_ICONST (cfg, next->dreg, 1);
1115                                         MONO_START_BB (cfg, set_to_0);
1116                                         NULLIFY_INS (next);
1117                                         break;  
1118                                 }
1119                                 default:
1120                                         g_assert_not_reached ();
1121                                 }
1122                                 break;
1123                         }
1124
1125                         default:
1126                                 break;
1127                         }
1128
1129                         if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1130                                 MonoInst *new_prev;
1131
1132                                 /* Replace the original instruction with the new code sequence */
1133
1134                                 /* Ignore the new value of prev */
1135                                 new_prev = prev;
1136                                 mono_replace_ins (cfg, bb, tree, &new_prev, first_bb, cfg->cbb);
1137
1138                                 /* Process the newly added ops again since they can be long ops too */
1139                                 if (prev)
1140                                         tree = mono_inst_next (prev, FILTER_IL_SEQ_POINT);
1141                                 else
1142                                         tree = mono_bb_first_inst (bb, FILTER_IL_SEQ_POINT);
1143
1144                                 first_bb->code = first_bb->last_ins = NULL;
1145                                 first_bb->in_count = first_bb->out_count = 0;
1146                                 cfg->cbb = first_bb;
1147                         }
1148                         else {
1149                                 prev = tree;
1150                                 tree = mono_inst_next (tree, FILTER_IL_SEQ_POINT);
1151                         }
1152                 }
1153         }
1154 #endif
1155
1156         /*
1157         for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
1158                 mono_print_bb (bb, "AFTER LOWER-LONG-OPTS");
1159         */
1160 }
1161
1162 /**
1163  * mono_decompose_vtype_opts:
1164  *
1165  *  Decompose valuetype opcodes.
1166  */
1167 void
1168 mono_decompose_vtype_opts (MonoCompile *cfg)
1169 {
1170         MonoBasicBlock *bb, *first_bb;
1171
1172         /**
1173          * Using OP_V opcodes and decomposing them later have two main benefits:
1174          * - it simplifies method_to_ir () since there is no need to special-case vtypes
1175          *   everywhere.
1176          * - it gets rid of the LDADDR opcodes generated when vtype operations are decomposed,
1177          *   enabling optimizations to work on vtypes too.
1178          * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it 
1179          * can be executed anytime. It should be executed as late as possible so vtype
1180          * opcodes can be optimized by the other passes.
1181          * The pinvoke wrappers need to manipulate vtypes in their unmanaged representation.
1182          * This is indicated by setting the 'backend.is_pinvoke' field of the MonoInst for the 
1183          * var to 1.
1184          * This is done on demand, ie. by the LDNATIVEOBJ opcode, and propagated by this pass 
1185          * when OP_VMOVE opcodes are decomposed.
1186          */
1187
1188         /* 
1189          * Vregs have no associated type information, so we store the type of the vregs
1190          * in ins->klass.
1191          */
1192
1193         /**
1194          * Create a dummy bblock and emit code into it so we can use the normal 
1195          * code generation macros.
1196          */
1197         cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1198         first_bb = cfg->cbb;
1199
1200         /* For LLVM, decompose only the OP_STOREV_MEMBASE opcodes, which need write barriers and the gsharedvt opcodes */
1201
1202         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1203                 MonoInst *ins;
1204                 MonoInst *prev = NULL;
1205                 MonoInst *src_var, *dest_var, *src, *dest;
1206                 gboolean restart;
1207                 int dreg;
1208
1209                 if (cfg->verbose_level > 2) mono_print_bb (bb, "BEFORE LOWER-VTYPE-OPTS ");
1210
1211                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1212                 restart = TRUE;
1213
1214                 while (restart) {
1215                         restart = FALSE;
1216
1217                         for (ins = bb->code; ins; ins = ins->next) {
1218                                 switch (ins->opcode) {
1219                                 case OP_VMOVE: {
1220                                         g_assert (ins->klass);
1221                                         if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1222                                                 break;
1223                                         src_var = get_vreg_to_inst (cfg, ins->sreg1);
1224                                         dest_var = get_vreg_to_inst (cfg, ins->dreg);
1225
1226                                         if (!src_var)
1227                                                 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1228
1229                                         if (!dest_var)
1230                                                 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1231
1232                                         // FIXME:
1233                                         if (src_var->backend.is_pinvoke)
1234                                                 dest_var->backend.is_pinvoke = 1;
1235
1236                                         EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
1237                                         EMIT_NEW_VARLOADA ((cfg), (dest), dest_var, dest_var->inst_vtype);
1238
1239                                         mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1240                                         break;
1241                                 }
1242                                 case OP_VZERO:
1243                                         if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1244                                                 break;
1245
1246                                         g_assert (ins->klass);
1247
1248                                         EMIT_NEW_VARLOADA_VREG (cfg, dest, ins->dreg, &ins->klass->byval_arg);
1249                                         mini_emit_initobj (cfg, dest, NULL, ins->klass);
1250                                         
1251                                         if (cfg->compute_gc_maps) {
1252                                                 MonoInst *tmp;
1253
1254                                                 /* 
1255                                                  * Tell the GC map code that the vtype is considered live after
1256                                                  * the initialization.
1257                                                  */
1258                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
1259                                                 tmp->inst_c1 = ins->dreg;
1260                                                 MONO_ADD_INS (cfg->cbb, tmp);
1261                                         }
1262                                         break;
1263                                 case OP_DUMMY_VZERO:
1264                                         if (COMPILE_LLVM (cfg))
1265                                                 break;
1266
1267                                         NULLIFY_INS (ins);
1268                                         break;
1269                                 case OP_STOREV_MEMBASE: {
1270                                         src_var = get_vreg_to_inst (cfg, ins->sreg1);
1271
1272                                         if (!src_var) {
1273                                                 g_assert (ins->klass);
1274                                                 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1275                                         }
1276
1277                                         EMIT_NEW_VARLOADA_VREG ((cfg), (src), ins->sreg1, &ins->klass->byval_arg);
1278
1279                                         dreg = alloc_preg (cfg);
1280                                         EMIT_NEW_BIALU_IMM (cfg, dest, OP_ADD_IMM, dreg, ins->inst_destbasereg, ins->inst_offset);
1281                                         mini_emit_stobj (cfg, dest, src, src_var->klass, src_var->backend.is_pinvoke);
1282                                         break;
1283                                 }
1284                                 case OP_LOADV_MEMBASE: {
1285                                         g_assert (ins->klass);
1286                                         if (COMPILE_LLVM (cfg) && !mini_is_gsharedvt_klass (ins->klass))
1287                                                 break;
1288
1289                                         dest_var = get_vreg_to_inst (cfg, ins->dreg);
1290                                         // FIXME-VT:
1291                                         // FIXME:
1292                                         if (!dest_var)
1293                                                 dest_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->dreg);
1294
1295                                         dreg = alloc_preg (cfg);
1296                                         EMIT_NEW_BIALU_IMM (cfg, src, OP_ADD_IMM, dreg, ins->inst_basereg, ins->inst_offset);
1297                                         EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1298                                         mini_emit_stobj (cfg, dest, src, dest_var->klass, dest_var->backend.is_pinvoke);
1299                                         break;
1300                                 }
1301                                 case OP_OUTARG_VT: {
1302                                         if (COMPILE_LLVM (cfg))
1303                                                 break;
1304
1305                                         g_assert (ins->klass);
1306
1307                                         src_var = get_vreg_to_inst (cfg, ins->sreg1);
1308                                         if (!src_var)
1309                                                 src_var = mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, ins->sreg1);
1310                                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1311
1312                                         mono_arch_emit_outarg_vt (cfg, ins, src);
1313
1314                                         /* This might be decomposed into other vtype opcodes */
1315                                         restart = TRUE;
1316                                         break;
1317                                 }
1318                                 case OP_OUTARG_VTRETADDR: {
1319                                         MonoCallInst *call = (MonoCallInst*)ins->inst_p1;
1320
1321                                         src_var = get_vreg_to_inst (cfg, call->inst.dreg);
1322                                         if (!src_var)
1323                                                 src_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1324                                         // FIXME: src_var->backend.is_pinvoke ?
1325
1326                                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
1327                                         src->dreg = ins->dreg;
1328                                         break;
1329                                 }
1330                                 case OP_VCALL:
1331                                 case OP_VCALL_REG:
1332                                 case OP_VCALL_MEMBASE: {
1333                                         MonoCallInst *call = (MonoCallInst*)ins;
1334                                         int size;
1335
1336                                         if (COMPILE_LLVM (cfg))
1337                                                 break;
1338
1339                                         if (call->vret_in_reg) {
1340                                                 MonoCallInst *call2;
1341
1342                                                 /* Replace the vcall with a scalar call */
1343                                                 MONO_INST_NEW_CALL (cfg, call2, OP_NOP);
1344                                                 memcpy (call2, call, sizeof (MonoCallInst));
1345                                                 switch (ins->opcode) {
1346                                                 case OP_VCALL:
1347                                                         call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL : OP_CALL;
1348                                                         break;
1349                                                 case OP_VCALL_REG:
1350                                                         call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_REG : OP_CALL_REG;
1351                                                         break;
1352                                                 case OP_VCALL_MEMBASE:
1353                                                         call2->inst.opcode = call->vret_in_reg_fp ? OP_FCALL_MEMBASE : OP_CALL_MEMBASE;
1354                                                         break;
1355                                                 }
1356                                                 call2->inst.dreg = alloc_preg (cfg);
1357                                                 MONO_ADD_INS (cfg->cbb, ((MonoInst*)call2));
1358
1359                                                 /* Compute the vtype location */
1360                                                 dest_var = get_vreg_to_inst (cfg, call->inst.dreg);
1361                                                 if (!dest_var)
1362                                                         dest_var = mono_compile_create_var_for_vreg (cfg, call->signature->ret, OP_LOCAL, call->inst.dreg);
1363                                                 EMIT_NEW_VARLOADA (cfg, dest, dest_var, dest_var->inst_vtype);
1364
1365                                                 /* Save the result */
1366                                                 if (dest_var->backend.is_pinvoke)
1367                                                         size = mono_class_native_size (mono_class_from_mono_type (dest_var->inst_vtype), NULL);
1368                                                 else
1369                                                         size = mono_type_size (dest_var->inst_vtype, NULL);
1370                                                 switch (size) {
1371                                                 case 1:
1372                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1373                                                         break;
1374                                                 case 2:
1375                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1376                                                         break;
1377                                                 case 3:
1378                                                 case 4:
1379                                                         if (call->vret_in_reg_fp)
1380                                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1381                                                         else
1382                                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1383                                                         break;
1384                                                 case 5:
1385                                                 case 6:
1386                                                 case 7:
1387                                                 case 8:
1388                                                         if (call->vret_in_reg_fp) {
1389                                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1390                                                                 break;
1391                                                         }
1392 #if SIZEOF_REGISTER == 4
1393                                                         /*
1394                                                         FIXME Other ABIs might return in different regs than the ones used for LCALL.
1395                                                         FIXME It would be even nicer to be able to leverage the long decompose stuff.
1396                                                         */
1397                                                         switch (call2->inst.opcode) {
1398                                                         case OP_CALL:
1399                                                                 call2->inst.opcode = OP_LCALL;
1400                                                                 break;
1401                                                         case OP_CALL_REG:
1402                                                                 call2->inst.opcode = OP_LCALL_REG;
1403                                                                 break;
1404                                                         case OP_CALL_MEMBASE:
1405                                                                 call2->inst.opcode = OP_LCALL_MEMBASE;
1406                                                                 break;
1407                                                         }
1408                                                         call2->inst.dreg = alloc_lreg (cfg);
1409                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_MS_WORD_OFFSET, MONO_LVREG_MS (call2->inst.dreg));
1410                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, dest->dreg, MINI_LS_WORD_OFFSET, MONO_LVREG_LS (call2->inst.dreg));
1411 #else
1412                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1413 #endif
1414                                                         break;
1415                                                 default:
1416                                                         /* This assumes the vtype is sizeof (gpointer) long */
1417                                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, dest->dreg, 0, call2->inst.dreg);
1418                                                         break;
1419                                                 }
1420                                         } else {
1421                                                 switch (ins->opcode) {
1422                                                 case OP_VCALL:
1423                                                         ins->opcode = OP_VCALL2;
1424                                                         break;
1425                                                 case OP_VCALL_REG:
1426                                                         ins->opcode = OP_VCALL2_REG;
1427                                                         break;
1428                                                 case OP_VCALL_MEMBASE:
1429                                                         ins->opcode = OP_VCALL2_MEMBASE;
1430                                                         break;
1431                                                 }
1432                                                 ins->dreg = -1;
1433                                         }
1434                                         break;
1435                                 }
1436                                 default:
1437                                         break;
1438                                 }
1439
1440                                 g_assert (cfg->cbb == first_bb);
1441
1442                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1443                                         /* Replace the original instruction with the new code sequence */
1444
1445                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1446                                         first_bb->code = first_bb->last_ins = NULL;
1447                                         first_bb->in_count = first_bb->out_count = 0;
1448                                         cfg->cbb = first_bb;
1449                                 }
1450                                 else
1451                                         prev = ins;
1452                         }
1453                 }
1454
1455                 if (cfg->verbose_level > 2) mono_print_bb (bb, "AFTER LOWER-VTYPE-OPTS ");
1456         }
1457 }
1458
1459 inline static MonoInst *
1460 mono_get_domainvar (MonoCompile *cfg)
1461 {
1462         if (!cfg->domainvar)
1463                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1464         return cfg->domainvar;
1465 }
1466
1467 /**
1468  * mono_decompose_array_access_opts:
1469  *
1470  *  Decompose array access opcodes.
1471  */
1472 void
1473 mono_decompose_array_access_opts (MonoCompile *cfg)
1474 {
1475         MonoBasicBlock *bb, *first_bb;
1476
1477         /*
1478          * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it 
1479          * can be executed anytime. It should be run before decompose_long
1480          */
1481
1482         /**
1483          * Create a dummy bblock and emit code into it so we can use the normal 
1484          * code generation macros.
1485          */
1486         cfg->cbb = (MonoBasicBlock *)mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1487         first_bb = cfg->cbb;
1488
1489         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1490                 MonoInst *ins;
1491                 MonoInst *prev = NULL;
1492                 MonoInst *dest;
1493                 MonoInst *iargs [3];
1494                 gboolean restart;
1495
1496                 if (!bb->has_array_access)
1497                         continue;
1498
1499                 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
1500
1501                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1502                 restart = TRUE;
1503
1504                 while (restart) {
1505                         restart = FALSE;
1506
1507                         for (ins = bb->code; ins; ins = ins->next) {
1508                                 switch (ins->opcode) {
1509                                 case OP_LDLEN:
1510                                         NEW_LOAD_MEMBASE_FLAGS (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
1511                                                                                         MONO_STRUCT_OFFSET (MonoArray, max_length), ins->flags | MONO_INST_INVARIANT_LOAD);
1512                                         MONO_ADD_INS (cfg->cbb, dest);
1513                                         break;
1514                                 case OP_BOUNDS_CHECK:
1515                                         MONO_EMIT_NULL_CHECK (cfg, ins->sreg1);
1516                                         if (COMPILE_LLVM (cfg))
1517                                                 MONO_EMIT_DEFAULT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->flags & MONO_INST_FAULT);
1518                                         else
1519                                                 MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
1520                                         break;
1521                                 case OP_NEWARR:
1522                                         if (cfg->opt & MONO_OPT_SHARED) {
1523                                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
1524                                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
1525                                                 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
1526                                                 iargs [2]->dreg = ins->sreg1;
1527
1528                                                 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
1529                                                 dest->dreg = ins->dreg;
1530                                         } else {
1531                                                 MonoClass *array_class = mono_array_class_get (ins->inst_newa_class, 1);
1532                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, array_class);
1533                                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
1534
1535                                                 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
1536                                                 NEW_VTABLECONST (cfg, iargs [0], vtable);
1537                                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
1538                                                 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
1539                                                 iargs [1]->dreg = ins->sreg1;
1540
1541                                                 if (managed_alloc)
1542                                                         dest = mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
1543                                                 else
1544                                                         dest = mono_emit_jit_icall (cfg, ves_icall_array_new_specific, iargs);
1545                                                 dest->dreg = ins->dreg;
1546                                         }
1547                                         break;
1548                                 case OP_STRLEN:
1549                                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FLAGS (cfg, OP_LOADI4_MEMBASE, ins->dreg,
1550                                                                                                                  ins->sreg1, MONO_STRUCT_OFFSET (MonoString, length), ins->flags | MONO_INST_INVARIANT_LOAD);
1551                                         break;
1552                                 default:
1553                                         break;
1554                                 }
1555
1556                                 g_assert (cfg->cbb == first_bb);
1557
1558                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1559                                         /* Replace the original instruction with the new code sequence */
1560
1561                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1562                                         first_bb->code = first_bb->last_ins = NULL;
1563                                         first_bb->in_count = first_bb->out_count = 0;
1564                                         cfg->cbb = first_bb;
1565                                 }
1566                                 else
1567                                         prev = ins;
1568                         }
1569                 }
1570
1571                 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
1572         }
1573 }
1574
1575 typedef union {
1576         guint32 vali [2];
1577         gint64 vall;
1578         double vald;
1579 } DVal;
1580
1581 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
1582
1583 /**
1584  * mono_decompose_soft_float:
1585  *
1586  *  Soft float support on ARM. We store each double value in a pair of integer vregs,
1587  * similar to long support on 32 bit platforms. 32 bit float values require special
1588  * handling when used as locals, arguments, and in calls.
1589  * One big problem with soft-float is that there are few r4 test cases in our test suite.
1590  */
1591 void
1592 mono_decompose_soft_float (MonoCompile *cfg)
1593 {
1594         MonoBasicBlock *bb, *first_bb;
1595
1596         /*
1597          * This pass creates long opcodes, so it should be run before decompose_long_opts ().
1598          */
1599
1600         /**
1601          * Create a dummy bblock and emit code into it so we can use the normal 
1602          * code generation macros.
1603          */
1604         cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1605         first_bb = cfg->cbb;
1606
1607         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1608                 MonoInst *ins;
1609                 MonoInst *prev = NULL;
1610                 gboolean restart;
1611
1612                 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
1613
1614                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
1615                 restart = TRUE;
1616
1617                 while (restart) {
1618                         restart = FALSE;
1619
1620                         for (ins = bb->code; ins; ins = ins->next) {
1621                                 const char *spec = INS_INFO (ins->opcode);
1622
1623                                 /* Most fp operations are handled automatically by opcode emulation */
1624
1625                                 switch (ins->opcode) {
1626                                 case OP_R8CONST: {
1627                                         DVal d;
1628                                         d.vald = *(double*)ins->inst_p0;
1629                                         MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1630                                         break;
1631                                 }
1632                                 case OP_R4CONST: {
1633                                         DVal d;
1634                                         /* We load the r8 value */
1635                                         d.vald = *(float*)ins->inst_p0;
1636                                         MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
1637                                         break;
1638                                 }
1639                                 case OP_FMOVE:
1640                                         ins->opcode = OP_LMOVE;
1641                                         break;
1642                                 case OP_FGETLOW32:
1643                                         ins->opcode = OP_MOVE;
1644                                         ins->sreg1 = MONO_LVREG_LS (ins->sreg1);
1645                                         break;
1646                                 case OP_FGETHIGH32:
1647                                         ins->opcode = OP_MOVE;
1648                                         ins->sreg1 = MONO_LVREG_MS (ins->sreg1);
1649                                         break;
1650                                 case OP_SETFRET: {
1651                                         int reg = ins->sreg1;
1652
1653                                         ins->opcode = OP_SETLRET;
1654                                         ins->dreg = -1;
1655                                         ins->sreg1 = MONO_LVREG_LS (reg);
1656                                         ins->sreg2 = MONO_LVREG_MS (reg);
1657                                         break;
1658                                 }
1659                                 case OP_LOADR8_MEMBASE:
1660                                         ins->opcode = OP_LOADI8_MEMBASE;
1661                                         break;
1662                                 case OP_STORER8_MEMBASE_REG:
1663                                         ins->opcode = OP_STOREI8_MEMBASE_REG;
1664                                         break;
1665                                 case OP_STORER4_MEMBASE_REG: {
1666                                         MonoInst *iargs [2];
1667                                         int addr_reg;
1668
1669                                         /* Arg 1 is the double value */
1670                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1671                                         iargs [0]->dreg = ins->sreg1;
1672
1673                                         /* Arg 2 is the address to store to */
1674                                         addr_reg = mono_alloc_preg (cfg);
1675                                         EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
1676                                         mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
1677                                         restart = TRUE;
1678                                         break;
1679                                 }
1680                                 case OP_LOADR4_MEMBASE: {
1681                                         MonoInst *iargs [1];
1682                                         MonoInst *conv;
1683                                         int addr_reg;
1684
1685                                         addr_reg = mono_alloc_preg (cfg);
1686                                         EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
1687                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1688                                         conv->dreg = ins->dreg;
1689                                         break;
1690                                 }                                       
1691                                 case OP_FCALL:
1692                                 case OP_FCALL_REG:
1693                                 case OP_FCALL_MEMBASE: {
1694                                         MonoCallInst *call = (MonoCallInst*)ins;
1695                                         if (call->signature->ret->type == MONO_TYPE_R4) {
1696                                                 MonoCallInst *call2;
1697                                                 MonoInst *iargs [1];
1698                                                 MonoInst *conv;
1699                                                 GSList *l;
1700
1701                                                 /* Convert the call into a call returning an int */
1702                                                 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
1703                                                 memcpy (call2, call, sizeof (MonoCallInst));
1704                                                 switch (ins->opcode) {
1705                                                 case OP_FCALL:
1706                                                         call2->inst.opcode = OP_CALL;
1707                                                         break;
1708                                                 case OP_FCALL_REG:
1709                                                         call2->inst.opcode = OP_CALL_REG;
1710                                                         break;
1711                                                 case OP_FCALL_MEMBASE:
1712                                                         call2->inst.opcode = OP_CALL_MEMBASE;
1713                                                         break;
1714                                                 default:
1715                                                         g_assert_not_reached ();
1716                                                 }
1717                                                 call2->inst.dreg = mono_alloc_ireg (cfg);
1718                                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
1719
1720                                                 /* Remap OUTARG_VT instructions referencing this call */
1721                                                 for (l = call->outarg_vts; l; l = l->next)
1722                                                         ((MonoInst*)(l->data))->inst_p0 = call2;
1723
1724                                                 /* FIXME: Optimize this */
1725
1726                                                 /* Emit an r4->r8 conversion */
1727                                                 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
1728                                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
1729                                                 conv->dreg = ins->dreg;
1730
1731                                                 /* The call sequence might include fp ins */
1732                                                 restart = TRUE;
1733                                         } else {
1734                                                 switch (ins->opcode) {
1735                                                 case OP_FCALL:
1736                                                         ins->opcode = OP_LCALL;
1737                                                         break;
1738                                                 case OP_FCALL_REG:
1739                                                         ins->opcode = OP_LCALL_REG;
1740                                                         break;
1741                                                 case OP_FCALL_MEMBASE:
1742                                                         ins->opcode = OP_LCALL_MEMBASE;
1743                                                         break;
1744                                                 default:
1745                                                         g_assert_not_reached ();
1746                                                 }
1747                                         }
1748                                         break;
1749                                 }
1750                                 case OP_FCOMPARE: {
1751                                         MonoJitICallInfo *info;
1752                                         MonoInst *iargs [2];
1753                                         MonoInst *call, *cmp, *br;
1754
1755                                         /* Convert fcompare+fbcc to icall+icompare+beq */
1756
1757                                         if (!ins->next) {
1758                                                 /* The branch might be optimized away */
1759                                                 NULLIFY_INS (ins);
1760                                                 break;
1761                                         }
1762
1763                                         info = mono_find_jit_opcode_emulation (ins->next->opcode);
1764                                         if (!info) {
1765                                                 /* The branch might be optimized away */
1766                                                 NULLIFY_INS (ins);
1767                                                 break;
1768                                         }
1769
1770                                         /* Create dummy MonoInst's for the arguments */
1771                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1772                                         iargs [0]->dreg = ins->sreg1;
1773                                         MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1774                                         iargs [1]->dreg = ins->sreg2;
1775
1776                                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1777
1778                                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1779                                         cmp->sreg1 = call->dreg;
1780                                         cmp->inst_imm = 0;
1781                                         MONO_ADD_INS (cfg->cbb, cmp);
1782                                         
1783                                         MONO_INST_NEW (cfg, br, OP_IBNE_UN);
1784                                         br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
1785                                         br->inst_true_bb = ins->next->inst_true_bb;
1786                                         br->inst_false_bb = ins->next->inst_false_bb;
1787                                         MONO_ADD_INS (cfg->cbb, br);
1788
1789                                         /* The call sequence might include fp ins */
1790                                         restart = TRUE;
1791
1792                                         /* Skip fbcc or fccc */
1793                                         NULLIFY_INS (ins->next);
1794                                         break;
1795                                 }
1796                                 case OP_FCEQ:
1797                                 case OP_FCGT:
1798                                 case OP_FCGT_UN:
1799                                 case OP_FCLT:
1800                                 case OP_FCLT_UN: {
1801                                         MonoJitICallInfo *info;
1802                                         MonoInst *iargs [2];
1803                                         MonoInst *call;
1804
1805                                         /* Convert fccc to icall+icompare+iceq */
1806
1807                                         info = mono_find_jit_opcode_emulation (ins->opcode);
1808                                         g_assert (info);
1809
1810                                         /* Create dummy MonoInst's for the arguments */
1811                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1812                                         iargs [0]->dreg = ins->sreg1;
1813                                         MONO_INST_NEW (cfg, iargs [1], OP_ARG);
1814                                         iargs [1]->dreg = ins->sreg2;
1815
1816                                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
1817
1818                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
1819                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
1820
1821                                         /* The call sequence might include fp ins */
1822                                         restart = TRUE;
1823                                         break;
1824                                 }
1825                                 case OP_CKFINITE: {
1826                                         MonoInst *iargs [2];
1827                                         MonoInst *call, *cmp;
1828
1829                                         /* Convert to icall+icompare+cond_exc+move */
1830
1831                                         /* Create dummy MonoInst's for the arguments */
1832                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
1833                                         iargs [0]->dreg = ins->sreg1;
1834
1835                                         call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
1836
1837                                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
1838                                         cmp->sreg1 = call->dreg;
1839                                         cmp->inst_imm = 1;
1840                                         MONO_ADD_INS (cfg->cbb, cmp);
1841
1842                                         MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
1843
1844                                         /* Do the assignment if the value is finite */
1845                                         MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
1846
1847                                         restart = TRUE;
1848                                         break;
1849                                 }
1850                                 default:
1851                                         if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
1852                                                 mono_print_ins (ins);
1853                                                 g_assert_not_reached ();
1854                                         }
1855                                         break;
1856                                 }
1857
1858                                 g_assert (cfg->cbb == first_bb);
1859
1860                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1861                                         /* Replace the original instruction with the new code sequence */
1862
1863                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
1864                                         first_bb->code = first_bb->last_ins = NULL;
1865                                         first_bb->in_count = first_bb->out_count = 0;
1866                                         cfg->cbb = first_bb;
1867                                 }
1868                                 else
1869                                         prev = ins;
1870                         }
1871                 }
1872
1873                 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
1874         }
1875
1876         mono_decompose_long_opts (cfg);
1877 }
1878
1879 #endif
1880
1881 void
1882 mono_local_emulate_ops (MonoCompile *cfg)
1883 {
1884         MonoBasicBlock *bb;
1885         gboolean inlined_wrapper = FALSE;
1886
1887         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
1888                 MonoInst *ins;
1889
1890                 MONO_BB_FOR_EACH_INS (bb, ins) {
1891                         int op_noimm = mono_op_imm_to_op (ins->opcode);
1892                         MonoJitICallInfo *info;
1893
1894                         /*
1895                          * Emulation can't handle _IMM ops. If this is an imm opcode we need
1896                          * to check whether its non-imm counterpart is emulated and, if so,
1897                          * decompose it back to its non-imm counterpart.
1898                          */
1899                         if (op_noimm != -1)
1900                                 info = mono_find_jit_opcode_emulation (op_noimm);
1901                         else
1902                                 info = mono_find_jit_opcode_emulation (ins->opcode);
1903
1904                         if (info) {
1905                                 MonoInst **args;
1906                                 MonoInst *call;
1907                                 MonoBasicBlock *first_bb;
1908
1909                                 /* Create dummy MonoInst's for the arguments */
1910                                 g_assert (!info->sig->hasthis);
1911                                 g_assert (info->sig->param_count <= MONO_MAX_SRC_REGS);
1912
1913                                 if (op_noimm != -1)
1914                                         mono_decompose_op_imm (cfg, bb, ins);
1915
1916                                 args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * info->sig->param_count);
1917                                 if (info->sig->param_count > 0) {
1918                                         int sregs [MONO_MAX_SRC_REGS];
1919                                         int num_sregs, i;
1920                                         num_sregs = mono_inst_get_src_registers (ins, sregs);
1921                                         g_assert (num_sregs == info->sig->param_count);
1922                                         for (i = 0; i < num_sregs; ++i) {
1923                                                 MONO_INST_NEW (cfg, args [i], OP_ARG);
1924                                                 args [i]->dreg = sregs [i];
1925                                         }
1926                                 }
1927
1928                                 /* We emit the call on a separate dummy basic block */
1929                                 cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
1930                                 first_bb = cfg->cbb;
1931
1932                                 call = mono_emit_jit_icall_by_info (cfg, info, args);
1933                                 call->dreg = ins->dreg;
1934
1935                                 /* Replace ins with the emitted code and do the necessary bb linking */
1936                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
1937                                         MonoInst *saved_prev = ins->prev;
1938
1939                                         mono_replace_ins (cfg, bb, ins, &ins->prev, first_bb, cfg->cbb);
1940                                         first_bb->code = first_bb->last_ins = NULL;
1941                                         first_bb->in_count = first_bb->out_count = 0;
1942                                         cfg->cbb = first_bb;
1943
1944                                         /* ins is hanging, continue scanning the emitted code */
1945                                         ins = saved_prev;
1946                                 } else {
1947                                         g_error ("Failed to emit emulation code");
1948                                 }
1949                                 inlined_wrapper = TRUE;
1950                         }
1951                 }
1952         }
1953
1954         /*
1955          * Avoid rerunning these passes by emitting directly the exception checkpoint
1956          * at IR level, instead of inlining the icall wrapper. FIXME
1957          */
1958         if (inlined_wrapper) {
1959                 if (!COMPILE_LLVM (cfg))
1960                         mono_decompose_long_opts (cfg);
1961                 if (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP))
1962                         mono_local_cprop (cfg);
1963         }
1964 }
1965
1966 #endif /* DISABLE_JIT */