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