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