a23cacb749cf4beab676eb35ca2ac8c870b548e3
[mono.git] / mono / mini / mini-arm.c
1 /*
2  * mini-arm.c: ARM backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2003 Ximian, Inc.
9  */
10 #include "mini.h"
11 #include <string.h>
12
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
15
16 #include "mini-arm.h"
17 #include "inssel.h"
18 #include "cpu-arm.h"
19 #include "trace.h"
20 #ifdef ARM_FPU_FPA
21 #include "mono/arch/arm/arm-fpa-codegen.h"
22 #elif defined(ARM_FPU_VFP)
23 #include "mono/arch/arm/arm-vfp-codegen.h"
24 #endif
25
26 static int mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount);
27
28 /*
29  * TODO:
30  * floating point support: on ARM it is a mess, there are at least 3
31  * different setups, each of which binary incompat with the other.
32  * 1) FPA: old and ugly, but unfortunately what current distros use
33  *    the double binary format has the two words swapped. 8 double registers.
34  *    Implemented usually by kernel emulation.
35  * 2) softfloat: the compiler emulates all the fp ops. Usually uses the
36  *    ugly swapped double format (I guess a softfloat-vfp exists, too, though).
37  * 3) VFP: the new and actually sensible and useful FP support. Implemented
38  *    in HW or kernel-emulated, requires new tools. I think this ios what symbian uses.
39  *
40  * The plan is to write the FPA support first. softfloat can be tested in a chroot.
41  */
42 int mono_exc_esp_offset = 0;
43
44 #define arm_is_imm12(v) ((v) > -4096 && (v) < 4096)
45 #define arm_is_imm8(v) ((v) > -256 && (v) < 256)
46 #define arm_is_fpimm8(v) ((v) >= -1020 && (v) <= 1020)
47
48 const char*
49 mono_arch_regname (int reg) {
50         static const char * rnames[] = {
51                 "arm_r0", "arm_r1", "arm_r2", "arm_r3", "arm_v1",
52                 "arm_v2", "arm_v3", "arm_v4", "arm_v5", "arm_v6",
53                 "arm_v7", "arm_fp", "arm_ip", "arm_sp", "arm_lr",
54                 "arm_pc"
55         };
56         if (reg >= 0 && reg < 16)
57                 return rnames [reg];
58         return "unknown";
59 }
60
61 const char*
62 mono_arch_fregname (int reg) {
63         static const char * rnames[] = {
64                 "arm_f0", "arm_f1", "arm_f2", "arm_f3", "arm_f4",
65                 "arm_f5", "arm_f6", "arm_f7", "arm_f8", "arm_f9",
66                 "arm_f10", "arm_f11", "arm_f12", "arm_f13", "arm_f14",
67                 "arm_f15", "arm_f16", "arm_f17", "arm_f18", "arm_f19",
68                 "arm_f20", "arm_f21", "arm_f22", "arm_f23", "arm_f24",
69                 "arm_f25", "arm_f26", "arm_f27", "arm_f28", "arm_f29",
70                 "arm_f30", "arm_f31"
71         };
72         if (reg >= 0 && reg < 32)
73                 return rnames [reg];
74         return "unknown";
75 }
76
77 static guint8*
78 emit_big_add (guint8 *code, int dreg, int sreg, int imm)
79 {
80         int imm8, rot_amount;
81         if ((imm8 = mono_arm_is_rotated_imm8 (imm, &rot_amount)) >= 0) {
82                 ARM_ADD_REG_IMM (code, dreg, sreg, imm8, rot_amount);
83                 return code;
84         }
85         g_assert (dreg != sreg);
86         code = mono_arm_emit_load_imm (code, dreg, imm);
87         ARM_ADD_REG_REG (code, dreg, dreg, sreg);
88         return code;
89 }
90
91 static guint8*
92 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
93 {
94         /* we can use r0-r3, since this is called only for incoming args on the stack */
95         if (size > sizeof (gpointer) * 4) {
96                 guint8 *start_loop;
97                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
98                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
99                 start_loop = code = mono_arm_emit_load_imm (code, ARMREG_R2, size);
100                 ARM_LDR_IMM (code, ARMREG_R3, ARMREG_R0, 0);
101                 ARM_STR_IMM (code, ARMREG_R3, ARMREG_R1, 0);
102                 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, 4);
103                 ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
104                 ARM_SUBS_REG_IMM8 (code, ARMREG_R2, ARMREG_R2, 4);
105                 ARM_B_COND (code, ARMCOND_NE, 0);
106                 arm_patch (code - 4, start_loop);
107                 return code;
108         }
109         if (arm_is_imm12 (doffset) && arm_is_imm12 (doffset + size) &&
110                         arm_is_imm12 (soffset) && arm_is_imm12 (soffset + size)) {
111                 while (size >= 4) {
112                         ARM_LDR_IMM (code, ARMREG_LR, sreg, soffset);
113                         ARM_STR_IMM (code, ARMREG_LR, dreg, doffset);
114                         doffset += 4;
115                         soffset += 4;
116                         size -= 4;
117                 }
118         } else if (size) {
119                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
120                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
121                 doffset = soffset = 0;
122                 while (size >= 4) {
123                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R0, soffset);
124                         ARM_STR_IMM (code, ARMREG_LR, ARMREG_R1, doffset);
125                         doffset += 4;
126                         soffset += 4;
127                         size -= 4;
128                 }
129         }
130         g_assert (size == 0);
131         return code;
132 }
133
134 /*
135  * mono_arch_get_argument_info:
136  * @csig:  a method signature
137  * @param_count: the number of parameters to consider
138  * @arg_info: an array to store the result infos
139  *
140  * Gathers information on parameters such as size, alignment and
141  * padding. arg_info should be large enought to hold param_count + 1 entries. 
142  *
143  * Returns the size of the activation frame.
144  */
145 int
146 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
147 {
148         int k, frame_size = 0;
149         int size, align, pad;
150         int offset = 8;
151
152         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
153                 frame_size += sizeof (gpointer);
154                 offset += 4;
155         }
156
157         arg_info [0].offset = offset;
158
159         if (csig->hasthis) {
160                 frame_size += sizeof (gpointer);
161                 offset += 4;
162         }
163
164         arg_info [0].size = frame_size;
165
166         for (k = 0; k < param_count; k++) {
167                 
168                 if (csig->pinvoke)
169                         size = mono_type_native_stack_size (csig->params [k], &align);
170                 else
171                         size = mono_type_stack_size (csig->params [k], &align);
172
173                 /* ignore alignment for now */
174                 align = 1;
175
176                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
177                 arg_info [k].pad = pad;
178                 frame_size += size;
179                 arg_info [k + 1].pad = 0;
180                 arg_info [k + 1].size = size;
181                 offset += pad;
182                 arg_info [k + 1].offset = offset;
183                 offset += size;
184         }
185
186         align = MONO_ARCH_FRAME_ALIGNMENT;
187         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
188         arg_info [k].pad = pad;
189
190         return frame_size;
191 }
192
193 /*
194  * Initialize the cpu to execute managed code.
195  */
196 void
197 mono_arch_cpu_init (void)
198 {
199 }
200
201 /*
202  * This function returns the optimizations supported on this cpu.
203  */
204 guint32
205 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
206 {
207         guint32 opts = 0;
208
209         /* no arm-specific optimizations yet */
210         *exclude_mask = 0;
211         return opts;
212 }
213
214 static gboolean
215 is_regsize_var (MonoType *t) {
216         if (t->byref)
217                 return TRUE;
218         t = mono_type_get_underlying_type (t);
219         switch (t->type) {
220         case MONO_TYPE_I4:
221         case MONO_TYPE_U4:
222         case MONO_TYPE_I:
223         case MONO_TYPE_U:
224         case MONO_TYPE_PTR:
225         case MONO_TYPE_FNPTR:
226                 return TRUE;
227         case MONO_TYPE_OBJECT:
228         case MONO_TYPE_STRING:
229         case MONO_TYPE_CLASS:
230         case MONO_TYPE_SZARRAY:
231         case MONO_TYPE_ARRAY:
232                 return TRUE;
233         case MONO_TYPE_GENERICINST:
234                 if (!mono_type_generic_inst_is_valuetype (t))
235                         return TRUE;
236                 return FALSE;
237         case MONO_TYPE_VALUETYPE:
238                 return FALSE;
239         }
240         return FALSE;
241 }
242
243 GList *
244 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
245 {
246         GList *vars = NULL;
247         int i;
248
249         for (i = 0; i < cfg->num_varinfo; i++) {
250                 MonoInst *ins = cfg->varinfo [i];
251                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
252
253                 /* unused vars */
254                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
255                         continue;
256
257                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
258                         continue;
259
260                 /* we can only allocate 32 bit values */
261                 if (is_regsize_var (ins->inst_vtype)) {
262                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
263                         g_assert (i == vmv->idx);
264                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
265                 }
266         }
267
268         return vars;
269 }
270
271 #define USE_EXTRA_TEMPS 0
272
273 GList *
274 mono_arch_get_global_int_regs (MonoCompile *cfg)
275 {
276         GList *regs = NULL;
277         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V1));
278         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V2));
279         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V3));
280         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V4));
281         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
282         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V6));*/
283         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));*/
284
285         return regs;
286 }
287
288 /*
289  * mono_arch_regalloc_cost:
290  *
291  *  Return the cost, in number of memory references, of the action of 
292  * allocating the variable VMV into a register during global register
293  * allocation.
294  */
295 guint32
296 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
297 {
298         /* FIXME: */
299         return 2;
300 }
301
302 void
303 mono_arch_flush_icache (guint8 *code, gint size)
304 {
305         __asm __volatile ("mov r0, %0\n"
306                         "mov r1, %1\n"
307                         "mov r2, %2\n"
308                         "swi 0x9f0002       @ sys_cacheflush"
309                         : /* no outputs */
310                         : "r" (code), "r" (code + size), "r" (0)
311                         : "r0", "r1", "r3" );
312
313 }
314
315 #define NOT_IMPLEMENTED(x) \
316                 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
317
318 enum {
319         RegTypeGeneral,
320         RegTypeBase,
321         RegTypeBaseGen,
322         RegTypeFP,
323         RegTypeStructByVal,
324         RegTypeStructByAddr
325 };
326
327 typedef struct {
328         gint32  offset;
329         guint16 vtsize; /* in param area */
330         guint8  reg;
331         guint8  regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
332         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
333 } ArgInfo;
334
335 typedef struct {
336         int nargs;
337         guint32 stack_usage;
338         guint32 struct_ret;
339         ArgInfo ret;
340         ArgInfo sig_cookie;
341         ArgInfo args [1];
342 } CallInfo;
343
344 #define DEBUG(a)
345
346 static void inline
347 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
348 {
349         if (simple) {
350                 if (*gr > ARMREG_R3) {
351                         ainfo->offset = *stack_size;
352                         ainfo->reg = ARMREG_SP; /* in the caller */
353                         ainfo->regtype = RegTypeBase;
354                         *stack_size += 4;
355                 } else {
356                         ainfo->reg = *gr;
357                 }
358         } else {
359                 if (*gr == ARMREG_R3) {
360                         /* first word in r3 and the second on the stack */
361                         ainfo->offset = *stack_size;
362                         ainfo->reg = ARMREG_SP; /* in the caller */
363                         ainfo->regtype = RegTypeBaseGen;
364                         *stack_size += 4;
365                 } else if (*gr > ARMREG_R3) {
366                         /**stack_size += 7;
367                         *stack_size &= ~7;*/
368                         ainfo->offset = *stack_size;
369                         ainfo->reg = ARMREG_SP; /* in the caller */
370                         ainfo->regtype = RegTypeBase;
371                         *stack_size += 8;
372                 } else {
373                         /*if ((*gr) & 1)
374                                 (*gr) ++;*/
375                         ainfo->reg = *gr;
376                 }
377                 (*gr) ++;
378         }
379         (*gr) ++;
380 }
381
382 static CallInfo*
383 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
384 {
385         guint i, gr;
386         int n = sig->hasthis + sig->param_count;
387         guint32 simpletype;
388         guint32 stack_size = 0;
389         CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
390
391         gr = ARMREG_R0;
392
393         /* FIXME: handle returning a struct */
394         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
395                 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
396                 cinfo->struct_ret = ARMREG_R0;
397         }
398
399         n = 0;
400         if (sig->hasthis) {
401                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
402                 n++;
403         }
404         DEBUG(printf("params: %d\n", sig->param_count));
405         for (i = 0; i < sig->param_count; ++i) {
406                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
407                         /* Prevent implicit arguments and sig_cookie from
408                            being passed in registers */
409                         gr = ARMREG_R3 + 1;
410                         /* Emit the signature cookie just before the implicit arguments */
411                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
412                 }
413                 DEBUG(printf("param %d: ", i));
414                 if (sig->params [i]->byref) {
415                         DEBUG(printf("byref\n"));
416                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
417                         n++;
418                         continue;
419                 }
420                 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
421                 switch (simpletype) {
422                 case MONO_TYPE_BOOLEAN:
423                 case MONO_TYPE_I1:
424                 case MONO_TYPE_U1:
425                         cinfo->args [n].size = 1;
426                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
427                         n++;
428                         break;
429                 case MONO_TYPE_CHAR:
430                 case MONO_TYPE_I2:
431                 case MONO_TYPE_U2:
432                         cinfo->args [n].size = 2;
433                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
434                         n++;
435                         break;
436                 case MONO_TYPE_I4:
437                 case MONO_TYPE_U4:
438                         cinfo->args [n].size = 4;
439                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
440                         n++;
441                         break;
442                 case MONO_TYPE_I:
443                 case MONO_TYPE_U:
444                 case MONO_TYPE_PTR:
445                 case MONO_TYPE_FNPTR:
446                 case MONO_TYPE_CLASS:
447                 case MONO_TYPE_OBJECT:
448                 case MONO_TYPE_STRING:
449                 case MONO_TYPE_SZARRAY:
450                 case MONO_TYPE_ARRAY:
451                 case MONO_TYPE_R4:
452                         cinfo->args [n].size = sizeof (gpointer);
453                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
454                         n++;
455                         break;
456                 case MONO_TYPE_GENERICINST:
457                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
458                                 cinfo->args [n].size = sizeof (gpointer);
459                                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
460                                 n++;
461                                 break;
462                         }
463                         /* Fall through */
464                 case MONO_TYPE_TYPEDBYREF:
465                 case MONO_TYPE_VALUETYPE: {
466                         gint size;
467                         int align_size;
468                         int nwords;
469
470                         if (simpletype == MONO_TYPE_TYPEDBYREF) {
471                                 size = sizeof (MonoTypedRef);
472                         } else {
473                                 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
474                                 if (is_pinvoke)
475                                         size = mono_class_native_size (klass, NULL);
476                                 else
477                                         size = mono_class_value_size (klass, NULL);
478                         }
479                         DEBUG(printf ("load %d bytes struct\n",
480                                       mono_class_native_size (sig->params [i]->data.klass, NULL)));
481                         align_size = size;
482                         nwords = 0;
483                         align_size += (sizeof (gpointer) - 1);
484                         align_size &= ~(sizeof (gpointer) - 1);
485                         nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
486                         cinfo->args [n].regtype = RegTypeStructByVal;
487                         /* FIXME: align gr and stack_size if needed */
488                         if (gr > ARMREG_R3) {
489                                 cinfo->args [n].size = 0;
490                                 cinfo->args [n].vtsize = nwords;
491                         } else {
492                                 int rest = ARMREG_R3 - gr + 1;
493                                 int n_in_regs = rest >= nwords? nwords: rest;
494                                 cinfo->args [n].size = n_in_regs;
495                                 cinfo->args [n].vtsize = nwords - n_in_regs;
496                                 cinfo->args [n].reg = gr;
497                                 gr += n_in_regs;
498                         }
499                         cinfo->args [n].offset = stack_size;
500                         /*g_print ("offset for arg %d at %d\n", n, stack_size);*/
501                         stack_size += nwords * sizeof (gpointer);
502                         n++;
503                         break;
504                 }
505                 case MONO_TYPE_U8:
506                 case MONO_TYPE_I8:
507                 case MONO_TYPE_R8:
508                         cinfo->args [n].size = 8;
509                         add_general (&gr, &stack_size, cinfo->args + n, FALSE);
510                         n++;
511                         break;
512                 default:
513                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
514                 }
515         }
516
517         {
518                 simpletype = mono_type_get_underlying_type (sig->ret)->type;
519                 switch (simpletype) {
520                 case MONO_TYPE_BOOLEAN:
521                 case MONO_TYPE_I1:
522                 case MONO_TYPE_U1:
523                 case MONO_TYPE_I2:
524                 case MONO_TYPE_U2:
525                 case MONO_TYPE_CHAR:
526                 case MONO_TYPE_I4:
527                 case MONO_TYPE_U4:
528                 case MONO_TYPE_I:
529                 case MONO_TYPE_U:
530                 case MONO_TYPE_PTR:
531                 case MONO_TYPE_FNPTR:
532                 case MONO_TYPE_CLASS:
533                 case MONO_TYPE_OBJECT:
534                 case MONO_TYPE_SZARRAY:
535                 case MONO_TYPE_ARRAY:
536                 case MONO_TYPE_STRING:
537                         cinfo->ret.reg = ARMREG_R0;
538                         break;
539                 case MONO_TYPE_U8:
540                 case MONO_TYPE_I8:
541                         cinfo->ret.reg = ARMREG_R0;
542                         break;
543                 case MONO_TYPE_R4:
544                 case MONO_TYPE_R8:
545                         cinfo->ret.reg = ARMREG_R0;
546                         /* FIXME: cinfo->ret.reg = ???;
547                         cinfo->ret.regtype = RegTypeFP;*/
548                         break;
549                 case MONO_TYPE_GENERICINST:
550                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
551                                 cinfo->ret.reg = ARMREG_R0;
552                                 break;
553                         }
554                         break;
555                 case MONO_TYPE_VALUETYPE:
556                         break;
557                 case MONO_TYPE_TYPEDBYREF:
558                 case MONO_TYPE_VOID:
559                         break;
560                 default:
561                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
562                 }
563         }
564
565         /* align stack size to 8 */
566         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
567         stack_size = (stack_size + 7) & ~7;
568
569         cinfo->stack_usage = stack_size;
570         return cinfo;
571 }
572
573
574 /*
575  * Set var information according to the calling convention. arm version.
576  * The locals var stuff should most likely be split in another method.
577  */
578 void
579 mono_arch_allocate_vars (MonoCompile *m)
580 {
581         MonoMethodSignature *sig;
582         MonoMethodHeader *header;
583         MonoInst *inst;
584         int i, offset, size, align, curinst;
585         int frame_reg = ARMREG_FP;
586
587         /* FIXME: this will change when we use FP as gcc does */
588         m->flags |= MONO_CFG_HAS_SPILLUP;
589
590         /* allow room for the vararg method args: void* and long/double */
591         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
592                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
593
594         header = mono_method_get_header (m->method);
595
596         /* 
597          * We use the frame register also for any method that has
598          * exception clauses. This way, when the handlers are called,
599          * the code will reference local variables using the frame reg instead of
600          * the stack pointer: if we had to restore the stack pointer, we'd
601          * corrupt the method frames that are already on the stack (since
602          * filters get called before stack unwinding happens) when the filter
603          * code would call any method (this also applies to finally etc.).
604          */ 
605         if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
606                 frame_reg = ARMREG_FP;
607         m->frame_reg = frame_reg;
608         if (frame_reg != ARMREG_SP) {
609                 m->used_int_regs |= 1 << frame_reg;
610         }
611
612         sig = mono_method_signature (m->method);
613         
614         offset = 0;
615         curinst = 0;
616         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
617                 m->ret->opcode = OP_REGVAR;
618                 m->ret->inst_c0 = ARMREG_R0;
619         } else {
620                 /* FIXME: handle long and FP values */
621                 switch (mono_type_get_underlying_type (sig->ret)->type) {
622                 case MONO_TYPE_VOID:
623                         break;
624                 default:
625                         m->ret->opcode = OP_REGVAR;
626                         m->ret->inst_c0 = ARMREG_R0;
627                         break;
628                 }
629         }
630         /* local vars are at a positive offset from the stack pointer */
631         /* 
632          * also note that if the function uses alloca, we use FP
633          * to point at the local variables.
634          */
635         offset = 0; /* linkage area */
636         /* align the offset to 16 bytes: not sure this is needed here  */
637         //offset += 8 - 1;
638         //offset &= ~(8 - 1);
639
640         /* add parameter area size for called functions */
641         offset += m->param_area;
642         offset += 8 - 1;
643         offset &= ~(8 - 1);
644         if (m->flags & MONO_CFG_HAS_FPOUT)
645                 offset += 8;
646
647         /* allow room to save the return value */
648         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
649                 offset += 8;
650
651         /* the MonoLMF structure is stored just below the stack pointer */
652
653         if (sig->call_convention == MONO_CALL_VARARG) {
654                 m->sig_cookie = 0;
655         }
656
657         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
658                 inst = m->ret;
659                 offset += sizeof(gpointer) - 1;
660                 offset &= ~(sizeof(gpointer) - 1);
661                 inst->inst_offset = offset;
662                 inst->opcode = OP_REGOFFSET;
663                 inst->inst_basereg = frame_reg;
664                 offset += sizeof(gpointer);
665                 if (sig->call_convention == MONO_CALL_VARARG)
666                         m->sig_cookie += sizeof (gpointer);
667         }
668
669         curinst = m->locals_start;
670         for (i = curinst; i < m->num_varinfo; ++i) {
671                 inst = m->varinfo [i];
672                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
673                         continue;
674
675                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
676                 * pinvoke wrappers when they call functions returning structure */
677                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
678                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
679                 else
680                         size = mono_type_size (inst->inst_vtype, &align);
681
682                 /* FIXME: if a structure is misaligned, our memcpy doesn't work,
683                  * since it loads/stores misaligned words, which don't do the right thing.
684                  */
685                 if (align < 4 && size >= 4)
686                         align = 4;
687                 offset += align - 1;
688                 offset &= ~(align - 1);
689                 inst->inst_offset = offset;
690                 inst->opcode = OP_REGOFFSET;
691                 inst->inst_basereg = frame_reg;
692                 offset += size;
693                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
694         }
695
696         curinst = 0;
697         if (sig->hasthis) {
698                 inst = m->varinfo [curinst];
699                 if (inst->opcode != OP_REGVAR) {
700                         inst->opcode = OP_REGOFFSET;
701                         inst->inst_basereg = frame_reg;
702                         offset += sizeof (gpointer) - 1;
703                         offset &= ~(sizeof (gpointer) - 1);
704                         inst->inst_offset = offset;
705                         offset += sizeof (gpointer);
706                         if (sig->call_convention == MONO_CALL_VARARG)
707                                 m->sig_cookie += sizeof (gpointer);
708                 }
709                 curinst++;
710         }
711
712         for (i = 0; i < sig->param_count; ++i) {
713                 inst = m->varinfo [curinst];
714                 if (inst->opcode != OP_REGVAR) {
715                         inst->opcode = OP_REGOFFSET;
716                         inst->inst_basereg = frame_reg;
717                         size = mono_type_size (sig->params [i], &align);
718                         /* FIXME: if a structure is misaligned, our memcpy doesn't work,
719                          * since it loads/stores misaligned words, which don't do the right thing.
720                          */
721                         if (align < 4 && size >= 4)
722                                 align = 4;
723                         offset += align - 1;
724                         offset &= ~(align - 1);
725                         inst->inst_offset = offset;
726                         offset += size;
727                         if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
728                                 m->sig_cookie += size;
729                 }
730                 curinst++;
731         }
732
733         /* align the offset to 8 bytes */
734         offset += 8 - 1;
735         offset &= ~(8 - 1);
736
737         /* change sign? */
738         m->stack_offset = offset;
739
740 }
741
742 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
743  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
744  */
745
746 /* 
747  * take the arguments and generate the arch-specific
748  * instructions to properly call the function in call.
749  * This includes pushing, moving arguments to the right register
750  * etc.
751  * Issue: who does the spilling if needed, and when?
752  */
753 MonoCallInst*
754 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
755         MonoInst *arg, *in;
756         MonoMethodSignature *sig;
757         int i, n;
758         CallInfo *cinfo;
759         ArgInfo *ainfo;
760
761         sig = call->signature;
762         n = sig->param_count + sig->hasthis;
763         
764         cinfo = calculate_sizes (sig, sig->pinvoke);
765         if (cinfo->struct_ret)
766                 call->used_iregs |= 1 << cinfo->struct_ret;
767
768         for (i = 0; i < n; ++i) {
769                 ainfo = cinfo->args + i;
770                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
771                         MonoInst *sig_arg;
772                         cfg->disable_aot = TRUE;
773                                 
774                         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
775                         sig_arg->inst_p0 = call->signature;
776                         
777                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
778                         arg->inst_imm = cinfo->sig_cookie.offset;
779                         arg->inst_left = sig_arg;
780                         
781                         /* prepend, so they get reversed */
782                         arg->next = call->out_args;
783                         call->out_args = arg;
784                 }
785                 if (is_virtual && i == 0) {
786                         /* the argument will be attached to the call instrucion */
787                         in = call->args [i];
788                         call->used_iregs |= 1 << ainfo->reg;
789                 } else {
790                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
791                         in = call->args [i];
792                         arg->cil_code = in->cil_code;
793                         arg->inst_left = in;
794                         arg->inst_right = (MonoInst*)call;
795                         arg->type = in->type;
796                         /* prepend, we'll need to reverse them later */
797                         arg->next = call->out_args;
798                         call->out_args = arg;
799                         if (ainfo->regtype == RegTypeGeneral) {
800                                 arg->backend.reg3 = ainfo->reg;
801                                 call->used_iregs |= 1 << ainfo->reg;
802                                 if (arg->type == STACK_I8)
803                                         call->used_iregs |= 1 << (ainfo->reg + 1);
804                                 if (arg->type == STACK_R8) {
805                                         if (ainfo->size == 4) {
806                                                 arg->opcode = OP_OUTARG_R4;
807                                         } else {
808                                                 call->used_iregs |= 1 << (ainfo->reg + 1);
809                                         }
810                                         cfg->flags |= MONO_CFG_HAS_FPOUT;
811                                 }
812                         } else if (ainfo->regtype == RegTypeStructByAddr) {
813                                 /* FIXME: where si the data allocated? */
814                                 arg->backend.reg3 = ainfo->reg;
815                                 call->used_iregs |= 1 << ainfo->reg;
816                                 g_assert_not_reached ();
817                         } else if (ainfo->regtype == RegTypeStructByVal) {
818                                 int cur_reg;
819                                 /* mark the used regs */
820                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
821                                         call->used_iregs |= 1 << (ainfo->reg + cur_reg);
822                                 }
823                                 arg->opcode = OP_OUTARG_VT;
824                                 /* vtsize and offset have just 12 bits of encoding in number of words */
825                                 g_assert (((ainfo->vtsize | (ainfo->offset / 4)) & 0xfffff000) == 0);
826                                 arg->backend.arg_info = ainfo->reg | (ainfo->size << 4) | (ainfo->vtsize << 8) | ((ainfo->offset / 4) << 20);
827                         } else if (ainfo->regtype == RegTypeBase) {
828                                 arg->opcode = OP_OUTARG_MEMBASE;
829                                 arg->backend.arg_info = (ainfo->offset << 8) | ainfo->size;
830                         } else if (ainfo->regtype == RegTypeBaseGen) {
831                                 call->used_iregs |= 1 << ARMREG_R3;
832                                 arg->opcode = OP_OUTARG_MEMBASE;
833                                 arg->backend.arg_info = (ainfo->offset << 8) | 0xff;
834                                 if (arg->type == STACK_R8)
835                                         cfg->flags |= MONO_CFG_HAS_FPOUT;
836                         } else if (ainfo->regtype == RegTypeFP) {
837                                 arg->backend.reg3 = ainfo->reg;
838                                 /* FP args are passed in int regs */
839                                 call->used_iregs |= 1 << ainfo->reg;
840                                 if (ainfo->size == 8) {
841                                         arg->opcode = OP_OUTARG_R8;
842                                         call->used_iregs |= 1 << (ainfo->reg + 1);
843                                 } else {
844                                         arg->opcode = OP_OUTARG_R4;
845                                 }
846                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
847                         } else {
848                                 g_assert_not_reached ();
849                         }
850                 }
851         }
852         /*
853          * Reverse the call->out_args list.
854          */
855         {
856                 MonoInst *prev = NULL, *list = call->out_args, *next;
857                 while (list) {
858                         next = list->next;
859                         list->next = prev;
860                         prev = list;
861                         list = next;
862                 }
863                 call->out_args = prev;
864         }
865         call->stack_usage = cinfo->stack_usage;
866         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
867         cfg->flags |= MONO_CFG_HAS_CALLS;
868         /* 
869          * should set more info in call, such as the stack space
870          * used by the args that needs to be added back to esp
871          */
872
873         g_free (cinfo);
874         return call;
875 }
876
877 /*
878  * Allow tracing to work with this interface (with an optional argument)
879  */
880
881 void*
882 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
883 {
884         guchar *code = p;
885
886         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
887         ARM_MOV_REG_IMM8 (code, ARMREG_R1, 0); /* NULL ebp for now */
888         code = mono_arm_emit_load_imm (code, ARMREG_R2, (guint32)func);
889         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
890         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_R2);
891         return code;
892 }
893
894 enum {
895         SAVE_NONE,
896         SAVE_STRUCT,
897         SAVE_ONE,
898         SAVE_TWO,
899         SAVE_FP
900 };
901
902 void*
903 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
904 {
905         guchar *code = p;
906         int save_mode = SAVE_NONE;
907         int offset;
908         MonoMethod *method = cfg->method;
909         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
910         int save_offset = cfg->param_area;
911         save_offset += 7;
912         save_offset &= ~7;
913         
914         offset = code - cfg->native_code;
915         /* we need about 16 instructions */
916         if (offset > (cfg->code_size - 16 * 4)) {
917                 cfg->code_size *= 2;
918                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
919                 code = cfg->native_code + offset;
920         }
921         switch (rtype) {
922         case MONO_TYPE_VOID:
923                 /* special case string .ctor icall */
924                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
925                         save_mode = SAVE_ONE;
926                 else
927                         save_mode = SAVE_NONE;
928                 break;
929         case MONO_TYPE_I8:
930         case MONO_TYPE_U8:
931                 save_mode = SAVE_TWO;
932                 break;
933         case MONO_TYPE_R4:
934         case MONO_TYPE_R8:
935                 save_mode = SAVE_FP;
936                 break;
937         case MONO_TYPE_VALUETYPE:
938                 save_mode = SAVE_STRUCT;
939                 break;
940         default:
941                 save_mode = SAVE_ONE;
942                 break;
943         }
944
945         switch (save_mode) {
946         case SAVE_TWO:
947                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
948                 ARM_STR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
949                 if (enable_arguments) {
950                         ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_R1);
951                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
952                 }
953                 break;
954         case SAVE_ONE:
955                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
956                 if (enable_arguments) {
957                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
958                 }
959                 break;
960         case SAVE_FP:
961                 /* FIXME: what reg?  */
962                 if (enable_arguments) {
963                         /* FIXME: what reg?  */
964                 }
965                 break;
966         case SAVE_STRUCT:
967                 if (enable_arguments) {
968                         /* FIXME: get the actual address  */
969                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
970                 }
971                 break;
972         case SAVE_NONE:
973         default:
974                 break;
975         }
976
977         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
978         code = mono_arm_emit_load_imm (code, ARMREG_IP, (guint32)func);
979         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
980         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
981
982         switch (save_mode) {
983         case SAVE_TWO:
984                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
985                 ARM_LDR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
986                 break;
987         case SAVE_ONE:
988                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
989                 break;
990         case SAVE_FP:
991                 /* FIXME */
992                 break;
993         case SAVE_NONE:
994         default:
995                 break;
996         }
997
998         return code;
999 }
1000
1001 /*
1002  * The immediate field for cond branches is big enough for all reasonable methods
1003  */
1004 #define EMIT_COND_BRANCH_FLAGS(ins,condcode) \
1005 if (ins->flags & MONO_INST_BRLABEL) { \
1006         if (0 && ins->inst_i0->inst_c0) { \
1007                 ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffffff);    \
1008         } else { \
1009                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1010                 ARM_B_COND (code, (condcode), 0);       \
1011         } \
1012 } else { \
1013         if (0 && ins->inst_true_bb->native_offset) { \
1014                 ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffffff); \
1015         } else { \
1016                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1017                 ARM_B_COND (code, (condcode), 0);       \
1018         } \
1019 }
1020
1021 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_cc_table [(cond)])
1022
1023 /* emit an exception if condition is fail
1024  *
1025  * We assign the extra code used to throw the implicit exceptions
1026  * to cfg->bb_exit as far as the big branch handling is concerned
1027  */
1028 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(condcode,exc_name)            \
1029         do {                                                        \
1030                 mono_add_patch_info (cfg, code - cfg->native_code,   \
1031                                     MONO_PATCH_INFO_EXC, exc_name);  \
1032                 ARM_BL_COND (code, (condcode), 0);      \
1033         } while (0); 
1034
1035 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_cc_table [(cond)], (exc_name))
1036
1037 static void
1038 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1039 {
1040         MonoInst *ins, *last_ins = NULL;
1041         ins = bb->code;
1042
1043         while (ins) {
1044
1045                 switch (ins->opcode) {
1046                 case OP_MUL_IMM: 
1047                         /* remove unnecessary multiplication with 1 */
1048                         if (ins->inst_imm == 1) {
1049                                 if (ins->dreg != ins->sreg1) {
1050                                         ins->opcode = OP_MOVE;
1051                                 } else {
1052                                         last_ins->next = ins->next;                             
1053                                         ins = ins->next;                                
1054                                         continue;
1055                                 }
1056                         } else {
1057                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1058                                 if (power2 > 0) {
1059                                         ins->opcode = OP_SHL_IMM;
1060                                         ins->inst_imm = power2;
1061                                 }
1062                         }
1063                         break;
1064                 case OP_LOAD_MEMBASE:
1065                 case OP_LOADI4_MEMBASE:
1066                         /* 
1067                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1068                          * OP_LOAD_MEMBASE offset(basereg), reg
1069                          */
1070                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1071                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1072                             ins->inst_basereg == last_ins->inst_destbasereg &&
1073                             ins->inst_offset == last_ins->inst_offset) {
1074                                 if (ins->dreg == last_ins->sreg1) {
1075                                         last_ins->next = ins->next;                             
1076                                         ins = ins->next;                                
1077                                         continue;
1078                                 } else {
1079                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1080                                         ins->opcode = OP_MOVE;
1081                                         ins->sreg1 = last_ins->sreg1;
1082                                 }
1083
1084                         /* 
1085                          * Note: reg1 must be different from the basereg in the second load
1086                          * OP_LOAD_MEMBASE offset(basereg), reg1
1087                          * OP_LOAD_MEMBASE offset(basereg), reg2
1088                          * -->
1089                          * OP_LOAD_MEMBASE offset(basereg), reg1
1090                          * OP_MOVE reg1, reg2
1091                          */
1092                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1093                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1094                               ins->inst_basereg != last_ins->dreg &&
1095                               ins->inst_basereg == last_ins->inst_basereg &&
1096                               ins->inst_offset == last_ins->inst_offset) {
1097
1098                                 if (ins->dreg == last_ins->dreg) {
1099                                         last_ins->next = ins->next;                             
1100                                         ins = ins->next;                                
1101                                         continue;
1102                                 } else {
1103                                         ins->opcode = OP_MOVE;
1104                                         ins->sreg1 = last_ins->dreg;
1105                                 }
1106
1107                                 //g_assert_not_reached ();
1108
1109 #if 0
1110                         /* 
1111                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1112                          * OP_LOAD_MEMBASE offset(basereg), reg
1113                          * -->
1114                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1115                          * OP_ICONST reg, imm
1116                          */
1117                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1118                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1119                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1120                                    ins->inst_offset == last_ins->inst_offset) {
1121                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1122                                 ins->opcode = OP_ICONST;
1123                                 ins->inst_c0 = last_ins->inst_imm;
1124                                 g_assert_not_reached (); // check this rule
1125 #endif
1126                         }
1127                         break;
1128                 case OP_LOADU1_MEMBASE:
1129                 case OP_LOADI1_MEMBASE:
1130                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1131                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1132                                         ins->inst_offset == last_ins->inst_offset) {
1133                                 if (ins->dreg == last_ins->sreg1) {
1134                                         last_ins->next = ins->next;                             
1135                                         ins = ins->next;                                
1136                                         continue;
1137                                 } else {
1138                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1139                                         ins->opcode = OP_MOVE;
1140                                         ins->sreg1 = last_ins->sreg1;
1141                                 }
1142                         }
1143                         break;
1144                 case OP_LOADU2_MEMBASE:
1145                 case OP_LOADI2_MEMBASE:
1146                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1147                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1148                                         ins->inst_offset == last_ins->inst_offset) {
1149                                 if (ins->dreg == last_ins->sreg1) {
1150                                         last_ins->next = ins->next;                             
1151                                         ins = ins->next;                                
1152                                         continue;
1153                                 } else {
1154                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1155                                         ins->opcode = OP_MOVE;
1156                                         ins->sreg1 = last_ins->sreg1;
1157                                 }
1158                         }
1159                         break;
1160                 case CEE_CONV_I4:
1161                 case CEE_CONV_U4:
1162                 case OP_MOVE:
1163                 case OP_SETREG:
1164                         ins->opcode = OP_MOVE;
1165                         /* 
1166                          * OP_MOVE reg, reg 
1167                          */
1168                         if (ins->dreg == ins->sreg1) {
1169                                 if (last_ins)
1170                                         last_ins->next = ins->next;                             
1171                                 ins = ins->next;
1172                                 continue;
1173                         }
1174                         /* 
1175                          * OP_MOVE sreg, dreg 
1176                          * OP_MOVE dreg, sreg
1177                          */
1178                         if (last_ins && last_ins->opcode == OP_MOVE &&
1179                             ins->sreg1 == last_ins->dreg &&
1180                             ins->dreg == last_ins->sreg1) {
1181                                 last_ins->next = ins->next;                             
1182                                 ins = ins->next;                                
1183                                 continue;
1184                         }
1185                         break;
1186                 }
1187                 last_ins = ins;
1188                 ins = ins->next;
1189         }
1190         bb->last_ins = last_ins;
1191 }
1192
1193 /* 
1194  * the branch_cc_table should maintain the order of these
1195  * opcodes.
1196 case CEE_BEQ:
1197 case CEE_BGE:
1198 case CEE_BGT:
1199 case CEE_BLE:
1200 case CEE_BLT:
1201 case CEE_BNE_UN:
1202 case CEE_BGE_UN:
1203 case CEE_BGT_UN:
1204 case CEE_BLE_UN:
1205 case CEE_BLT_UN:
1206  */
1207 static const guchar 
1208 branch_cc_table [] = {
1209         ARMCOND_EQ, 
1210         ARMCOND_GE, 
1211         ARMCOND_GT, 
1212         ARMCOND_LE,
1213         ARMCOND_LT, 
1214         
1215         ARMCOND_NE, 
1216         ARMCOND_HS, 
1217         ARMCOND_HI, 
1218         ARMCOND_LS,
1219         ARMCOND_LO
1220 };
1221
1222
1223 static void
1224 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1225 {
1226         if (ins == NULL) {
1227                 ins = bb->code;
1228                 bb->code = to_insert;
1229                 to_insert->next = ins;
1230         } else {
1231                 to_insert->next = ins->next;
1232                 ins->next = to_insert;
1233         }
1234 }
1235
1236 #define NEW_INS(cfg,dest,op) do {       \
1237                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
1238                 (dest)->opcode = (op);  \
1239                 insert_after_ins (bb, last_ins, (dest)); \
1240         } while (0)
1241
1242 static int
1243 map_to_reg_reg_op (int op)
1244 {
1245         switch (op) {
1246         case OP_ADD_IMM:
1247                 return CEE_ADD;
1248         case OP_SUB_IMM:
1249                 return CEE_SUB;
1250         case OP_AND_IMM:
1251                 return CEE_AND;
1252         case OP_COMPARE_IMM:
1253                 return OP_COMPARE;
1254         case OP_ADDCC_IMM:
1255                 return OP_ADDCC;
1256         case OP_ADC_IMM:
1257                 return OP_ADC;
1258         case OP_SUBCC_IMM:
1259                 return OP_SUBCC;
1260         case OP_SBB_IMM:
1261                 return OP_SBB;
1262         case OP_OR_IMM:
1263                 return CEE_OR;
1264         case OP_XOR_IMM:
1265                 return CEE_XOR;
1266         case OP_LOAD_MEMBASE:
1267                 return OP_LOAD_MEMINDEX;
1268         case OP_LOADI4_MEMBASE:
1269                 return OP_LOADI4_MEMINDEX;
1270         case OP_LOADU4_MEMBASE:
1271                 return OP_LOADU4_MEMINDEX;
1272         case OP_LOADU1_MEMBASE:
1273                 return OP_LOADU1_MEMINDEX;
1274         case OP_LOADI2_MEMBASE:
1275                 return OP_LOADI2_MEMINDEX;
1276         case OP_LOADU2_MEMBASE:
1277                 return OP_LOADU2_MEMINDEX;
1278         case OP_LOADI1_MEMBASE:
1279                 return OP_LOADI1_MEMINDEX;
1280         case OP_STOREI1_MEMBASE_REG:
1281                 return OP_STOREI1_MEMINDEX;
1282         case OP_STOREI2_MEMBASE_REG:
1283                 return OP_STOREI2_MEMINDEX;
1284         case OP_STOREI4_MEMBASE_REG:
1285                 return OP_STOREI4_MEMINDEX;
1286         case OP_STORE_MEMBASE_REG:
1287                 return OP_STORE_MEMINDEX;
1288         case OP_STORER4_MEMBASE_REG:
1289                 return OP_STORER4_MEMINDEX;
1290         case OP_STORER8_MEMBASE_REG:
1291                 return OP_STORER8_MEMINDEX;
1292         case OP_STORE_MEMBASE_IMM:
1293                 return OP_STORE_MEMBASE_REG;
1294         case OP_STOREI1_MEMBASE_IMM:
1295                 return OP_STOREI1_MEMBASE_REG;
1296         case OP_STOREI2_MEMBASE_IMM:
1297                 return OP_STOREI2_MEMBASE_REG;
1298         case OP_STOREI4_MEMBASE_IMM:
1299                 return OP_STOREI4_MEMBASE_REG;
1300         }
1301         g_assert_not_reached ();
1302 }
1303
1304 /*
1305  * Remove from the instruction list the instructions that can't be
1306  * represented with very simple instructions with no register
1307  * requirements.
1308  */
1309 static void
1310 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1311 {
1312         MonoInst *ins, *temp, *last_ins = NULL;
1313         int rot_amount, imm8, low_imm;
1314
1315         /* setup the virtual reg allocator */
1316         if (bb->max_ireg > cfg->rs->next_vireg)
1317                 cfg->rs->next_vireg = bb->max_ireg;
1318
1319         ins = bb->code;
1320         while (ins) {
1321 loop_start:
1322                 switch (ins->opcode) {
1323                 case OP_ADD_IMM:
1324                 case OP_SUB_IMM:
1325                 case OP_AND_IMM:
1326                 case OP_COMPARE_IMM:
1327                 case OP_ADDCC_IMM:
1328                 case OP_ADC_IMM:
1329                 case OP_SUBCC_IMM:
1330                 case OP_SBB_IMM:
1331                 case OP_OR_IMM:
1332                 case OP_XOR_IMM:
1333                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
1334                                 NEW_INS (cfg, temp, OP_ICONST);
1335                                 temp->inst_c0 = ins->inst_imm;
1336                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1337                                 ins->sreg2 = temp->dreg;
1338                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1339                         }
1340                         break;
1341                 case OP_MUL_IMM:
1342                         if (ins->inst_imm == 1) {
1343                                 ins->opcode = OP_MOVE;
1344                                 break;
1345                         }
1346                         if (ins->inst_imm == 0) {
1347                                 ins->opcode = OP_ICONST;
1348                                 ins->inst_c0 = 0;
1349                                 break;
1350                         }
1351                         imm8 = mono_is_power_of_two (ins->inst_imm);
1352                         if (imm8 > 0) {
1353                                 ins->opcode = OP_SHL_IMM;
1354                                 ins->inst_imm = imm8;
1355                                 break;
1356                         }
1357                         NEW_INS (cfg, temp, OP_ICONST);
1358                         temp->inst_c0 = ins->inst_imm;
1359                         temp->dreg = mono_regstate_next_int (cfg->rs);
1360                         ins->sreg2 = temp->dreg;
1361                         ins->opcode = CEE_MUL;
1362                         break;
1363                 case OP_LOAD_MEMBASE:
1364                 case OP_LOADI4_MEMBASE:
1365                 case OP_LOADU4_MEMBASE:
1366                 case OP_LOADU1_MEMBASE:
1367                         /* we can do two things: load the immed in a register
1368                          * and use an indexed load, or see if the immed can be
1369                          * represented as an ad_imm + a load with a smaller offset
1370                          * that fits. We just do the first for now, optimize later.
1371                          */
1372                         if (arm_is_imm12 (ins->inst_offset))
1373                                 break;
1374                         NEW_INS (cfg, temp, OP_ICONST);
1375                         temp->inst_c0 = ins->inst_offset;
1376                         temp->dreg = mono_regstate_next_int (cfg->rs);
1377                         ins->sreg2 = temp->dreg;
1378                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1379                         break;
1380                 case OP_LOADI2_MEMBASE:
1381                 case OP_LOADU2_MEMBASE:
1382                 case OP_LOADI1_MEMBASE:
1383                         if (arm_is_imm8 (ins->inst_offset))
1384                                 break;
1385                         NEW_INS (cfg, temp, OP_ICONST);
1386                         temp->inst_c0 = ins->inst_offset;
1387                         temp->dreg = mono_regstate_next_int (cfg->rs);
1388                         ins->sreg2 = temp->dreg;
1389                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1390                         break;
1391                 case OP_LOADR4_MEMBASE:
1392                 case OP_LOADR8_MEMBASE:
1393                         if (arm_is_fpimm8 (ins->inst_offset))
1394                                 break;
1395                         low_imm = ins->inst_offset & 0x1ff;
1396                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~0x1ff, &rot_amount)) >= 0) {
1397                                 NEW_INS (cfg, temp, OP_ADD_IMM);
1398                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
1399                                 temp->sreg1 = ins->inst_basereg;
1400                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1401                                 ins->inst_basereg = temp->dreg;
1402                                 ins->inst_offset = low_imm;
1403                                 break;
1404                         }
1405                         /* VFP/FPA doesn't have indexed load instructions */
1406                         g_assert_not_reached ();
1407                         break;
1408                 case OP_STORE_MEMBASE_REG:
1409                 case OP_STOREI4_MEMBASE_REG:
1410                 case OP_STOREI1_MEMBASE_REG:
1411                         if (arm_is_imm12 (ins->inst_offset))
1412                                 break;
1413                         NEW_INS (cfg, temp, OP_ICONST);
1414                         temp->inst_c0 = ins->inst_offset;
1415                         temp->dreg = mono_regstate_next_int (cfg->rs);
1416                         ins->sreg2 = temp->dreg;
1417                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1418                         break;
1419                 case OP_STOREI2_MEMBASE_REG:
1420                         if (arm_is_imm8 (ins->inst_offset))
1421                                 break;
1422                         NEW_INS (cfg, temp, OP_ICONST);
1423                         temp->inst_c0 = ins->inst_offset;
1424                         temp->dreg = mono_regstate_next_int (cfg->rs);
1425                         ins->sreg2 = temp->dreg;
1426                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1427                         break;
1428                 case OP_STORER4_MEMBASE_REG:
1429                 case OP_STORER8_MEMBASE_REG:
1430                         if (arm_is_fpimm8 (ins->inst_offset))
1431                                 break;
1432                         low_imm = ins->inst_offset & 0x1ff;
1433                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~ 0x1ff, &rot_amount)) >= 0 && arm_is_fpimm8 (low_imm)) {
1434                                 NEW_INS (cfg, temp, OP_ADD_IMM);
1435                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
1436                                 temp->sreg1 = ins->inst_destbasereg;
1437                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1438                                 ins->inst_destbasereg = temp->dreg;
1439                                 ins->inst_offset = low_imm;
1440                                 break;
1441                         }
1442                         /*g_print ("fail with: %d (%d, %d)\n", ins->inst_offset, ins->inst_offset & ~0x1ff, low_imm);*/
1443                         /* VFP/FPA doesn't have indexed store instructions */
1444                         g_assert_not_reached ();
1445                         break;
1446                 case OP_STORE_MEMBASE_IMM:
1447                 case OP_STOREI1_MEMBASE_IMM:
1448                 case OP_STOREI2_MEMBASE_IMM:
1449                 case OP_STOREI4_MEMBASE_IMM:
1450                         NEW_INS (cfg, temp, OP_ICONST);
1451                         temp->inst_c0 = ins->inst_imm;
1452                         temp->dreg = mono_regstate_next_int (cfg->rs);
1453                         ins->sreg1 = temp->dreg;
1454                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1455                         last_ins = temp;
1456                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
1457                 }
1458                 last_ins = ins;
1459                 ins = ins->next;
1460         }
1461         bb->last_ins = last_ins;
1462         bb->max_ireg = cfg->rs->next_vireg;
1463
1464 }
1465
1466 void
1467 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1468 {
1469         if (!bb->code)
1470                 return;
1471         mono_arch_lowering_pass (cfg, bb);
1472         mono_local_regalloc (cfg, bb);
1473 }
1474
1475 static guchar*
1476 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1477 {
1478         /* sreg is a float, dreg is an integer reg  */
1479 #ifdef ARM_FPU_FPA
1480         ARM_FIXZ (code, dreg, sreg);
1481 #elif defined(ARM_FPU_VFP)
1482         if (is_signed)
1483                 ARM_TOSIZD (code, ARM_VFP_F0, sreg);
1484         else
1485                 ARM_TOUIZD (code, ARM_VFP_F0, sreg);
1486         ARM_FMRS (code, dreg, ARM_VFP_F0);
1487 #endif
1488         if (!is_signed) {
1489                 if (size == 1)
1490                         ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff);
1491                 else if (size == 2) {
1492                         ARM_SHL_IMM (code, dreg, dreg, 16);
1493                         ARM_SHR_IMM (code, dreg, dreg, 16);
1494                 }
1495         } else {
1496                 if (size == 1) {
1497                         ARM_SHL_IMM (code, dreg, dreg, 24);
1498                         ARM_SAR_IMM (code, dreg, dreg, 24);
1499                 } else if (size == 2) {
1500                         ARM_SHL_IMM (code, dreg, dreg, 16);
1501                         ARM_SAR_IMM (code, dreg, dreg, 16);
1502                 }
1503         }
1504         return code;
1505 }
1506
1507 typedef struct {
1508         guchar *code;
1509         const guchar *target;
1510         int absolute;
1511         int found;
1512 } PatchData;
1513
1514 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1515
1516 static int
1517 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1518         PatchData *pdata = (PatchData*)user_data;
1519         guchar *code = data;
1520         guint32 *thunks = data;
1521         guint32 *endthunks = (guint32*)(code + bsize);
1522         int count = 0;
1523         int difflow, diffhigh;
1524
1525         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1526         difflow = (char*)pdata->code - (char*)thunks;
1527         diffhigh = (char*)pdata->code - (char*)endthunks;
1528         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1529                 return 0;
1530
1531         /*
1532          * The thunk is composed of 3 words:
1533          * load constant from thunks [2] into ARM_IP
1534          * bx to ARM_IP
1535          * address constant
1536          * Note that the LR register is already setup
1537          */
1538         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1539         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1540                 while (thunks < endthunks) {
1541                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1542                         if (thunks [2] == (guint32)pdata->target) {
1543                                 arm_patch (pdata->code, (guchar*)thunks);
1544                                 mono_arch_flush_icache (pdata->code, 4);
1545                                 pdata->found = 1;
1546                                 return 1;
1547                         } else if ((thunks [0] == 0) && (thunks [1] == 0) && (thunks [2] == 0)) {
1548                                 /* found a free slot instead: emit thunk */
1549                                 code = (guchar*)thunks;
1550                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
1551                                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
1552                                 thunks [2] = (guint32)pdata->target;
1553                                 mono_arch_flush_icache ((guchar*)thunks, 12);
1554
1555                                 arm_patch (pdata->code, (guchar*)thunks);
1556                                 mono_arch_flush_icache (pdata->code, 4);
1557                                 pdata->found = 1;
1558                                 return 1;
1559                         }
1560                         /* skip 12 bytes, the size of the thunk */
1561                         thunks += 3;
1562                         count++;
1563                 }
1564                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1565         }
1566         return 0;
1567 }
1568
1569 static void
1570 handle_thunk (int absolute, guchar *code, const guchar *target) {
1571         MonoDomain *domain = mono_domain_get ();
1572         PatchData pdata;
1573
1574         pdata.code = code;
1575         pdata.target = target;
1576         pdata.absolute = absolute;
1577         pdata.found = 0;
1578
1579         mono_domain_lock (domain);
1580         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1581
1582         if (!pdata.found) {
1583                 /* this uses the first available slot */
1584                 pdata.found = 2;
1585                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1586         }
1587         mono_domain_unlock (domain);
1588
1589         if (pdata.found != 1)
1590                 g_print ("thunk failed for %p from %p\n", target, code);
1591         g_assert (pdata.found == 1);
1592 }
1593
1594 void
1595 arm_patch (guchar *code, const guchar *target)
1596 {
1597         guint32 ins = *(guint32*)code;
1598         guint32 prim = (ins >> 25) & 7;
1599
1600         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1601         if (prim == 5) { /* 101b */
1602                 /* the diff starts 8 bytes from the branch opcode */
1603                 gint diff = target - code - 8;
1604                 if (diff >= 0) {
1605                         if (diff <= 33554431) {
1606                                 diff >>= 2;
1607                                 ins = (ins & 0xff000000) | diff;
1608                                 *(guint32*)code = ins;
1609                                 return;
1610                         }
1611                 } else {
1612                         /* diff between 0 and -33554432 */
1613                         if (diff >= -33554432) {
1614                                 diff >>= 2;
1615                                 ins = (ins & 0xff000000) | (diff & ~0xff000000);
1616                                 *(guint32*)code = ins;
1617                                 return;
1618                         }
1619                 }
1620                 
1621                 handle_thunk (TRUE, code, target);
1622                 return;
1623         }
1624
1625
1626         if ((ins & 0x0ffffff0) == 0x12fff10) {
1627                 /* branch and exchange: the address is constructed in a reg */
1628                 g_assert_not_reached ();
1629         } else {
1630                 guint32 ccode [3];
1631                 guint32 *tmp = ccode;
1632                 ARM_LDR_IMM (tmp, ARMREG_IP, ARMREG_PC, 0);
1633                 ARM_MOV_REG_REG (tmp, ARMREG_LR, ARMREG_PC);
1634                 ARM_MOV_REG_REG (tmp, ARMREG_PC, ARMREG_IP);
1635                 if (ins == ccode [2]) {
1636                         tmp = (guint32*)code;
1637                         tmp [-1] = (guint32)target;
1638                         return;
1639                 }
1640                 if (ins == ccode [0]) {
1641                         tmp = (guint32*)code;
1642                         tmp [2] = (guint32)target;
1643                         return;
1644                 }
1645                 g_assert_not_reached ();
1646         }
1647 //      g_print ("patched with 0x%08x\n", ins);
1648 }
1649
1650 /* 
1651  * Return the >= 0 uimm8 value if val can be represented with a byte + rotation
1652  * (with the rotation amount in *rot_amount. rot_amount is already adjusted
1653  * to be used with the emit macros.
1654  * Return -1 otherwise.
1655  */
1656 static int
1657 mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount)
1658 {
1659         guint32 res, i;
1660         for (i = 0; i < 31; i+= 2) {
1661                 res = (val << (32 - i)) | (val >> i);
1662                 if (res & ~0xff)
1663                         continue;
1664                 *rot_amount = i? 32 - i: 0;
1665                 return res;
1666         }
1667         return -1;
1668 }
1669
1670 /*
1671  * Emits in code a sequence of instructions that load the value 'val'
1672  * into the dreg register. Uses at most 4 instructions.
1673  */
1674 guint8*
1675 mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
1676 {
1677         int imm8, rot_amount;
1678 #if 0
1679         ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
1680         /* skip the constant pool */
1681         ARM_B (code, 0);
1682         *(int*)code = val;
1683         code += 4;
1684         return code;
1685 #endif
1686         if ((imm8 = mono_arm_is_rotated_imm8 (val, &rot_amount)) >= 0) {
1687                 ARM_MOV_REG_IMM (code, dreg, imm8, rot_amount);
1688         } else if ((imm8 = mono_arm_is_rotated_imm8 (~val, &rot_amount)) >= 0) {
1689                 ARM_MVN_REG_IMM (code, dreg, imm8, rot_amount);
1690         } else {
1691                 if (val & 0xFF) {
1692                         ARM_MOV_REG_IMM8 (code, dreg, (val & 0xFF));
1693                         if (val & 0xFF00) {
1694                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
1695                         }
1696                         if (val & 0xFF0000) {
1697                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
1698                         }
1699                         if (val & 0xFF000000) {
1700                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
1701                         }
1702                 } else if (val & 0xFF00) {
1703                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF00) >> 8, 24);
1704                         if (val & 0xFF0000) {
1705                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
1706                         }
1707                         if (val & 0xFF000000) {
1708                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
1709                         }
1710                 } else if (val & 0xFF0000) {
1711                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF0000) >> 16, 16);
1712                         if (val & 0xFF000000) {
1713                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
1714                         }
1715                 }
1716                 //g_assert_not_reached ();
1717         }
1718         return code;
1719 }
1720
1721 void
1722 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1723 {
1724         MonoInst *ins;
1725         MonoCallInst *call;
1726         guint offset;
1727         guint8 *code = cfg->native_code + cfg->code_len;
1728         MonoInst *last_ins = NULL;
1729         guint last_offset = 0;
1730         int max_len, cpos;
1731         int imm8, rot_amount;
1732
1733         if (cfg->opt & MONO_OPT_PEEPHOLE)
1734                 peephole_pass (cfg, bb);
1735
1736         /* we don't align basic blocks of loops on arm */
1737
1738         if (cfg->verbose_level > 2)
1739                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1740
1741         cpos = bb->max_offset;
1742
1743         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1744                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1745                 //g_assert (!mono_compile_aot);
1746                 //cpos += 6;
1747                 //if (bb->cil_code)
1748                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1749                 /* this is not thread save, but good enough */
1750                 /* fixme: howto handle overflows? */
1751                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
1752         }
1753
1754         ins = bb->code;
1755         while (ins) {
1756                 offset = code - cfg->native_code;
1757
1758                 max_len = ((guint8 *)arm_cpu_desc [ins->opcode])[MONO_INST_LEN];
1759
1760                 if (offset > (cfg->code_size - max_len - 16)) {
1761                         cfg->code_size *= 2;
1762                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1763                         code = cfg->native_code + offset;
1764                 }
1765         //      if (ins->cil_code)
1766         //              g_print ("cil code\n");
1767                 mono_debug_record_line_number (cfg, ins, offset);
1768
1769                 switch (ins->opcode) {
1770                 case OP_MEMORY_BARRIER:
1771                         break;
1772                 case OP_TLS_GET:
1773                         g_assert_not_reached ();
1774                         break;
1775                 /*case OP_BIGMUL:
1776                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
1777                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
1778                         break;
1779                 case OP_BIGMUL_UN:
1780                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
1781                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
1782                         break;*/
1783                 case OP_STOREI1_MEMBASE_IMM:
1784                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFF);
1785                         g_assert (arm_is_imm12 (ins->inst_offset));
1786                         ARM_STRB_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
1787                         break;
1788                 case OP_STOREI2_MEMBASE_IMM:
1789                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFFFF);
1790                         g_assert (arm_is_imm8 (ins->inst_offset));
1791                         ARM_STRH_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
1792                         break;
1793                 case OP_STORE_MEMBASE_IMM:
1794                 case OP_STOREI4_MEMBASE_IMM:
1795                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm);
1796                         g_assert (arm_is_imm12 (ins->inst_offset));
1797                         ARM_STR_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
1798                         break;
1799                 case OP_STOREI1_MEMBASE_REG:
1800                         g_assert (arm_is_imm12 (ins->inst_offset));
1801                         ARM_STRB_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1802                         break;
1803                 case OP_STOREI2_MEMBASE_REG:
1804                         g_assert (arm_is_imm8 (ins->inst_offset));
1805                         ARM_STRH_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1806                         break;
1807                 case OP_STORE_MEMBASE_REG:
1808                 case OP_STOREI4_MEMBASE_REG:
1809                         /* this case is special, since it happens for spill code after lowering has been called */
1810                         if (arm_is_imm12 (ins->inst_offset)) {
1811                                 ARM_STR_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1812                         } else {
1813                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
1814                                 ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
1815                         }
1816                         break;
1817                 case OP_STOREI1_MEMINDEX:
1818                         ARM_STRB_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
1819                         break;
1820                 case OP_STOREI2_MEMINDEX:
1821                         /* note: the args are reversed in the macro */
1822                         ARM_STRH_REG_REG (code, ins->inst_destbasereg, ins->sreg1, ins->sreg2);
1823                         break;
1824                 case OP_STORE_MEMINDEX:
1825                 case OP_STOREI4_MEMINDEX:
1826                         ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
1827                         break;
1828                 case CEE_LDIND_I:
1829                 case CEE_LDIND_I4:
1830                 case CEE_LDIND_U4:
1831                         g_assert_not_reached ();
1832                         break;
1833                 case OP_LOADU4_MEM:
1834                         g_assert_not_reached ();
1835                         break;
1836                 case OP_LOAD_MEMINDEX:
1837                 case OP_LOADI4_MEMINDEX:
1838                 case OP_LOADU4_MEMINDEX:
1839                         ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
1840                         break;
1841                 case OP_LOADI1_MEMINDEX:
1842                         /* note: the args are reversed in the macro */
1843                         ARM_LDRSB_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
1844                         break;
1845                 case OP_LOADU1_MEMINDEX:
1846                         ARM_LDRB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
1847                         break;
1848                 case OP_LOADI2_MEMINDEX:
1849                         /* note: the args are reversed in the macro */
1850                         ARM_LDRSH_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
1851                         break;
1852                 case OP_LOADU2_MEMINDEX:
1853                         /* note: the args are reversed in the macro */
1854                         ARM_LDRH_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
1855                         break;
1856                 case OP_LOAD_MEMBASE:
1857                 case OP_LOADI4_MEMBASE:
1858                 case OP_LOADU4_MEMBASE:
1859                         /* this case is special, since it happens for spill code after lowering has been called */
1860                         if (arm_is_imm12 (ins->inst_offset)) {
1861                                 ARM_LDR_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1862                         } else {
1863                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
1864                                 ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
1865                         }
1866                         break;
1867                 case OP_LOADI1_MEMBASE:
1868                         g_assert (arm_is_imm8 (ins->inst_offset));
1869                         ARM_LDRSB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1870                         break;
1871                 case OP_LOADU1_MEMBASE:
1872                         g_assert (arm_is_imm12 (ins->inst_offset));
1873                         ARM_LDRB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1874                         break;
1875                 case OP_LOADU2_MEMBASE:
1876                         g_assert (arm_is_imm8 (ins->inst_offset));
1877                         ARM_LDRH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1878                         break;
1879                 case OP_LOADI2_MEMBASE:
1880                         g_assert (arm_is_imm8 (ins->inst_offset));
1881                         ARM_LDRSH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1882                         break;
1883                 case CEE_CONV_I1:
1884                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 24);
1885                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 24);
1886                         break;
1887                 case CEE_CONV_I2:
1888                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
1889                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 16);
1890                         break;
1891                 case CEE_CONV_U1:
1892                         ARM_AND_REG_IMM8 (code, ins->dreg, ins->sreg1, 0xff);
1893                         break;
1894                 case CEE_CONV_U2:
1895                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
1896                         ARM_SHR_IMM (code, ins->dreg, ins->dreg, 16);
1897                         break;
1898                 case OP_COMPARE:
1899                         ARM_CMP_REG_REG (code, ins->sreg1, ins->sreg2);
1900                         break;
1901                 case OP_COMPARE_IMM:
1902                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1903                         g_assert (imm8 >= 0);
1904                         ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount);
1905                         break;
1906                 case CEE_BREAK:
1907                         *(int*)code = 0xe7f001f0;
1908                         *(int*)code = 0xef9f0001;
1909                         code += 4;
1910                         //ARM_DBRK (code);
1911                         break;
1912                 case OP_ADDCC:
1913                         ARM_ADDS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1914                         break;
1915                 case CEE_ADD:
1916                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1917                         break;
1918                 case OP_ADC:
1919                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1920                         break;
1921                 case OP_ADDCC_IMM:
1922                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1923                         g_assert (imm8 >= 0);
1924                         ARM_ADDS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1925                         break;
1926                 case OP_ADD_IMM:
1927                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1928                         g_assert (imm8 >= 0);
1929                         ARM_ADD_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1930                         break;
1931                 case OP_ADC_IMM:
1932                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1933                         g_assert (imm8 >= 0);
1934                         ARM_ADCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1935                         break;
1936                 case CEE_ADD_OVF:
1937                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1938                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1939                         break;
1940                 case CEE_ADD_OVF_UN:
1941                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1942                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1943                         break;
1944                 case CEE_SUB_OVF:
1945                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1946                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1947                         break;
1948                 case CEE_SUB_OVF_UN:
1949                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1950                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
1951                         break;
1952                 case OP_ADD_OVF_CARRY:
1953                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1954                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1955                         break;
1956                 case OP_ADD_OVF_UN_CARRY:
1957                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1958                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1959                         break;
1960                 case OP_SUB_OVF_CARRY:
1961                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1962                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1963                         break;
1964                 case OP_SUB_OVF_UN_CARRY:
1965                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1966                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
1967                         break;
1968                 case OP_SUBCC:
1969                         ARM_SUBS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1970                         break;
1971                 case OP_SUBCC_IMM:
1972                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1973                         g_assert (imm8 >= 0);
1974                         ARM_SUBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1975                         break;
1976                 case CEE_SUB:
1977                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1978                         break;
1979                 case OP_SBB:
1980                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1981                         break;
1982                 case OP_SUB_IMM:
1983                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1984                         g_assert (imm8 >= 0);
1985                         ARM_SUB_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1986                         break;
1987                 case OP_SBB_IMM:
1988                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1989                         g_assert (imm8 >= 0);
1990                         ARM_SBCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1991                         break;
1992                 case OP_ARM_RSBS_IMM:
1993                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1994                         g_assert (imm8 >= 0);
1995                         ARM_RSBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1996                         break;
1997                 case OP_ARM_RSC_IMM:
1998                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1999                         g_assert (imm8 >= 0);
2000                         ARM_RSC_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2001                         break;
2002                 case CEE_AND:
2003                         ARM_AND_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2004                         break;
2005                 case OP_AND_IMM:
2006                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2007                         g_assert (imm8 >= 0);
2008                         ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2009                         break;
2010                 case CEE_DIV:
2011                 case CEE_DIV_UN:
2012                 case OP_DIV_IMM:
2013                 case CEE_REM:
2014                 case CEE_REM_UN:
2015                 case OP_REM_IMM:
2016                         /* crappy ARM arch doesn't have a DIV instruction */
2017                         g_assert_not_reached ();
2018                 case CEE_OR:
2019                         ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2020                         break;
2021                 case OP_OR_IMM:
2022                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2023                         g_assert (imm8 >= 0);
2024                         ARM_ORR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2025                         break;
2026                 case CEE_XOR:
2027                         ARM_EOR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2028                         break;
2029                 case OP_XOR_IMM:
2030                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2031                         g_assert (imm8 >= 0);
2032                         ARM_EOR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2033                         break;
2034                 case CEE_SHL:
2035                         ARM_SHL_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2036                         break;
2037                 case OP_SHL_IMM:
2038                         if (ins->inst_imm)
2039                                 ARM_SHL_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2040                         break;
2041                 case CEE_SHR:
2042                         ARM_SAR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2043                         break;
2044                 case OP_SHR_IMM:
2045                         if (ins->inst_imm)
2046                                 ARM_SAR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2047                         break;
2048                 case OP_SHR_UN_IMM:
2049                         if (ins->inst_imm)
2050                                 ARM_SHR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2051                         break;
2052                 case CEE_SHR_UN:
2053                         ARM_SHR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2054                         break;
2055                 case CEE_NOT:
2056                         ARM_MVN_REG_REG (code, ins->dreg, ins->sreg1);
2057                         break;
2058                 case CEE_NEG:
2059                         ARM_RSB_REG_IMM8 (code, ins->dreg, ins->sreg1, 0);
2060                         break;
2061                 case CEE_MUL:
2062                         if (ins->dreg == ins->sreg2)
2063                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2064                         else
2065                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg2, ins->sreg1);
2066                         break;
2067                 case OP_MUL_IMM:
2068                         g_assert_not_reached ();
2069                         break;
2070                 case CEE_MUL_OVF:
2071                         /* FIXME: handle ovf/ sreg2 != dreg */
2072                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2073                         break;
2074                 case CEE_MUL_OVF_UN:
2075                         /* FIXME: handle ovf/ sreg2 != dreg */
2076                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2077                         break;
2078                 case OP_ICONST:
2079                 case OP_SETREGIMM:
2080                         code = mono_arm_emit_load_imm (code, ins->dreg, ins->inst_c0);
2081                         break;
2082                 case OP_AOTCONST:
2083                         g_assert_not_reached ();
2084                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2085                         break;
2086                 case CEE_CONV_I4:
2087                 case CEE_CONV_U4:
2088                 case OP_MOVE:
2089                 case OP_SETREG:
2090                         if (ins->dreg != ins->sreg1)
2091                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2092                         break;
2093                 case OP_SETLRET: {
2094                         int saved = ins->sreg2;
2095                         if (ins->sreg2 == ARM_LSW_REG) {
2096                                 ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg2);
2097                                 saved = ARMREG_LR;
2098                         }
2099                         if (ins->sreg1 != ARM_LSW_REG)
2100                                 ARM_MOV_REG_REG (code, ARM_LSW_REG, ins->sreg1);
2101                         if (saved != ARM_MSW_REG)
2102                                 ARM_MOV_REG_REG (code, ARM_MSW_REG, saved);
2103                         break;
2104                 }
2105                 case OP_SETFREG:
2106                 case OP_FMOVE:
2107 #ifdef ARM_FPU_FPA
2108                         ARM_MVFD (code, ins->dreg, ins->sreg1);
2109 #elif defined(ARM_FPU_VFP)
2110                         ARM_CPYD (code, ins->dreg, ins->sreg1);
2111 #endif
2112                         break;
2113                 case OP_FCONV_TO_R4:
2114 #ifdef ARM_FPU_FPA
2115                         ARM_MVFS (code, ins->dreg, ins->sreg1);
2116 #elif defined(ARM_FPU_VFP)
2117                         ARM_CVTD (code, ins->dreg, ins->sreg1);
2118                         ARM_CVTS (code, ins->dreg, ins->dreg);
2119 #endif
2120                         break;
2121                 case CEE_JMP:
2122                         /*
2123                          * Keep in sync with mono_arch_emit_epilog
2124                          */
2125                         g_assert (!cfg->method->save_lmf);
2126                         code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
2127                         ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP)) | ((1 << ARMREG_LR)));
2128                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2129                         ARM_B (code, 0);
2130                         break;
2131                 case OP_CHECK_THIS:
2132                         /* ensure ins->sreg1 is not NULL */
2133                         ARM_LDR_IMM (code, ARMREG_LR, ins->sreg1, 0);
2134                         break;
2135                 case OP_ARGLIST: {
2136 #if ARM_PORT
2137                         if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2138                                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2139                         } else {
2140                                 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2141                                 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2142                         }
2143                         ppc_stw (code, ppc_r11, 0, ins->sreg1);
2144 #endif
2145                         break;
2146                 }
2147                 case OP_FCALL:
2148                 case OP_LCALL:
2149                 case OP_VCALL:
2150                 case OP_VOIDCALL:
2151                 case CEE_CALL:
2152                         call = (MonoCallInst*)ins;
2153                         if (ins->flags & MONO_INST_HAS_METHOD)
2154                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2155                         else
2156                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2157                         if (cfg->method->dynamic) {
2158                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
2159                                 ARM_B (code, 0);
2160                                 *(gpointer*)code = NULL;
2161                                 code += 4;
2162                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2163                                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2164                         } else {
2165                                 ARM_BL (code, 0);
2166                         }
2167                         break;
2168                 case OP_FCALL_REG:
2169                 case OP_LCALL_REG:
2170                 case OP_VCALL_REG:
2171                 case OP_VOIDCALL_REG:
2172                 case OP_CALL_REG:
2173                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2174                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
2175                         break;
2176                 case OP_FCALL_MEMBASE:
2177                 case OP_LCALL_MEMBASE:
2178                 case OP_VCALL_MEMBASE:
2179                 case OP_VOIDCALL_MEMBASE:
2180                 case OP_CALL_MEMBASE:
2181                         g_assert (arm_is_imm12 (ins->inst_offset));
2182                         g_assert (ins->sreg1 != ARMREG_LR);
2183                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2184                         ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
2185                         break;
2186                 case OP_OUTARG:
2187                         g_assert_not_reached ();
2188                         break;
2189                 case OP_LOCALLOC: {
2190                         /* keep alignment */
2191                         int alloca_waste = cfg->param_area;
2192                         alloca_waste += 7;
2193                         alloca_waste &= ~7;
2194                         /* round the size to 8 bytes */
2195                         ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
2196                         ARM_BIC_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
2197                         ARM_ADD_REG_IMM8 (code, ins->dreg, ins->dreg, alloca_waste);
2198                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ins->dreg);
2199                         /* memzero the area: dreg holds the size, sp is the pointer */
2200                         if (ins->flags & MONO_INST_INIT) {
2201                                 guint8 *start_loop, *branch_to_cond;
2202                                 ARM_MOV_REG_IMM8 (code, ARMREG_LR, 0);
2203                                 branch_to_cond = code;
2204                                 ARM_B (code, 0);
2205                                 start_loop = code;
2206                                 ARM_STR_REG_REG (code, ARMREG_LR, ARMREG_SP, ins->dreg);
2207                                 arm_patch (branch_to_cond, code);
2208                                 /* decrement by 4 and set flags */
2209                                 ARM_SUBS_REG_IMM8 (code, ins->dreg, ins->dreg, 4);
2210                                 ARM_B_COND (code, ARMCOND_LT, 0);
2211                                 arm_patch (code - 4, start_loop);
2212                         }
2213                         ARM_ADD_REG_IMM8 (code, ins->dreg, ARMREG_SP, alloca_waste);
2214                         break;
2215                 }
2216                 case CEE_RET:
2217                         g_assert_not_reached ();
2218                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_LR);
2219                         break;
2220                 case CEE_THROW: {
2221                         if (ins->sreg1 != ARMREG_R0)
2222                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2223                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2224                                              (gpointer)"mono_arch_throw_exception");
2225                         if (cfg->method->dynamic) {
2226                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
2227                                 ARM_B (code, 0);
2228                                 *(gpointer*)code = NULL;
2229                                 code += 4;
2230                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2231                                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2232                         } else {
2233                                 ARM_BL (code, 0);
2234                         }
2235                         break;
2236                 }
2237                 case OP_RETHROW: {
2238                         if (ins->sreg1 != ARMREG_R0)
2239                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2240                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2241                                              (gpointer)"mono_arch_rethrow_exception");
2242                         if (cfg->method->dynamic) {
2243                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
2244                                 ARM_B (code, 0);
2245                                 *(gpointer*)code = NULL;
2246                                 code += 4;
2247                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2248                                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2249                         } else {
2250                                 ARM_BL (code, 0);
2251                         }
2252                         break;
2253                 }
2254                 case OP_START_HANDLER:
2255                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2256                                 ARM_STR_IMM (code, ARMREG_LR, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2257                         } else {
2258                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2259                                 ARM_STR_REG_REG (code, ARMREG_LR, ins->inst_left->inst_basereg, ARMREG_IP);
2260                         }
2261                         break;
2262                 case OP_ENDFILTER:
2263                         if (ins->sreg1 != ARMREG_R0)
2264                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2265                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2266                                 ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2267                         } else {
2268                                 g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
2269                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2270                                 ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
2271                         }
2272                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2273                         break;
2274                 case CEE_ENDFINALLY:
2275                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2276                                 ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2277                         } else {
2278                                 g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
2279                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2280                                 ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
2281                         }
2282                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2283                         break;
2284                 case OP_CALL_HANDLER: 
2285                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2286                         ARM_BL (code, 0);
2287                         break;
2288                 case OP_LABEL:
2289                         ins->inst_c0 = code - cfg->native_code;
2290                         break;
2291                 case CEE_BR:
2292                         if (ins->flags & MONO_INST_BRLABEL) {
2293                                 /*if (ins->inst_i0->inst_c0) {
2294                                         ARM_B (code, 0);
2295                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2296                                 } else*/ {
2297                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2298                                         ARM_B (code, 0);
2299                                 }
2300                         } else {
2301                                 /*if (ins->inst_target_bb->native_offset) {
2302                                         ARM_B (code, 0);
2303                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2304                                 } else*/ {
2305                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2306                                         ARM_B (code, 0);
2307                                 } 
2308                         }
2309                         break;
2310                 case OP_BR_REG:
2311                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
2312                         break;
2313                 case CEE_SWITCH:
2314                         /* 
2315                          * In the normal case we have:
2316                          *      ldr pc, [pc, ins->sreg1 << 2]
2317                          *      nop
2318                          * If aot, we have:
2319                          *      ldr lr, [pc, ins->sreg1 << 2]
2320                          *      add pc, pc, lr
2321                          * After follows the data.
2322                          * FIXME: add aot support.
2323                          */
2324                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
2325                         if (offset > (cfg->code_size - max_len - 16)) {
2326                                 cfg->code_size += max_len;
2327                                 cfg->code_size *= 2;
2328                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2329                                 code = cfg->native_code + offset;
2330                         }
2331                         ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_PC, ins->sreg1, ARMSHIFT_LSL, 2);
2332                         ARM_NOP (code);
2333                         code += 4 * GPOINTER_TO_INT (ins->klass);
2334                         break;
2335                 case OP_CEQ:
2336                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
2337                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
2338                         break;
2339                 case OP_CLT:
2340                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2341                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LT);
2342                         break;
2343                 case OP_CLT_UN:
2344                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2345                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LO);
2346                         break;
2347                 case OP_CGT:
2348                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2349                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_GT);
2350                         break;
2351                 case OP_CGT_UN:
2352                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2353                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_HI);
2354                         break;
2355                 case OP_COND_EXC_EQ:
2356                 case OP_COND_EXC_NE_UN:
2357                 case OP_COND_EXC_LT:
2358                 case OP_COND_EXC_LT_UN:
2359                 case OP_COND_EXC_GT:
2360                 case OP_COND_EXC_GT_UN:
2361                 case OP_COND_EXC_GE:
2362                 case OP_COND_EXC_GE_UN:
2363                 case OP_COND_EXC_LE:
2364                 case OP_COND_EXC_LE_UN:
2365                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2366                         break;
2367                 case OP_COND_EXC_C:
2368                 case OP_COND_EXC_OV:
2369                 case OP_COND_EXC_NC:
2370                 case OP_COND_EXC_NO:
2371                         g_assert_not_reached ();
2372                         break;
2373                 case CEE_BEQ:
2374                 case CEE_BNE_UN:
2375                 case CEE_BLT:
2376                 case CEE_BLT_UN:
2377                 case CEE_BGT:
2378                 case CEE_BGT_UN:
2379                 case CEE_BGE:
2380                 case CEE_BGE_UN:
2381                 case CEE_BLE:
2382                 case CEE_BLE_UN:
2383                         EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2384                         break;
2385
2386                 /* floating point opcodes */
2387 #ifdef ARM_FPU_FPA
2388                 case OP_R8CONST:
2389                         /* FIXME: we can optimize the imm load by dealing with part of 
2390                          * the displacement in LDFD (aligning to 512).
2391                          */
2392                         code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2393                         ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
2394                         break;
2395                 case OP_R4CONST:
2396                         code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2397                         ARM_LDFS (code, ins->dreg, ARMREG_LR, 0);
2398                         break;
2399                 case OP_STORER8_MEMBASE_REG:
2400                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2401                         ARM_STFD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2402                         break;
2403                 case OP_LOADR8_MEMBASE:
2404                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2405                         ARM_LDFD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2406                         break;
2407                 case OP_STORER4_MEMBASE_REG:
2408                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2409                         ARM_STFS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2410                         break;
2411                 case OP_LOADR4_MEMBASE:
2412                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2413                         ARM_LDFS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2414                         break;
2415                 case CEE_CONV_R_UN: {
2416                         int tmpreg;
2417                         tmpreg = ins->dreg == 0? 1: 0;
2418                         ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
2419                         ARM_FLTD (code, ins->dreg, ins->sreg1);
2420                         ARM_B_COND (code, ARMCOND_GE, 8);
2421                         /* save the temp register */
2422                         ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
2423                         ARM_STFD (code, tmpreg, ARMREG_SP, 0);
2424                         ARM_LDFD (code, tmpreg, ARMREG_PC, 12);
2425                         ARM_FPA_ADFD (code, ins->dreg, ins->dreg, tmpreg);
2426                         ARM_LDFD (code, tmpreg, ARMREG_SP, 0);
2427                         ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
2428                         /* skip the constant pool */
2429                         ARM_B (code, 8);
2430                         code += 4;
2431                         *(int*)code = 0x41f00000;
2432                         code += 4;
2433                         *(int*)code = 0;
2434                         code += 4;
2435                         /* FIXME: adjust:
2436                          * ldfltd  ftemp, [pc, #8] 0x41f00000 0x00000000
2437                          * adfltd  fdest, fdest, ftemp
2438                          */
2439                         break;
2440                 }
2441                 case CEE_CONV_R4:
2442                         ARM_FLTS (code, ins->dreg, ins->sreg1);
2443                         break;
2444                 case CEE_CONV_R8:
2445                         ARM_FLTD (code, ins->dreg, ins->sreg1);
2446                         break;
2447 #elif defined(ARM_FPU_VFP)
2448                 case OP_R8CONST:
2449                         /* FIXME: we can optimize the imm load by dealing with part of 
2450                          * the displacement in LDFD (aligning to 512).
2451                          */
2452                         code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2453                         ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
2454                         break;
2455                 case OP_R4CONST:
2456                         code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2457                         ARM_FLDS (code, ins->dreg, ARMREG_LR, 0);
2458                         ARM_CVTS (code, ins->dreg, ins->dreg);
2459                         break;
2460                 case OP_STORER8_MEMBASE_REG:
2461                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2462                         ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2463                         break;
2464                 case OP_LOADR8_MEMBASE:
2465                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2466                         ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2467                         break;
2468                 case OP_STORER4_MEMBASE_REG:
2469                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2470                         ARM_FSTS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2471                         break;
2472                 case OP_LOADR4_MEMBASE:
2473                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2474                         ARM_FLDS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2475                         break;
2476                 case CEE_CONV_R_UN: {
2477                         g_assert_not_reached ();
2478                         break;
2479                 }
2480                 case CEE_CONV_R4:
2481                         g_assert_not_reached ();
2482                         //ARM_FLTS (code, ins->dreg, ins->sreg1);
2483                         break;
2484                 case CEE_CONV_R8:
2485                         g_assert_not_reached ();
2486                         //ARM_FLTD (code, ins->dreg, ins->sreg1);
2487                         break;
2488 #endif
2489                 case OP_FCONV_TO_I1:
2490                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2491                         break;
2492                 case OP_FCONV_TO_U1:
2493                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2494                         break;
2495                 case OP_FCONV_TO_I2:
2496                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2497                         break;
2498                 case OP_FCONV_TO_U2:
2499                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2500                         break;
2501                 case OP_FCONV_TO_I4:
2502                 case OP_FCONV_TO_I:
2503                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2504                         break;
2505                 case OP_FCONV_TO_U4:
2506                 case OP_FCONV_TO_U:
2507                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2508                         break;
2509                 case OP_FCONV_TO_I8:
2510                 case OP_FCONV_TO_U8:
2511                         g_assert_not_reached ();
2512                         /* Implemented as helper calls */
2513                         break;
2514                 case OP_LCONV_TO_R_UN:
2515                         g_assert_not_reached ();
2516                         /* Implemented as helper calls */
2517                         break;
2518                 case OP_LCONV_TO_OVF_I: {
2519 #if ARM_PORT
2520                         guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2521                         // Check if its negative
2522                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2523                         negative_branch = code;
2524                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2525                         // Its positive msword == 0
2526                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2527                         msword_positive_branch = code;
2528                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2529
2530                         ovf_ex_target = code;
2531                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2532                         // Negative
2533                         ppc_patch (negative_branch, code);
2534                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2535                         msword_negative_branch = code;
2536                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2537                         ppc_patch (msword_negative_branch, ovf_ex_target);
2538                         
2539                         ppc_patch (msword_positive_branch, code);
2540                         if (ins->dreg != ins->sreg1)
2541                                 ppc_mr (code, ins->dreg, ins->sreg1);
2542 #endif
2543                         if (ins->dreg != ins->sreg1)
2544                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2545                         break;
2546                 }
2547 #ifdef ARM_FPU_FPA
2548                 case OP_FADD:
2549                         ARM_FPA_ADFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2550                         break;
2551                 case OP_FSUB:
2552                         ARM_FPA_SUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2553                         break;          
2554                 case OP_FMUL:
2555                         ARM_FPA_MUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2556                         break;          
2557                 case OP_FDIV:
2558                         ARM_FPA_DVFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2559                         break;          
2560                 case OP_FNEG:
2561                         ARM_MNFD (code, ins->dreg, ins->sreg1);
2562                         break;
2563 #elif defined(ARM_FPU_VFP)
2564                 case OP_FADD:
2565                         ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2);
2566                         break;
2567                 case OP_FSUB:
2568                         ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2);
2569                         break;          
2570                 case OP_FMUL:
2571                         ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2);
2572                         break;          
2573                 case OP_FDIV:
2574                         ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2);
2575                         break;          
2576                 case OP_FNEG:
2577                         ARM_NEGD (code, ins->dreg, ins->sreg1);
2578                         break;
2579 #endif
2580                 case OP_FREM:
2581                         /* emulated */
2582                         g_assert_not_reached ();
2583                         break;
2584                 case OP_FCOMPARE:
2585                         /* each fp compare op needs to do its own */
2586                         g_assert_not_reached ();
2587                         //ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2588                         break;
2589                 case OP_FCEQ:
2590 #ifdef ARM_FPU_FPA
2591                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2592 #elif defined(ARM_FPU_VFP)
2593                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2594 #endif
2595                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
2596                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
2597                         break;
2598                 case OP_FCLT:
2599 #ifdef ARM_FPU_FPA
2600                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2601 #elif defined(ARM_FPU_VFP)
2602                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2603 #endif
2604                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2605                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2606                         break;
2607                 case OP_FCLT_UN:
2608 #ifdef ARM_FPU_FPA
2609                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2610 #elif defined(ARM_FPU_VFP)
2611                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2612 #endif
2613                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2614                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2615                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
2616                         break;
2617                 case OP_FCGT:
2618                         /* swapped */
2619 #ifdef ARM_FPU_FPA
2620                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2621 #elif defined(ARM_FPU_VFP)
2622                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2623 #endif
2624                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2625                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2626                         break;
2627                 case OP_FCGT_UN:
2628                         /* swapped */
2629 #ifdef ARM_FPU_FPA
2630                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2631 #elif defined(ARM_FPU_VFP)
2632                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2633 #endif
2634                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2635                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2636                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
2637                         break;
2638                 /* ARM FPA flags table:
2639                  * N        Less than               ARMCOND_MI
2640                  * Z        Equal                   ARMCOND_EQ
2641                  * C        Greater Than or Equal   ARMCOND_CS
2642                  * V        Unordered               ARMCOND_VS
2643                  */
2644                 case OP_FBEQ:
2645 #ifdef ARM_FPU_FPA
2646                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2647 #elif defined(ARM_FPU_VFP)
2648                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2649 #endif
2650                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2651                         break;
2652                 case OP_FBNE_UN:
2653 #ifdef ARM_FPU_FPA
2654                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2655 #elif defined(ARM_FPU_VFP)
2656                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2657 #endif
2658                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2659                         break;
2660                 case OP_FBLT:
2661 #ifdef ARM_FPU_FPA
2662                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2663 #elif defined(ARM_FPU_VFP)
2664                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2665 #endif
2666                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
2667                         break;
2668                 case OP_FBLT_UN:
2669 #ifdef ARM_FPU_FPA
2670                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2671 #elif defined(ARM_FPU_VFP)
2672                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2673 #endif
2674                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2675                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
2676                         break;
2677                 case OP_FBGT:
2678 #ifdef ARM_FPU_FPA
2679                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2680 #elif defined(ARM_FPU_VFP)
2681                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2682 #endif
2683                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
2684                         break;
2685                 case OP_FBGT_UN:
2686 #ifdef ARM_FPU_FPA
2687                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2688 #elif defined(ARM_FPU_VFP)
2689                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2690 #endif
2691                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2692                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
2693                         break;
2694                 case OP_FBGE:
2695 #ifdef ARM_FPU_FPA
2696                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2697 #elif defined(ARM_FPU_VFP)
2698                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2699 #endif
2700                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
2701                         break;
2702                 case OP_FBGE_UN:
2703 #ifdef ARM_FPU_FPA
2704                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2705 #elif defined(ARM_FPU_VFP)
2706                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2707 #endif
2708                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2709                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
2710                         break;
2711                 case OP_FBLE:
2712 #ifdef ARM_FPU_FPA
2713                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2714 #elif defined(ARM_FPU_VFP)
2715                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2716 #endif
2717                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); /* swapped */
2718                         break;
2719                 case OP_FBLE_UN:
2720 #ifdef ARM_FPU_FPA
2721                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2722 #elif defined(ARM_FPU_VFP)
2723                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2724 #endif
2725                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2726                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE); /* swapped */
2727                         break;
2728                 case CEE_CKFINITE: {
2729                         /*ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2730                         ppc_lwz (code, ppc_r11, -8, ppc_sp);
2731                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2732                         ppc_addis (code, ppc_r11, ppc_r11, -32752);
2733                         ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2734                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");*/
2735                         g_assert_not_reached ();
2736                         break;
2737                 }
2738                 default:
2739                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2740                         g_assert_not_reached ();
2741                 }
2742
2743                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2744                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2745                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2746                         g_assert_not_reached ();
2747                 }
2748                
2749                 cpos += max_len;
2750
2751                 last_ins = ins;
2752                 last_offset = offset;
2753                 
2754                 ins = ins->next;
2755         }
2756
2757         cfg->code_len = code - cfg->native_code;
2758 }
2759
2760 void
2761 mono_arch_register_lowlevel_calls (void)
2762 {
2763 }
2764
2765 #define patch_lis_ori(ip,val) do {\
2766                 guint16 *__lis_ori = (guint16*)(ip);    \
2767                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
2768                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
2769         } while (0)
2770
2771 void
2772 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
2773 {
2774         MonoJumpInfo *patch_info;
2775
2776         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
2777                 unsigned char *ip = patch_info->ip.i + code;
2778                 const unsigned char *target;
2779
2780                 if (patch_info->type == MONO_PATCH_INFO_SWITCH) {
2781                         gpointer *jt = (gpointer*)(ip + 8);
2782                         int i;
2783                         /* jt is the inlined jump table, 2 instructions after ip
2784                          * In the normal case we store the absolute addresses,
2785                          * otherwise the displacements.
2786                          */
2787                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
2788                                 jt [i] = code + (int)patch_info->data.table->table [i];
2789                         }
2790                         continue;
2791                 }
2792                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
2793
2794                 switch (patch_info->type) {
2795                 case MONO_PATCH_INFO_IP:
2796                         g_assert_not_reached ();
2797                         patch_lis_ori (ip, ip);
2798                         continue;
2799                 case MONO_PATCH_INFO_METHOD_REL:
2800                         g_assert_not_reached ();
2801                         *((gpointer *)(ip)) = code + patch_info->data.offset;
2802                         continue;
2803                 case MONO_PATCH_INFO_METHODCONST:
2804                 case MONO_PATCH_INFO_CLASS:
2805                 case MONO_PATCH_INFO_IMAGE:
2806                 case MONO_PATCH_INFO_FIELD:
2807                 case MONO_PATCH_INFO_VTABLE:
2808                 case MONO_PATCH_INFO_IID:
2809                 case MONO_PATCH_INFO_SFLDA:
2810                 case MONO_PATCH_INFO_LDSTR:
2811                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
2812                 case MONO_PATCH_INFO_LDTOKEN:
2813                         g_assert_not_reached ();
2814                         /* from OP_AOTCONST : lis + ori */
2815                         patch_lis_ori (ip, target);
2816                         continue;
2817                 case MONO_PATCH_INFO_R4:
2818                 case MONO_PATCH_INFO_R8:
2819                         g_assert_not_reached ();
2820                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
2821                         continue;
2822                 case MONO_PATCH_INFO_EXC_NAME:
2823                         g_assert_not_reached ();
2824                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
2825                         continue;
2826                 case MONO_PATCH_INFO_NONE:
2827                 case MONO_PATCH_INFO_BB_OVF:
2828                 case MONO_PATCH_INFO_EXC_OVF:
2829                         /* everything is dealt with at epilog output time */
2830                         continue;
2831                 default:
2832                         break;
2833                 }
2834                 arm_patch (ip, target);
2835         }
2836 }
2837
2838 /*
2839  * Stack frame layout:
2840  * 
2841  *   ------------------- fp
2842  *      MonoLMF structure or saved registers
2843  *   -------------------
2844  *      locals
2845  *   -------------------
2846  *      spilled regs
2847  *   -------------------
2848  *      optional 8 bytes for tracing
2849  *   -------------------
2850  *      param area             size is cfg->param_area
2851  *   ------------------- sp
2852  */
2853 guint8 *
2854 mono_arch_emit_prolog (MonoCompile *cfg)
2855 {
2856         MonoMethod *method = cfg->method;
2857         MonoBasicBlock *bb;
2858         MonoMethodSignature *sig;
2859         MonoInst *inst;
2860         int alloc_size, pos, max_offset, i, rot_amount;
2861         guint8 *code;
2862         CallInfo *cinfo;
2863         int tracing = 0;
2864         int lmf_offset = 0;
2865         int prev_sp_offset;
2866
2867         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
2868                 tracing = 1;
2869
2870         sig = mono_method_signature (method);
2871         cfg->code_size = 256 + sig->param_count * 20;
2872         code = cfg->native_code = g_malloc (cfg->code_size);
2873
2874         ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
2875
2876         alloc_size = cfg->stack_offset;
2877         pos = 0;
2878
2879         if (!method->save_lmf) {
2880                 ARM_PUSH (code, (cfg->used_int_regs | (1 << ARMREG_IP) | (1 << ARMREG_LR)));
2881                 prev_sp_offset = 8; /* ip and lr */
2882                 for (i = 0; i < 16; ++i) {
2883                         if (cfg->used_int_regs & (1 << i))
2884                                 prev_sp_offset += 4;
2885                 }
2886         } else {
2887                 ARM_PUSH (code, 0x5ff0);
2888                 prev_sp_offset = 4 * 10; /* all but r0-r3, sp and pc */
2889                 pos += sizeof (MonoLMF) - prev_sp_offset;
2890                 lmf_offset = pos;
2891         }
2892         alloc_size += pos;
2893         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
2894         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
2895                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2896                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
2897         }
2898
2899         /* the stack used in the pushed regs */
2900         if (prev_sp_offset & 4)
2901                 alloc_size += 4;
2902         cfg->stack_usage = alloc_size;
2903         if (alloc_size) {
2904                 if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
2905                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
2906                 } else {
2907                         code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
2908                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
2909                 }
2910         }
2911         if (cfg->frame_reg != ARMREG_SP)
2912                 ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
2913         //g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
2914         prev_sp_offset += alloc_size;
2915
2916         /* compute max_offset in order to use short forward jumps
2917          * we could skip do it on arm because the immediate displacement
2918          * for jumps is large enough, it may be useful later for constant pools
2919          */
2920         max_offset = 0;
2921         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
2922                 MonoInst *ins = bb->code;
2923                 bb->max_offset = max_offset;
2924
2925                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
2926                         max_offset += 6; 
2927
2928                 while (ins) {
2929                         max_offset += ((guint8 *)arm_cpu_desc [ins->opcode])[MONO_INST_LEN];
2930                         ins = ins->next;
2931                 }
2932         }
2933
2934         /* load arguments allocated to register from the stack */
2935         pos = 0;
2936
2937         cinfo = calculate_sizes (sig, sig->pinvoke);
2938
2939         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2940                 ArgInfo *ainfo = &cinfo->ret;
2941                 inst = cfg->ret;
2942                 g_assert (arm_is_imm12 (inst->inst_offset));
2943                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2944         }
2945         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2946                 ArgInfo *ainfo = cinfo->args + i;
2947                 inst = cfg->varinfo [pos];
2948                 
2949                 if (cfg->verbose_level > 2)
2950                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
2951                 if (inst->opcode == OP_REGVAR) {
2952                         if (ainfo->regtype == RegTypeGeneral)
2953                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
2954                         else if (ainfo->regtype == RegTypeFP) {
2955                                 g_assert_not_reached ();
2956                         } else if (ainfo->regtype == RegTypeBase) {
2957                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
2958                                 ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
2959                         } else
2960                                 g_assert_not_reached ();
2961
2962                         if (cfg->verbose_level > 2)
2963                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
2964                 } else {
2965                         /* the argument should be put on the stack: FIXME handle size != word  */
2966                         if (ainfo->regtype == RegTypeGeneral) {
2967                                 switch (ainfo->size) {
2968                                 case 1:
2969                                         if (arm_is_imm12 (inst->inst_offset))
2970                                                 ARM_STRB_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2971                                         else {
2972                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2973                                                 ARM_STRB_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
2974                                         }
2975                                         break;
2976                                 case 2:
2977                                         if (arm_is_imm8 (inst->inst_offset)) {
2978                                                 ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2979                                         } else {
2980                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2981                                                 ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
2982                                                 ARM_STRH_IMM (code, ainfo->reg, ARMREG_IP, 0);
2983                                         }
2984                                         break;
2985                                 case 8:
2986                                         g_assert (arm_is_imm12 (inst->inst_offset));
2987                                         ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2988                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
2989                                         ARM_STR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2990                                         break;
2991                                 default:
2992                                         if (arm_is_imm12 (inst->inst_offset)) {
2993                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2994                                         } else {
2995                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2996                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
2997                                         }
2998                                         break;
2999                                 }
3000                         } else if (ainfo->regtype == RegTypeBaseGen) {
3001                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
3002                                 g_assert (arm_is_imm12 (inst->inst_offset));
3003                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3004                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
3005                                 ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset);
3006                         } else if (ainfo->regtype == RegTypeBase) {
3007                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
3008                                 switch (ainfo->size) {
3009                                 case 1:
3010                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3011                                         g_assert (arm_is_imm12 (inst->inst_offset));
3012                                         ARM_STRB_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3013                                         break;
3014                                 case 2:
3015                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3016                                         if (arm_is_imm8 (inst->inst_offset)) {
3017                                                 ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3018                                         } else {
3019                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3020                                                 ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
3021                                                 ARM_STRH_IMM (code, ARMREG_LR, ARMREG_IP, 0);
3022                                         }
3023                                         break;
3024                                 case 8:
3025                                         g_assert (arm_is_imm12 (inst->inst_offset));
3026                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3027                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3028                                         g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset + 4));
3029                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
3030                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset + 4));
3031                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
3032                                         break;
3033                                 default:
3034                                         g_assert (arm_is_imm12 (inst->inst_offset));
3035                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3036                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3037                                         break;
3038                                 }
3039                         } else if (ainfo->regtype == RegTypeFP) {
3040                                 g_assert_not_reached ();
3041                         } else if (ainfo->regtype == RegTypeStructByVal) {
3042                                 int doffset = inst->inst_offset;
3043                                 int soffset = 0;
3044                                 int cur_reg;
3045                                 int size = 0;
3046                                 if (mono_class_from_mono_type (inst->inst_vtype))
3047                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3048                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3049                                         g_assert (arm_is_imm12 (doffset));
3050                                         ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
3051                                         soffset += sizeof (gpointer);
3052                                         doffset += sizeof (gpointer);
3053                                 }
3054                                 if (ainfo->vtsize) {
3055                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3056                                         //g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
3057                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
3058                                 }
3059                         } else if (ainfo->regtype == RegTypeStructByAddr) {
3060                                 g_assert_not_reached ();
3061                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3062                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3063                         } else
3064                                 g_assert_not_reached ();
3065                 }
3066                 pos++;
3067         }
3068
3069         if (method->save_lmf) {
3070
3071                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3072                              (gpointer)"mono_get_lmf_addr");
3073                 if (cfg->method->dynamic) {
3074                         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
3075                         ARM_B (code, 0);
3076                         *(gpointer*)code = NULL;
3077                         code += 4;
3078                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
3079                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
3080                 } else {
3081                         ARM_BL (code, 0);
3082                 }
3083                 /* we build the MonoLMF structure on the stack - see mini-arm.h */
3084                 /* lmf_offset is the offset from the previous stack pointer,
3085                  * alloc_size is the total stack space allocated, so the offset
3086                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3087                  * The pointer to the struct is put in r1 (new_lmf).
3088                  * r2 is used as scratch
3089                  * The callee-saved registers are already in the MonoLMF structure
3090                  */
3091                 code = emit_big_add (code, ARMREG_R1, ARMREG_SP, alloc_size - lmf_offset);
3092                 /* r0 is the result from mono_get_lmf_addr () */
3093                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
3094                 /* new_lmf->previous_lmf = *lmf_addr */
3095                 ARM_LDR_IMM (code, ARMREG_R2, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3096                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3097                 /* *(lmf_addr) = r1 */
3098                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3099                 /* save method info */
3100                 code = mono_arm_emit_load_imm (code, ARMREG_R2, GPOINTER_TO_INT (method));
3101                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, method));
3102                 ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
3103                 /* save the current IP */
3104                 ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
3105                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
3106         }
3107
3108         if (tracing)
3109                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3110
3111         cfg->code_len = code - cfg->native_code;
3112         g_assert (cfg->code_len < cfg->code_size);
3113         g_free (cinfo);
3114
3115         return code;
3116 }
3117
3118 void
3119 mono_arch_emit_epilog (MonoCompile *cfg)
3120 {
3121         MonoMethod *method = cfg->method;
3122         int pos, i, rot_amount;
3123         int max_epilog_size = 16 + 20*4;
3124         guint8 *code;
3125
3126         if (cfg->method->save_lmf)
3127                 max_epilog_size += 128;
3128         
3129         if (mono_jit_trace_calls != NULL)
3130                 max_epilog_size += 50;
3131
3132         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3133                 max_epilog_size += 50;
3134
3135         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3136                 cfg->code_size *= 2;
3137                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3138                 mono_jit_stats.code_reallocs++;
3139         }
3140
3141         /*
3142          * Keep in sync with CEE_JMP
3143          */
3144         code = cfg->native_code + cfg->code_len;
3145
3146         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3147                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3148         }
3149         pos = 0;
3150
3151         if (method->save_lmf) {
3152                 int lmf_offset;
3153                 /* all but r0-r3, sp and pc */
3154                 pos += sizeof (MonoLMF) - (4 * 10);
3155                 lmf_offset = pos;
3156                 /* r2 contains the pointer to the current LMF */
3157                 code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3158                 /* ip = previous_lmf */
3159                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3160                 /* lr = lmf_addr */
3161                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
3162                 /* *(lmf_addr) = previous_lmf */
3163                 ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3164                 /* FIXME: speedup: there is no actual need to restore the registers if
3165                  * we didn't actually change them (idea from Zoltan).
3166                  */
3167                 /* restore iregs */
3168                 /* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
3169                 ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_R2, (sizeof (MonoLMF) - 10 * sizeof (gulong)));
3170                 ARM_POP_NWB (code, 0xaff0); /* restore ip to sp and lr to pc */
3171         } else {
3172                 if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
3173                         ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
3174                 } else {
3175                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage);
3176                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
3177                 }
3178                 ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP) | (1 << ARMREG_PC)));
3179         }
3180
3181         cfg->code_len = code - cfg->native_code;
3182
3183         g_assert (cfg->code_len < cfg->code_size);
3184
3185 }
3186
3187 /* remove once throw_exception_by_name is eliminated */
3188 static int
3189 exception_id_by_name (const char *name)
3190 {
3191         if (strcmp (name, "IndexOutOfRangeException") == 0)
3192                 return MONO_EXC_INDEX_OUT_OF_RANGE;
3193         if (strcmp (name, "OverflowException") == 0)
3194                 return MONO_EXC_OVERFLOW;
3195         if (strcmp (name, "ArithmeticException") == 0)
3196                 return MONO_EXC_ARITHMETIC;
3197         if (strcmp (name, "DivideByZeroException") == 0)
3198                 return MONO_EXC_DIVIDE_BY_ZERO;
3199         if (strcmp (name, "InvalidCastException") == 0)
3200                 return MONO_EXC_INVALID_CAST;
3201         if (strcmp (name, "NullReferenceException") == 0)
3202                 return MONO_EXC_NULL_REF;
3203         if (strcmp (name, "ArrayTypeMismatchException") == 0)
3204                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3205         g_error ("Unknown intrinsic exception %s\n", name);
3206         return -1;
3207 }
3208
3209 void
3210 mono_arch_emit_exceptions (MonoCompile *cfg)
3211 {
3212         MonoJumpInfo *patch_info;
3213         int i;
3214         guint8 *code;
3215         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3216         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3217         int max_epilog_size = 50;
3218
3219         /* count the number of exception infos */
3220      
3221         /* 
3222          * make sure we have enough space for exceptions
3223          * 12 is the simulated call to throw_exception_by_name
3224          */
3225         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3226                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3227                         i = exception_id_by_name (patch_info->data.target);
3228                         if (!exc_throw_found [i]) {
3229                                 max_epilog_size += 12;
3230                                 exc_throw_found [i] = TRUE;
3231                         }
3232                 }
3233         }
3234
3235         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3236                 cfg->code_size *= 2;
3237                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3238                 mono_jit_stats.code_reallocs++;
3239         }
3240
3241         code = cfg->native_code + cfg->code_len;
3242
3243         /* add code to raise exceptions */
3244         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3245                 switch (patch_info->type) {
3246                 case MONO_PATCH_INFO_EXC: {
3247                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3248                         const char *ex_name = patch_info->data.target;
3249                         i = exception_id_by_name (patch_info->data.target);
3250                         if (exc_throw_pos [i]) {
3251                                 arm_patch (ip, exc_throw_pos [i]);
3252                                 patch_info->type = MONO_PATCH_INFO_NONE;
3253                                 break;
3254                         } else {
3255                                 exc_throw_pos [i] = code;
3256                         }
3257                         arm_patch (ip, code);
3258                         //*(int*)code = 0xef9f0001;
3259                         code += 4;
3260                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3261                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
3262                         /* we got here from a conditional call, so the calling ip is set in lr already */
3263                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3264                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3265                         patch_info->ip.i = code - cfg->native_code;
3266                         ARM_B (code, 0);
3267                         *(gconstpointer*)code = ex_name;
3268                         code += 4;
3269                         break;
3270                 }
3271                 default:
3272                         /* do nothing */
3273                         break;
3274                 }
3275         }
3276
3277         cfg->code_len = code - cfg->native_code;
3278
3279         g_assert (cfg->code_len < cfg->code_size);
3280
3281 }
3282
3283 void
3284 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3285 {
3286 }
3287
3288 void
3289 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3290 {
3291 }
3292
3293 void
3294 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3295 {
3296         
3297         int this_dreg = ARMREG_R0;
3298         
3299         if (vt_reg != -1)
3300                 this_dreg = ARMREG_R1;
3301
3302         /* add the this argument */
3303         if (this_reg != -1) {
3304                 MonoInst *this;
3305                 MONO_INST_NEW (cfg, this, OP_SETREG);
3306                 this->type = this_type;
3307                 this->sreg1 = this_reg;
3308                 this->dreg = mono_regstate_next_int (cfg->rs);
3309                 mono_bblock_add_inst (cfg->cbb, this);
3310                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3311         }
3312
3313         if (vt_reg != -1) {
3314                 MonoInst *vtarg;
3315                 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3316                 vtarg->type = STACK_MP;
3317                 vtarg->sreg1 = vt_reg;
3318                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3319                 mono_bblock_add_inst (cfg->cbb, vtarg);
3320                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ARMREG_R0, FALSE);
3321         }
3322 }
3323
3324 MonoInst*
3325 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3326 {
3327         MonoInst *ins = NULL;
3328         if (cmethod->klass == mono_defaults.thread_class &&
3329                         strcmp (cmethod->name, "MemoryBarrier") == 0) {
3330                 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3331         }
3332         return ins;
3333 }
3334
3335 gboolean
3336 mono_arch_print_tree (MonoInst *tree, int arity)
3337 {
3338         return 0;
3339 }
3340
3341 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3342 {
3343         return NULL;
3344 }
3345
3346 MonoInst* 
3347 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3348 {
3349         return NULL;
3350 }
3351
3352 void
3353 mono_arch_flush_register_windows (void)
3354 {
3355 }
3356
3357 void
3358 mono_arch_fixup_jinfo (MonoCompile *cfg)
3359 {
3360         /* max encoded stack usage is 64KB * 4 */
3361         g_assert ((cfg->stack_usage & ~(0xffff << 2)) == 0);
3362         cfg->jit_info->used_regs |= cfg->stack_usage << 14;
3363 }
3364