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