2008-07-12 Zoltan Varga <vargaz@gmail.com>
[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 /* This mutex protects architecture specific caches */
27 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
28 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
29 static CRITICAL_SECTION mini_arch_mutex;
30
31 static int v5_supported = 0;
32 static int thumb_supported = 0;
33
34 static int mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount);
35
36 /*
37  * TODO:
38  * floating point support: on ARM it is a mess, there are at least 3
39  * different setups, each of which binary incompat with the other.
40  * 1) FPA: old and ugly, but unfortunately what current distros use
41  *    the double binary format has the two words swapped. 8 double registers.
42  *    Implemented usually by kernel emulation.
43  * 2) softfloat: the compiler emulates all the fp ops. Usually uses the
44  *    ugly swapped double format (I guess a softfloat-vfp exists, too, though).
45  * 3) VFP: the new and actually sensible and useful FP support. Implemented
46  *    in HW or kernel-emulated, requires new tools. I think this is what symbian uses.
47  *
48  * The plan is to write the FPA support first. softfloat can be tested in a chroot.
49  */
50 int mono_exc_esp_offset = 0;
51
52 #define arm_is_imm12(v) ((v) > -4096 && (v) < 4096)
53 #define arm_is_imm8(v) ((v) > -256 && (v) < 256)
54 #define arm_is_fpimm8(v) ((v) >= -1020 && (v) <= 1020)
55
56 #define LDR_MASK ((0xf << ARMCOND_SHIFT) | (3 << 26) | (1 << 22) | (1 << 20) | (15 << 12))
57 #define LDR_PC_VAL ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 26) | (0 << 22) | (1 << 20) | (15 << 12))
58 #define IS_LDR_PC(val) (((val) & LDR_MASK) == LDR_PC_VAL)
59
60 #define ADD_LR_PC_4 ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 25) | (1 << 23) | (ARMREG_PC << 16) | (ARMREG_LR << 12) | 4)
61 #define MOV_LR_PC ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 24) | (0xa << 20) |  (ARMREG_LR << 12) | ARMREG_PC)
62 #define DEBUG_IMT 0
63
64 const char*
65 mono_arch_regname (int reg)
66 {
67         static const char * rnames[] = {
68                 "arm_r0", "arm_r1", "arm_r2", "arm_r3", "arm_v1",
69                 "arm_v2", "arm_v3", "arm_v4", "arm_v5", "arm_v6",
70                 "arm_v7", "arm_fp", "arm_ip", "arm_sp", "arm_lr",
71                 "arm_pc"
72         };
73         if (reg >= 0 && reg < 16)
74                 return rnames [reg];
75         return "unknown";
76 }
77
78 const char*
79 mono_arch_fregname (int reg)
80 {
81         static const char * rnames[] = {
82                 "arm_f0", "arm_f1", "arm_f2", "arm_f3", "arm_f4",
83                 "arm_f5", "arm_f6", "arm_f7", "arm_f8", "arm_f9",
84                 "arm_f10", "arm_f11", "arm_f12", "arm_f13", "arm_f14",
85                 "arm_f15", "arm_f16", "arm_f17", "arm_f18", "arm_f19",
86                 "arm_f20", "arm_f21", "arm_f22", "arm_f23", "arm_f24",
87                 "arm_f25", "arm_f26", "arm_f27", "arm_f28", "arm_f29",
88                 "arm_f30", "arm_f31"
89         };
90         if (reg >= 0 && reg < 32)
91                 return rnames [reg];
92         return "unknown";
93 }
94
95 static guint8*
96 emit_big_add (guint8 *code, int dreg, int sreg, int imm)
97 {
98         int imm8, rot_amount;
99         if ((imm8 = mono_arm_is_rotated_imm8 (imm, &rot_amount)) >= 0) {
100                 ARM_ADD_REG_IMM (code, dreg, sreg, imm8, rot_amount);
101                 return code;
102         }
103         g_assert (dreg != sreg);
104         code = mono_arm_emit_load_imm (code, dreg, imm);
105         ARM_ADD_REG_REG (code, dreg, dreg, sreg);
106         return code;
107 }
108
109 static guint8*
110 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
111 {
112         /* we can use r0-r3, since this is called only for incoming args on the stack */
113         if (size > sizeof (gpointer) * 4) {
114                 guint8 *start_loop;
115                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
116                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
117                 start_loop = code = mono_arm_emit_load_imm (code, ARMREG_R2, size);
118                 ARM_LDR_IMM (code, ARMREG_R3, ARMREG_R0, 0);
119                 ARM_STR_IMM (code, ARMREG_R3, ARMREG_R1, 0);
120                 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, 4);
121                 ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
122                 ARM_SUBS_REG_IMM8 (code, ARMREG_R2, ARMREG_R2, 4);
123                 ARM_B_COND (code, ARMCOND_NE, 0);
124                 arm_patch (code - 4, start_loop);
125                 return code;
126         }
127         if (arm_is_imm12 (doffset) && arm_is_imm12 (doffset + size) &&
128                         arm_is_imm12 (soffset) && arm_is_imm12 (soffset + size)) {
129                 while (size >= 4) {
130                         ARM_LDR_IMM (code, ARMREG_LR, sreg, soffset);
131                         ARM_STR_IMM (code, ARMREG_LR, dreg, doffset);
132                         doffset += 4;
133                         soffset += 4;
134                         size -= 4;
135                 }
136         } else if (size) {
137                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
138                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
139                 doffset = soffset = 0;
140                 while (size >= 4) {
141                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R0, soffset);
142                         ARM_STR_IMM (code, ARMREG_LR, ARMREG_R1, doffset);
143                         doffset += 4;
144                         soffset += 4;
145                         size -= 4;
146                 }
147         }
148         g_assert (size == 0);
149         return code;
150 }
151
152 static guint8*
153 emit_call_reg (guint8 *code, int reg)
154 {
155         if (v5_supported) {
156                 ARM_BLX_REG (code, reg);
157         } else {
158                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
159                 if (thumb_supported)
160                         ARM_BX (code, reg);
161                 else
162                         ARM_MOV_REG_REG (code, ARMREG_PC, reg);
163         }
164         return code;
165 }
166
167 static guint8*
168 emit_call_seq (MonoCompile *cfg, guint8 *code)
169 {
170         if (cfg->method->dynamic) {
171                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
172                 ARM_B (code, 0);
173                 *(gpointer*)code = NULL;
174                 code += 4;
175                 code = emit_call_reg (code, ARMREG_IP);
176         } else {
177                 ARM_BL (code, 0);
178         }
179         return code;
180 }
181
182 static guint8*
183 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
184 {
185         switch (ins->opcode) {
186         case OP_FCALL:
187         case OP_FCALL_REG:
188         case OP_FCALL_MEMBASE:
189 #ifdef ARM_FPU_FPA
190                 if (ins->dreg != ARM_FPA_F0)
191                         ARM_MVFD (code, ins->dreg, ARM_FPA_F0);
192 #endif
193                 break;
194         }
195
196         return code;
197 }
198
199 /*
200  * mono_arch_get_argument_info:
201  * @csig:  a method signature
202  * @param_count: the number of parameters to consider
203  * @arg_info: an array to store the result infos
204  *
205  * Gathers information on parameters such as size, alignment and
206  * padding. arg_info should be large enought to hold param_count + 1 entries. 
207  *
208  * Returns the size of the activation frame.
209  */
210 int
211 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
212 {
213         int k, frame_size = 0;
214         int size, align, pad;
215         int offset = 8;
216
217         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
218                 frame_size += sizeof (gpointer);
219                 offset += 4;
220         }
221
222         arg_info [0].offset = offset;
223
224         if (csig->hasthis) {
225                 frame_size += sizeof (gpointer);
226                 offset += 4;
227         }
228
229         arg_info [0].size = frame_size;
230
231         for (k = 0; k < param_count; k++) {
232                 
233                 if (csig->pinvoke)
234                         size = mono_type_native_stack_size (csig->params [k], &align);
235                 else
236                         size = mini_type_stack_size (NULL, csig->params [k], &align);
237
238                 /* ignore alignment for now */
239                 align = 1;
240
241                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
242                 arg_info [k].pad = pad;
243                 frame_size += size;
244                 arg_info [k + 1].pad = 0;
245                 arg_info [k + 1].size = size;
246                 offset += pad;
247                 arg_info [k + 1].offset = offset;
248                 offset += size;
249         }
250
251         align = MONO_ARCH_FRAME_ALIGNMENT;
252         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
253         arg_info [k].pad = pad;
254
255         return frame_size;
256 }
257
258 static gpointer
259 decode_vcall_slot_from_ldr (guint32 ldr, gpointer *regs, int *displacement)
260 {
261         char *o = NULL;
262         int reg, offset = 0;
263         reg = (ldr >> 16 ) & 0xf;
264         offset = ldr & 0xfff;
265         if (((ldr >> 23) & 1) == 0) /*U bit, 0 means negative and 1 positive*/
266                 offset = -offset;
267         /*g_print ("found vcall at r%d + %d for code at %p 0x%x\n", reg, offset, code, *code);*/
268         o = regs [reg];
269
270         *displacement = offset;
271         return o;
272 }
273
274 gpointer
275 mono_arch_get_vcall_slot (guint8 *code_ptr, gpointer *regs, int *displacement)
276 {
277         guint32* code = (guint32*)code_ptr;
278
279         /* Locate the address of the method-specific trampoline. The call using
280         the vtable slot that took the processing flow to 'arch_create_jit_trampoline' 
281         looks something like this:
282
283                 ldr rA, rX, #offset
284                 mov lr, pc
285                 mov pc, rA
286         or better:
287                 mov lr, pc
288                 ldr pc, rX, #offset
289
290         The call sequence could be also:
291                 ldr ip, pc, 0
292                 b skip
293                 function pointer literal
294                 skip:
295                 mov lr, pc
296                 mov pc, ip
297         Note that on ARM5+ we can use one instruction instead of the last two.
298         Therefore, we need to locate the 'ldr rA' instruction to know which
299         register was used to hold the method addrs.
300         */
301
302         /* This is the instruction after "ldc pc, xxx", "mov pc, xxx" or "bl xxx" could be either the IMT value or some other instruction*/
303         --code;
304
305         /* Three possible code sequences can happen here:
306          * interface call:
307          * 
308          * add lr, [pc + #4]
309          * ldr pc, [rX - #offset]
310          * .word IMT value
311          * 
312          * virtual call:
313          * 
314          * mov lr, pc
315          * ldr pc, [rX - #offset] 
316          * 
317          * direct branch with bl:
318          * 
319          * bl #offset
320          * 
321          * direct branch with mov: 
322          * 
323          * mv pc, rX
324          * 
325          * We only need to identify interface and virtual calls, the others can be ignored.
326          * 
327          */
328         if (IS_LDR_PC (code [-1]) && code [-2] == ADD_LR_PC_4)
329                 return decode_vcall_slot_from_ldr (code [-1], regs, displacement);
330
331         if (IS_LDR_PC (code [0]) && code [-1] == MOV_LR_PC)
332                 return decode_vcall_slot_from_ldr (code [0], regs, displacement);
333
334         return NULL;
335 }
336
337 gpointer*
338 mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
339 {
340         gpointer vt;
341         int displacement;
342         vt = mono_arch_get_vcall_slot (code, regs, &displacement);
343         if (!vt)
344                 return NULL;
345         return (gpointer*)((char*)vt + displacement);
346 }
347
348 #define MAX_ARCH_DELEGATE_PARAMS 3
349
350 gpointer
351 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
352 {
353         guint8 *code, *start;
354
355         /* FIXME: Support more cases */
356         if (MONO_TYPE_ISSTRUCT (sig->ret))
357                 return NULL;
358
359         if (has_target) {
360                 static guint8* cached = NULL;
361                 mono_mini_arch_lock ();
362                 if (cached) {
363                         mono_mini_arch_unlock ();
364                         return cached;
365                 }
366                 
367                 start = code = mono_global_codeman_reserve (12);
368
369                 /* Replace the this argument with the target */
370                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
371                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, target));
372                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
373
374                 g_assert ((code - start) <= 12);
375
376                 mono_arch_flush_icache (code, 12);
377                 cached = start;
378                 mono_mini_arch_unlock ();
379                 return cached;
380         } else {
381                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
382                 int size, i;
383
384                 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
385                         return NULL;
386                 for (i = 0; i < sig->param_count; ++i)
387                         if (!mono_is_regsize_var (sig->params [i]))
388                                 return NULL;
389
390                 mono_mini_arch_lock ();
391                 code = cache [sig->param_count];
392                 if (code) {
393                         mono_mini_arch_unlock ();
394                         return code;
395                 }
396
397                 size = 8 + sig->param_count * 4;
398                 start = code = mono_global_codeman_reserve (size);
399
400                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
401                 /* slide down the arguments */
402                 for (i = 0; i < sig->param_count; ++i) {
403                         ARM_MOV_REG_REG (code, (ARMREG_R0 + i), (ARMREG_R0 + i + 1));
404                 }
405                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
406
407                 g_assert ((code - start) <= size);
408
409                 mono_arch_flush_icache (code, size);
410                 cache [sig->param_count] = start;
411                 mono_mini_arch_unlock ();
412                 return start;
413         }
414
415         return NULL;
416 }
417
418 gpointer
419 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, gssize *regs, guint8 *code)
420 {
421         /* FIXME: handle returning a struct */
422         if (MONO_TYPE_ISSTRUCT (sig->ret))
423                 return (gpointer)regs [ARMREG_R1];
424         return (gpointer)regs [ARMREG_R0];
425 }
426
427 /*
428  * Initialize the cpu to execute managed code.
429  */
430 void
431 mono_arch_cpu_init (void)
432 {
433 }
434
435 /*
436  * Initialize architecture specific code.
437  */
438 void
439 mono_arch_init (void)
440 {
441         InitializeCriticalSection (&mini_arch_mutex);   
442 }
443
444 /*
445  * Cleanup architecture specific code.
446  */
447 void
448 mono_arch_cleanup (void)
449 {
450 }
451
452 /*
453  * This function returns the optimizations supported on this cpu.
454  */
455 guint32
456 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
457 {
458         guint32 opts = 0;
459 #if __APPLE__
460         thumb_supported = TRUE;
461         v5_supported = TRUE;
462 #else
463         char buf [512];
464         char *line;
465         FILE *file = fopen ("/proc/cpuinfo", "r");
466         if (file) {
467                 while ((line = fgets (buf, 512, file))) {
468                         if (strncmp (line, "Processor", 9) == 0) {
469                                 char *ver = strstr (line, "(v");
470                                 if (ver && (ver [2] == '5' || ver [2] == '6' || ver [2] == '7')) {
471                                         v5_supported = TRUE;
472                                 }
473                                 continue;
474                         }
475                         if (strncmp (line, "Features", 8) == 0) {
476                                 char *th = strstr (line, "thumb");
477                                 if (th) {
478                                         thumb_supported = TRUE;
479                                         if (v5_supported)
480                                                 break;
481                                 }
482                                 continue;
483                         }
484                 }
485                 fclose (file);
486                 /*printf ("features: v5: %d, thumb: %d\n", v5_supported, thumb_supported);*/
487         }
488 #endif
489
490         /* no arm-specific optimizations yet */
491         *exclude_mask = 0;
492         return opts;
493 }
494
495 static gboolean
496 is_regsize_var (MonoType *t) {
497         if (t->byref)
498                 return TRUE;
499         t = mono_type_get_underlying_type (t);
500         switch (t->type) {
501         case MONO_TYPE_I4:
502         case MONO_TYPE_U4:
503         case MONO_TYPE_I:
504         case MONO_TYPE_U:
505         case MONO_TYPE_PTR:
506         case MONO_TYPE_FNPTR:
507                 return TRUE;
508         case MONO_TYPE_OBJECT:
509         case MONO_TYPE_STRING:
510         case MONO_TYPE_CLASS:
511         case MONO_TYPE_SZARRAY:
512         case MONO_TYPE_ARRAY:
513                 return TRUE;
514         case MONO_TYPE_GENERICINST:
515                 if (!mono_type_generic_inst_is_valuetype (t))
516                         return TRUE;
517                 return FALSE;
518         case MONO_TYPE_VALUETYPE:
519                 return FALSE;
520         }
521         return FALSE;
522 }
523
524 GList *
525 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
526 {
527         GList *vars = NULL;
528         int i;
529
530         for (i = 0; i < cfg->num_varinfo; i++) {
531                 MonoInst *ins = cfg->varinfo [i];
532                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
533
534                 /* unused vars */
535                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
536                         continue;
537
538                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
539                         continue;
540
541                 /* we can only allocate 32 bit values */
542                 if (is_regsize_var (ins->inst_vtype)) {
543                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
544                         g_assert (i == vmv->idx);
545                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
546                 }
547         }
548
549         return vars;
550 }
551
552 #define USE_EXTRA_TEMPS 0
553
554 GList *
555 mono_arch_get_global_int_regs (MonoCompile *cfg)
556 {
557         GList *regs = NULL;
558         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V1));
559         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V2));
560         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V3));
561         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V4));
562         if (cfg->compile_aot)
563                 /* V5 is reserved for holding the IMT method */
564                 cfg->used_int_regs |= (1 << ARMREG_V5);
565         else
566                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
567         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V6));*/
568         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));*/
569
570         return regs;
571 }
572
573 /*
574  * mono_arch_regalloc_cost:
575  *
576  *  Return the cost, in number of memory references, of the action of 
577  * allocating the variable VMV into a register during global register
578  * allocation.
579  */
580 guint32
581 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
582 {
583         /* FIXME: */
584         return 2;
585 }
586
587 void
588 mono_arch_flush_icache (guint8 *code, gint size)
589 {
590 #if __APPLE__
591         sys_icache_invalidate (code, size);
592 #else
593         __asm __volatile ("mov r0, %0\n"
594                         "mov r1, %1\n"
595                         "mov r2, %2\n"
596                         "swi 0x9f0002       @ sys_cacheflush"
597                         : /* no outputs */
598                         : "r" (code), "r" (code + size), "r" (0)
599                         : "r0", "r1", "r3" );
600 #endif
601 }
602
603 enum {
604         RegTypeGeneral,
605         RegTypeBase,
606         RegTypeBaseGen,
607         RegTypeFP,
608         RegTypeStructByVal,
609         RegTypeStructByAddr
610 };
611
612 typedef struct {
613         gint32  offset;
614         guint16 vtsize; /* in param area */
615         guint8  reg;
616         guint8  regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
617         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
618 } ArgInfo;
619
620 typedef struct {
621         int nargs;
622         guint32 stack_usage;
623         guint32 struct_ret;
624         ArgInfo ret;
625         ArgInfo sig_cookie;
626         ArgInfo args [1];
627 } CallInfo;
628
629 #define DEBUG(a)
630
631 static void inline
632 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
633 {
634         if (simple) {
635                 if (*gr > ARMREG_R3) {
636                         ainfo->offset = *stack_size;
637                         ainfo->reg = ARMREG_SP; /* in the caller */
638                         ainfo->regtype = RegTypeBase;
639                         *stack_size += 4;
640                 } else {
641                         ainfo->reg = *gr;
642                 }
643         } else {
644                 if (*gr == ARMREG_R3
645 #ifdef __ARM_EABI__
646                                 && 0
647 #endif
648                                         ) {
649                         /* first word in r3 and the second on the stack */
650                         ainfo->offset = *stack_size;
651                         ainfo->reg = ARMREG_SP; /* in the caller */
652                         ainfo->regtype = RegTypeBaseGen;
653                         *stack_size += 4;
654                 } else if (*gr >= ARMREG_R3) {
655 #ifdef __ARM_EABI__
656                         *stack_size += 7;
657                         *stack_size &= ~7;
658 #endif
659                         ainfo->offset = *stack_size;
660                         ainfo->reg = ARMREG_SP; /* in the caller */
661                         ainfo->regtype = RegTypeBase;
662                         *stack_size += 8;
663                 } else {
664 #ifdef __ARM_EABI__
665                         if ((*gr) & 1)
666                                 (*gr) ++;
667 #endif
668                         ainfo->reg = *gr;
669                 }
670                 (*gr) ++;
671         }
672         (*gr) ++;
673 }
674
675 static CallInfo*
676 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
677 {
678         guint i, gr;
679         int n = sig->hasthis + sig->param_count;
680         guint32 simpletype;
681         guint32 stack_size = 0;
682         CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
683
684         gr = ARMREG_R0;
685
686         /* FIXME: handle returning a struct */
687         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
688                 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
689                 cinfo->struct_ret = ARMREG_R0;
690         }
691
692         n = 0;
693         if (sig->hasthis) {
694                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
695                 n++;
696         }
697         DEBUG(printf("params: %d\n", sig->param_count));
698         for (i = 0; i < sig->param_count; ++i) {
699                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
700                         /* Prevent implicit arguments and sig_cookie from
701                            being passed in registers */
702                         gr = ARMREG_R3 + 1;
703                         /* Emit the signature cookie just before the implicit arguments */
704                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
705                 }
706                 DEBUG(printf("param %d: ", i));
707                 if (sig->params [i]->byref) {
708                         DEBUG(printf("byref\n"));
709                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
710                         n++;
711                         continue;
712                 }
713                 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
714                 switch (simpletype) {
715                 case MONO_TYPE_BOOLEAN:
716                 case MONO_TYPE_I1:
717                 case MONO_TYPE_U1:
718                         cinfo->args [n].size = 1;
719                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
720                         n++;
721                         break;
722                 case MONO_TYPE_CHAR:
723                 case MONO_TYPE_I2:
724                 case MONO_TYPE_U2:
725                         cinfo->args [n].size = 2;
726                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
727                         n++;
728                         break;
729                 case MONO_TYPE_I4:
730                 case MONO_TYPE_U4:
731                         cinfo->args [n].size = 4;
732                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
733                         n++;
734                         break;
735                 case MONO_TYPE_I:
736                 case MONO_TYPE_U:
737                 case MONO_TYPE_PTR:
738                 case MONO_TYPE_FNPTR:
739                 case MONO_TYPE_CLASS:
740                 case MONO_TYPE_OBJECT:
741                 case MONO_TYPE_STRING:
742                 case MONO_TYPE_SZARRAY:
743                 case MONO_TYPE_ARRAY:
744                 case MONO_TYPE_R4:
745                         cinfo->args [n].size = sizeof (gpointer);
746                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
747                         n++;
748                         break;
749                 case MONO_TYPE_GENERICINST:
750                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
751                                 cinfo->args [n].size = sizeof (gpointer);
752                                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
753                                 n++;
754                                 break;
755                         }
756                         /* Fall through */
757                 case MONO_TYPE_TYPEDBYREF:
758                 case MONO_TYPE_VALUETYPE: {
759                         gint size;
760                         int align_size;
761                         int nwords;
762
763                         if (simpletype == MONO_TYPE_TYPEDBYREF) {
764                                 size = sizeof (MonoTypedRef);
765                         } else {
766                                 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
767                                 if (is_pinvoke)
768                                         size = mono_class_native_size (klass, NULL);
769                                 else
770                                         size = mono_class_value_size (klass, NULL);
771                         }
772                         DEBUG(printf ("load %d bytes struct\n",
773                                       mono_class_native_size (sig->params [i]->data.klass, NULL)));
774                         align_size = size;
775                         nwords = 0;
776                         align_size += (sizeof (gpointer) - 1);
777                         align_size &= ~(sizeof (gpointer) - 1);
778                         nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
779                         cinfo->args [n].regtype = RegTypeStructByVal;
780                         /* FIXME: align gr and stack_size if needed */
781                         if (gr > ARMREG_R3) {
782                                 cinfo->args [n].size = 0;
783                                 cinfo->args [n].vtsize = nwords;
784                         } else {
785                                 int rest = ARMREG_R3 - gr + 1;
786                                 int n_in_regs = rest >= nwords? nwords: rest;
787                                 cinfo->args [n].size = n_in_regs;
788                                 cinfo->args [n].vtsize = nwords - n_in_regs;
789                                 cinfo->args [n].reg = gr;
790                                 gr += n_in_regs;
791                         }
792                         cinfo->args [n].offset = stack_size;
793                         /*g_print ("offset for arg %d at %d\n", n, stack_size);*/
794                         stack_size += nwords * sizeof (gpointer);
795                         n++;
796                         break;
797                 }
798                 case MONO_TYPE_U8:
799                 case MONO_TYPE_I8:
800                 case MONO_TYPE_R8:
801                         cinfo->args [n].size = 8;
802                         add_general (&gr, &stack_size, cinfo->args + n, FALSE);
803                         n++;
804                         break;
805                 default:
806                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
807                 }
808         }
809
810         {
811                 simpletype = mono_type_get_underlying_type (sig->ret)->type;
812                 switch (simpletype) {
813                 case MONO_TYPE_BOOLEAN:
814                 case MONO_TYPE_I1:
815                 case MONO_TYPE_U1:
816                 case MONO_TYPE_I2:
817                 case MONO_TYPE_U2:
818                 case MONO_TYPE_CHAR:
819                 case MONO_TYPE_I4:
820                 case MONO_TYPE_U4:
821                 case MONO_TYPE_I:
822                 case MONO_TYPE_U:
823                 case MONO_TYPE_PTR:
824                 case MONO_TYPE_FNPTR:
825                 case MONO_TYPE_CLASS:
826                 case MONO_TYPE_OBJECT:
827                 case MONO_TYPE_SZARRAY:
828                 case MONO_TYPE_ARRAY:
829                 case MONO_TYPE_STRING:
830                         cinfo->ret.reg = ARMREG_R0;
831                         break;
832                 case MONO_TYPE_U8:
833                 case MONO_TYPE_I8:
834                         cinfo->ret.reg = ARMREG_R0;
835                         break;
836                 case MONO_TYPE_R4:
837                 case MONO_TYPE_R8:
838                         cinfo->ret.reg = ARMREG_R0;
839                         /* FIXME: cinfo->ret.reg = ???;
840                         cinfo->ret.regtype = RegTypeFP;*/
841                         break;
842                 case MONO_TYPE_GENERICINST:
843                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
844                                 cinfo->ret.reg = ARMREG_R0;
845                                 break;
846                         }
847                         break;
848                 case MONO_TYPE_VALUETYPE:
849                         break;
850                 case MONO_TYPE_TYPEDBYREF:
851                 case MONO_TYPE_VOID:
852                         break;
853                 default:
854                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
855                 }
856         }
857
858         /* align stack size to 8 */
859         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
860         stack_size = (stack_size + 7) & ~7;
861
862         cinfo->stack_usage = stack_size;
863         return cinfo;
864 }
865
866
867 /*
868  * Set var information according to the calling convention. arm version.
869  * The locals var stuff should most likely be split in another method.
870  */
871 void
872 mono_arch_allocate_vars (MonoCompile *m)
873 {
874         MonoMethodSignature *sig;
875         MonoMethodHeader *header;
876         MonoInst *inst;
877         int i, offset, size, align, curinst;
878         int frame_reg = ARMREG_FP;
879
880         /* FIXME: this will change when we use FP as gcc does */
881         m->flags |= MONO_CFG_HAS_SPILLUP;
882
883         /* allow room for the vararg method args: void* and long/double */
884         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
885                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
886
887         header = mono_method_get_header (m->method);
888
889         /* 
890          * We use the frame register also for any method that has
891          * exception clauses. This way, when the handlers are called,
892          * the code will reference local variables using the frame reg instead of
893          * the stack pointer: if we had to restore the stack pointer, we'd
894          * corrupt the method frames that are already on the stack (since
895          * filters get called before stack unwinding happens) when the filter
896          * code would call any method (this also applies to finally etc.).
897          */ 
898         if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
899                 frame_reg = ARMREG_FP;
900         m->frame_reg = frame_reg;
901         if (frame_reg != ARMREG_SP) {
902                 m->used_int_regs |= 1 << frame_reg;
903         }
904
905         sig = mono_method_signature (m->method);
906         
907         offset = 0;
908         curinst = 0;
909         if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
910                 /* FIXME: handle long and FP values */
911                 switch (mono_type_get_underlying_type (sig->ret)->type) {
912                 case MONO_TYPE_VOID:
913                         break;
914                 default:
915                         m->ret->opcode = OP_REGVAR;
916                         m->ret->inst_c0 = ARMREG_R0;
917                         break;
918                 }
919         }
920         /* local vars are at a positive offset from the stack pointer */
921         /* 
922          * also note that if the function uses alloca, we use FP
923          * to point at the local variables.
924          */
925         offset = 0; /* linkage area */
926         /* align the offset to 16 bytes: not sure this is needed here  */
927         //offset += 8 - 1;
928         //offset &= ~(8 - 1);
929
930         /* add parameter area size for called functions */
931         offset += m->param_area;
932         offset += 8 - 1;
933         offset &= ~(8 - 1);
934         if (m->flags & MONO_CFG_HAS_FPOUT)
935                 offset += 8;
936
937         /* allow room to save the return value */
938         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
939                 offset += 8;
940
941         /* the MonoLMF structure is stored just below the stack pointer */
942
943         if (sig->call_convention == MONO_CALL_VARARG) {
944                 m->sig_cookie = 0;
945         }
946
947         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
948                 inst = m->vret_addr;
949                 offset += sizeof(gpointer) - 1;
950                 offset &= ~(sizeof(gpointer) - 1);
951                 inst->inst_offset = offset;
952                 inst->opcode = OP_REGOFFSET;
953                 inst->inst_basereg = frame_reg;
954                 if (G_UNLIKELY (m->verbose_level > 1)) {
955                         printf ("vret_addr =");
956                         mono_print_ins (m->vret_addr);
957                 }
958                 offset += sizeof(gpointer);
959                 if (sig->call_convention == MONO_CALL_VARARG)
960                         m->sig_cookie += sizeof (gpointer);
961         }
962
963         curinst = m->locals_start;
964         for (i = curinst; i < m->num_varinfo; ++i) {
965                 inst = m->varinfo [i];
966                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
967                         continue;
968
969                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
970                 * pinvoke wrappers when they call functions returning structure */
971                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
972                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
973                 else
974                         size = mono_type_size (inst->inst_vtype, &align);
975
976                 /* FIXME: if a structure is misaligned, our memcpy doesn't work,
977                  * since it loads/stores misaligned words, which don't do the right thing.
978                  */
979                 if (align < 4 && size >= 4)
980                         align = 4;
981                 offset += align - 1;
982                 offset &= ~(align - 1);
983                 inst->inst_offset = offset;
984                 inst->opcode = OP_REGOFFSET;
985                 inst->inst_basereg = frame_reg;
986                 offset += size;
987                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
988         }
989
990         curinst = 0;
991         if (sig->hasthis) {
992                 inst = m->args [curinst];
993                 if (inst->opcode != OP_REGVAR) {
994                         inst->opcode = OP_REGOFFSET;
995                         inst->inst_basereg = frame_reg;
996                         offset += sizeof (gpointer) - 1;
997                         offset &= ~(sizeof (gpointer) - 1);
998                         inst->inst_offset = offset;
999                         offset += sizeof (gpointer);
1000                         if (sig->call_convention == MONO_CALL_VARARG)
1001                                 m->sig_cookie += sizeof (gpointer);
1002                 }
1003                 curinst++;
1004         }
1005
1006         for (i = 0; i < sig->param_count; ++i) {
1007                 inst = m->args [curinst];
1008                 if (inst->opcode != OP_REGVAR) {
1009                         inst->opcode = OP_REGOFFSET;
1010                         inst->inst_basereg = frame_reg;
1011                         size = mono_type_size (sig->params [i], &align);
1012                         /* FIXME: if a structure is misaligned, our memcpy doesn't work,
1013                          * since it loads/stores misaligned words, which don't do the right thing.
1014                          */
1015                         if (align < 4 && size >= 4)
1016                                 align = 4;
1017                         offset += align - 1;
1018                         offset &= ~(align - 1);
1019                         inst->inst_offset = offset;
1020                         offset += size;
1021                         if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
1022                                 m->sig_cookie += size;
1023                 }
1024                 curinst++;
1025         }
1026
1027         /* align the offset to 8 bytes */
1028         offset += 8 - 1;
1029         offset &= ~(8 - 1);
1030
1031         /* change sign? */
1032         m->stack_offset = offset;
1033
1034 }
1035
1036 void
1037 mono_arch_create_vars (MonoCompile *cfg)
1038 {
1039         MonoMethodSignature *sig;
1040
1041         sig = mono_method_signature (cfg->method);
1042
1043         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1044                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1045                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1046                         printf ("vret_addr = ");
1047                         mono_print_ins (cfg->vret_addr);
1048                 }
1049         }
1050 }
1051
1052 /* 
1053  * take the arguments and generate the arch-specific
1054  * instructions to properly call the function in call.
1055  * This includes pushing, moving arguments to the right register
1056  * etc.
1057  * Issue: who does the spilling if needed, and when?
1058  */
1059 MonoCallInst*
1060 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1061         MonoInst *arg, *in;
1062         MonoMethodSignature *sig;
1063         int i, n;
1064         CallInfo *cinfo;
1065         ArgInfo *ainfo;
1066
1067         sig = call->signature;
1068         n = sig->param_count + sig->hasthis;
1069         
1070         cinfo = calculate_sizes (sig, sig->pinvoke);
1071         if (cinfo->struct_ret)
1072                 call->used_iregs |= 1 << cinfo->struct_ret;
1073
1074         for (i = 0; i < n; ++i) {
1075                 ainfo = cinfo->args + i;
1076                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1077                         MonoInst *sig_arg;
1078                         cfg->disable_aot = TRUE;
1079                                 
1080                         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1081                         sig_arg->inst_p0 = call->signature;
1082                         
1083                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1084                         arg->inst_imm = cinfo->sig_cookie.offset;
1085                         arg->inst_left = sig_arg;
1086                         MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1087                 }
1088                 if (is_virtual && i == 0) {
1089                         /* the argument will be attached to the call instrucion */
1090                         in = call->args [i];
1091                         call->used_iregs |= 1 << ainfo->reg;
1092                 } else {
1093                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1094                         in = call->args [i];
1095                         arg->cil_code = in->cil_code;
1096                         arg->inst_left = in;
1097                         arg->inst_right = (MonoInst*)call;
1098                         arg->type = in->type;
1099                         MONO_INST_LIST_ADD_TAIL (&arg->node, &call->out_args);
1100                         if (ainfo->regtype == RegTypeGeneral) {
1101                                 arg->backend.reg3 = ainfo->reg;
1102                                 call->used_iregs |= 1 << ainfo->reg;
1103                                 if (arg->type == STACK_I8)
1104                                         call->used_iregs |= 1 << (ainfo->reg + 1);
1105                                 if (arg->type == STACK_R8) {
1106                                         if (ainfo->size == 4) {
1107 #ifndef MONO_ARCH_SOFT_FLOAT
1108                                                 arg->opcode = OP_OUTARG_R4;
1109 #endif
1110                                         } else {
1111                                                 call->used_iregs |= 1 << (ainfo->reg + 1);
1112                                         }
1113                                         cfg->flags |= MONO_CFG_HAS_FPOUT;
1114                                 }
1115                         } else if (ainfo->regtype == RegTypeStructByAddr) {
1116                                 /* FIXME: where si the data allocated? */
1117                                 arg->backend.reg3 = ainfo->reg;
1118                                 call->used_iregs |= 1 << ainfo->reg;
1119                                 g_assert_not_reached ();
1120                         } else if (ainfo->regtype == RegTypeStructByVal) {
1121                                 int cur_reg;
1122                                 /* mark the used regs */
1123                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
1124                                         call->used_iregs |= 1 << (ainfo->reg + cur_reg);
1125                                 }
1126                                 arg->opcode = OP_OUTARG_VT;
1127                                 /* vtsize and offset have just 12 bits of encoding in number of words */
1128                                 g_assert (((ainfo->vtsize | (ainfo->offset / 4)) & 0xfffff000) == 0);
1129                                 arg->backend.arg_info = ainfo->reg | (ainfo->size << 4) | (ainfo->vtsize << 8) | ((ainfo->offset / 4) << 20);
1130                         } else if (ainfo->regtype == RegTypeBase) {
1131                                 arg->opcode = OP_OUTARG_MEMBASE;
1132                                 arg->backend.arg_info = (ainfo->offset << 8) | ainfo->size;
1133                         } else if (ainfo->regtype == RegTypeBaseGen) {
1134                                 call->used_iregs |= 1 << ARMREG_R3;
1135                                 arg->opcode = OP_OUTARG_MEMBASE;
1136                                 arg->backend.arg_info = (ainfo->offset << 8) | 0xff;
1137                                 if (arg->type == STACK_R8)
1138                                         cfg->flags |= MONO_CFG_HAS_FPOUT;
1139                         } else if (ainfo->regtype == RegTypeFP) {
1140                                 arg->backend.reg3 = ainfo->reg;
1141                                 /* FP args are passed in int regs */
1142                                 call->used_iregs |= 1 << ainfo->reg;
1143                                 if (ainfo->size == 8) {
1144                                         arg->opcode = OP_OUTARG_R8;
1145                                         call->used_iregs |= 1 << (ainfo->reg + 1);
1146                                 } else {
1147                                         arg->opcode = OP_OUTARG_R4;
1148                                 }
1149                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1150                         } else {
1151                                 g_assert_not_reached ();
1152                         }
1153                 }
1154         }
1155         call->stack_usage = cinfo->stack_usage;
1156         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
1157         cfg->flags |= MONO_CFG_HAS_CALLS;
1158         /* 
1159          * should set more info in call, such as the stack space
1160          * used by the args that needs to be added back to esp
1161          */
1162
1163         g_free (cinfo);
1164         return call;
1165 }
1166
1167 /*
1168  * Allow tracing to work with this interface (with an optional argument)
1169  */
1170
1171 void*
1172 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1173 {
1174         guchar *code = p;
1175
1176         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
1177         ARM_MOV_REG_IMM8 (code, ARMREG_R1, 0); /* NULL ebp for now */
1178         code = mono_arm_emit_load_imm (code, ARMREG_R2, (guint32)func);
1179         code = emit_call_reg (code, ARMREG_R2);
1180         return code;
1181 }
1182
1183 enum {
1184         SAVE_NONE,
1185         SAVE_STRUCT,
1186         SAVE_ONE,
1187         SAVE_TWO,
1188         SAVE_FP
1189 };
1190
1191 void*
1192 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1193 {
1194         guchar *code = p;
1195         int save_mode = SAVE_NONE;
1196         int offset;
1197         MonoMethod *method = cfg->method;
1198         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
1199         int save_offset = cfg->param_area;
1200         save_offset += 7;
1201         save_offset &= ~7;
1202         
1203         offset = code - cfg->native_code;
1204         /* we need about 16 instructions */
1205         if (offset > (cfg->code_size - 16 * 4)) {
1206                 cfg->code_size *= 2;
1207                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1208                 code = cfg->native_code + offset;
1209         }
1210         switch (rtype) {
1211         case MONO_TYPE_VOID:
1212                 /* special case string .ctor icall */
1213                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1214                         save_mode = SAVE_ONE;
1215                 else
1216                         save_mode = SAVE_NONE;
1217                 break;
1218         case MONO_TYPE_I8:
1219         case MONO_TYPE_U8:
1220                 save_mode = SAVE_TWO;
1221                 break;
1222         case MONO_TYPE_R4:
1223         case MONO_TYPE_R8:
1224                 save_mode = SAVE_FP;
1225                 break;
1226         case MONO_TYPE_VALUETYPE:
1227                 save_mode = SAVE_STRUCT;
1228                 break;
1229         default:
1230                 save_mode = SAVE_ONE;
1231                 break;
1232         }
1233
1234         switch (save_mode) {
1235         case SAVE_TWO:
1236                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
1237                 ARM_STR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
1238                 if (enable_arguments) {
1239                         ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_R1);
1240                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
1241                 }
1242                 break;
1243         case SAVE_ONE:
1244                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
1245                 if (enable_arguments) {
1246                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
1247                 }
1248                 break;
1249         case SAVE_FP:
1250                 /* FIXME: what reg?  */
1251                 if (enable_arguments) {
1252                         /* FIXME: what reg?  */
1253                 }
1254                 break;
1255         case SAVE_STRUCT:
1256                 if (enable_arguments) {
1257                         /* FIXME: get the actual address  */
1258                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
1259                 }
1260                 break;
1261         case SAVE_NONE:
1262         default:
1263                 break;
1264         }
1265
1266         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
1267         code = mono_arm_emit_load_imm (code, ARMREG_IP, (guint32)func);
1268         code = emit_call_reg (code, ARMREG_IP);
1269
1270         switch (save_mode) {
1271         case SAVE_TWO:
1272                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
1273                 ARM_LDR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
1274                 break;
1275         case SAVE_ONE:
1276                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
1277                 break;
1278         case SAVE_FP:
1279                 /* FIXME */
1280                 break;
1281         case SAVE_NONE:
1282         default:
1283                 break;
1284         }
1285
1286         return code;
1287 }
1288
1289 /*
1290  * The immediate field for cond branches is big enough for all reasonable methods
1291  */
1292 #define EMIT_COND_BRANCH_FLAGS(ins,condcode) \
1293 if (ins->flags & MONO_INST_BRLABEL) { \
1294         if (0 && ins->inst_i0->inst_c0) { \
1295                 ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffffff);    \
1296         } else { \
1297                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1298                 ARM_B_COND (code, (condcode), 0);       \
1299         } \
1300 } else { \
1301         if (0 && ins->inst_true_bb->native_offset) { \
1302                 ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffffff); \
1303         } else { \
1304                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1305                 ARM_B_COND (code, (condcode), 0);       \
1306         } \
1307 }
1308
1309 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_cc_table [(cond)])
1310
1311 /* emit an exception if condition is fail
1312  *
1313  * We assign the extra code used to throw the implicit exceptions
1314  * to cfg->bb_exit as far as the big branch handling is concerned
1315  */
1316 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(condcode,exc_name)            \
1317         do {                                                        \
1318                 mono_add_patch_info (cfg, code - cfg->native_code,   \
1319                                     MONO_PATCH_INFO_EXC, exc_name);  \
1320                 ARM_BL_COND (code, (condcode), 0);      \
1321         } while (0); 
1322
1323 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_cc_table [(cond)], (exc_name))
1324
1325 void
1326 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1327 {
1328 }
1329
1330 void
1331 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1332 {
1333         MonoInst *ins, *n;
1334
1335         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1336                 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1337
1338                 switch (ins->opcode) {
1339                 case OP_MUL_IMM: 
1340                         /* remove unnecessary multiplication with 1 */
1341                         if (ins->inst_imm == 1) {
1342                                 if (ins->dreg != ins->sreg1) {
1343                                         ins->opcode = OP_MOVE;
1344                                 } else {
1345                                         MONO_DELETE_INS (bb, ins);
1346                                         continue;
1347                                 }
1348                         } else {
1349                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1350                                 if (power2 > 0) {
1351                                         ins->opcode = OP_SHL_IMM;
1352                                         ins->inst_imm = power2;
1353                                 }
1354                         }
1355                         break;
1356                 case OP_LOAD_MEMBASE:
1357                 case OP_LOADI4_MEMBASE:
1358                         /* 
1359                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1360                          * OP_LOAD_MEMBASE offset(basereg), reg
1361                          */
1362                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1363                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1364                             ins->inst_basereg == last_ins->inst_destbasereg &&
1365                             ins->inst_offset == last_ins->inst_offset) {
1366                                 if (ins->dreg == last_ins->sreg1) {
1367                                         MONO_DELETE_INS (bb, ins);
1368                                         continue;
1369                                 } else {
1370                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1371                                         ins->opcode = OP_MOVE;
1372                                         ins->sreg1 = last_ins->sreg1;
1373                                 }
1374
1375                         /* 
1376                          * Note: reg1 must be different from the basereg in the second load
1377                          * OP_LOAD_MEMBASE offset(basereg), reg1
1378                          * OP_LOAD_MEMBASE offset(basereg), reg2
1379                          * -->
1380                          * OP_LOAD_MEMBASE offset(basereg), reg1
1381                          * OP_MOVE reg1, reg2
1382                          */
1383                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1384                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1385                               ins->inst_basereg != last_ins->dreg &&
1386                               ins->inst_basereg == last_ins->inst_basereg &&
1387                               ins->inst_offset == last_ins->inst_offset) {
1388
1389                                 if (ins->dreg == last_ins->dreg) {
1390                                         MONO_DELETE_INS (bb, ins);
1391                                         continue;
1392                                 } else {
1393                                         ins->opcode = OP_MOVE;
1394                                         ins->sreg1 = last_ins->dreg;
1395                                 }
1396
1397                                 //g_assert_not_reached ();
1398
1399 #if 0
1400                         /* 
1401                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1402                          * OP_LOAD_MEMBASE offset(basereg), reg
1403                          * -->
1404                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1405                          * OP_ICONST reg, imm
1406                          */
1407                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1408                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1409                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1410                                    ins->inst_offset == last_ins->inst_offset) {
1411                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1412                                 ins->opcode = OP_ICONST;
1413                                 ins->inst_c0 = last_ins->inst_imm;
1414                                 g_assert_not_reached (); // check this rule
1415 #endif
1416                         }
1417                         break;
1418                 case OP_LOADU1_MEMBASE:
1419                 case OP_LOADI1_MEMBASE:
1420                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1421                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1422                                         ins->inst_offset == last_ins->inst_offset) {
1423                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1424                                 ins->sreg1 = last_ins->sreg1;                           
1425                         }
1426                         break;
1427                 case OP_LOADU2_MEMBASE:
1428                 case OP_LOADI2_MEMBASE:
1429                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1430                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1431                                         ins->inst_offset == last_ins->inst_offset) {
1432                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1433                                 ins->sreg1 = last_ins->sreg1;                           
1434                         }
1435                         break;
1436                 case OP_MOVE:
1437                         ins->opcode = OP_MOVE;
1438                         /* 
1439                          * OP_MOVE reg, reg 
1440                          */
1441                         if (ins->dreg == ins->sreg1) {
1442                                 MONO_DELETE_INS (bb, ins);
1443                                 continue;
1444                         }
1445                         /* 
1446                          * OP_MOVE sreg, dreg 
1447                          * OP_MOVE dreg, sreg
1448                          */
1449                         if (last_ins && last_ins->opcode == OP_MOVE &&
1450                             ins->sreg1 == last_ins->dreg &&
1451                             ins->dreg == last_ins->sreg1) {
1452                                 MONO_DELETE_INS (bb, ins);
1453                                 continue;
1454                         }
1455                         break;
1456                 }
1457         }
1458 }
1459
1460 /* 
1461  * the branch_cc_table should maintain the order of these
1462  * opcodes.
1463 case CEE_BEQ:
1464 case CEE_BGE:
1465 case CEE_BGT:
1466 case CEE_BLE:
1467 case CEE_BLT:
1468 case CEE_BNE_UN:
1469 case CEE_BGE_UN:
1470 case CEE_BGT_UN:
1471 case CEE_BLE_UN:
1472 case CEE_BLT_UN:
1473  */
1474 static const guchar 
1475 branch_cc_table [] = {
1476         ARMCOND_EQ, 
1477         ARMCOND_GE, 
1478         ARMCOND_GT, 
1479         ARMCOND_LE,
1480         ARMCOND_LT, 
1481         
1482         ARMCOND_NE, 
1483         ARMCOND_HS, 
1484         ARMCOND_HI, 
1485         ARMCOND_LS,
1486         ARMCOND_LO
1487 };
1488
1489
1490 #define NEW_INS(cfg,ins,dest,op) do {                                   \
1491                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
1492                 (dest)->opcode = (op);  \
1493                 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
1494         } while (0)
1495
1496 static int
1497 map_to_reg_reg_op (int op)
1498 {
1499         switch (op) {
1500         case OP_ADD_IMM:
1501                 return OP_IADD;
1502         case OP_SUB_IMM:
1503                 return OP_ISUB;
1504         case OP_AND_IMM:
1505                 return OP_IAND;
1506         case OP_COMPARE_IMM:
1507                 return OP_COMPARE;
1508         case OP_ADDCC_IMM:
1509                 return OP_ADDCC;
1510         case OP_ADC_IMM:
1511                 return OP_ADC;
1512         case OP_SUBCC_IMM:
1513                 return OP_SUBCC;
1514         case OP_SBB_IMM:
1515                 return OP_SBB;
1516         case OP_OR_IMM:
1517                 return OP_IOR;
1518         case OP_XOR_IMM:
1519                 return OP_IXOR;
1520         case OP_LOAD_MEMBASE:
1521                 return OP_LOAD_MEMINDEX;
1522         case OP_LOADI4_MEMBASE:
1523                 return OP_LOADI4_MEMINDEX;
1524         case OP_LOADU4_MEMBASE:
1525                 return OP_LOADU4_MEMINDEX;
1526         case OP_LOADU1_MEMBASE:
1527                 return OP_LOADU1_MEMINDEX;
1528         case OP_LOADI2_MEMBASE:
1529                 return OP_LOADI2_MEMINDEX;
1530         case OP_LOADU2_MEMBASE:
1531                 return OP_LOADU2_MEMINDEX;
1532         case OP_LOADI1_MEMBASE:
1533                 return OP_LOADI1_MEMINDEX;
1534         case OP_STOREI1_MEMBASE_REG:
1535                 return OP_STOREI1_MEMINDEX;
1536         case OP_STOREI2_MEMBASE_REG:
1537                 return OP_STOREI2_MEMINDEX;
1538         case OP_STOREI4_MEMBASE_REG:
1539                 return OP_STOREI4_MEMINDEX;
1540         case OP_STORE_MEMBASE_REG:
1541                 return OP_STORE_MEMINDEX;
1542         case OP_STORER4_MEMBASE_REG:
1543                 return OP_STORER4_MEMINDEX;
1544         case OP_STORER8_MEMBASE_REG:
1545                 return OP_STORER8_MEMINDEX;
1546         case OP_STORE_MEMBASE_IMM:
1547                 return OP_STORE_MEMBASE_REG;
1548         case OP_STOREI1_MEMBASE_IMM:
1549                 return OP_STOREI1_MEMBASE_REG;
1550         case OP_STOREI2_MEMBASE_IMM:
1551                 return OP_STOREI2_MEMBASE_REG;
1552         case OP_STOREI4_MEMBASE_IMM:
1553                 return OP_STOREI4_MEMBASE_REG;
1554         }
1555         g_assert_not_reached ();
1556 }
1557
1558 /*
1559  * Remove from the instruction list the instructions that can't be
1560  * represented with very simple instructions with no register
1561  * requirements.
1562  */
1563 void
1564 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1565 {
1566         int rot_amount, imm8, low_imm;
1567         MonoInst *ins, *temp;
1568
1569         /* setup the virtual reg allocator */
1570         if (bb->max_vreg > cfg->rs->next_vreg)
1571                 cfg->rs->next_vreg = bb->max_vreg;
1572
1573         MONO_BB_FOR_EACH_INS (bb, ins) {
1574                 MonoInst *last_ins;
1575
1576 loop_start:
1577                 last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1578                 switch (ins->opcode) {
1579                 case OP_ADD_IMM:
1580                 case OP_SUB_IMM:
1581                 case OP_AND_IMM:
1582                 case OP_COMPARE_IMM:
1583                 case OP_ADDCC_IMM:
1584                 case OP_ADC_IMM:
1585                 case OP_SUBCC_IMM:
1586                 case OP_SBB_IMM:
1587                 case OP_OR_IMM:
1588                 case OP_XOR_IMM:
1589                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
1590                                 NEW_INS (cfg, ins, temp, OP_ICONST);
1591                                 temp->inst_c0 = ins->inst_imm;
1592                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1593                                 ins->sreg2 = temp->dreg;
1594                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1595                         }
1596                         break;
1597                 case OP_MUL_IMM:
1598                         if (ins->inst_imm == 1) {
1599                                 ins->opcode = OP_MOVE;
1600                                 break;
1601                         }
1602                         if (ins->inst_imm == 0) {
1603                                 ins->opcode = OP_ICONST;
1604                                 ins->inst_c0 = 0;
1605                                 break;
1606                         }
1607                         imm8 = mono_is_power_of_two (ins->inst_imm);
1608                         if (imm8 > 0) {
1609                                 ins->opcode = OP_SHL_IMM;
1610                                 ins->inst_imm = imm8;
1611                                 break;
1612                         }
1613                         NEW_INS (cfg, ins, temp, OP_ICONST);
1614                         temp->inst_c0 = ins->inst_imm;
1615                         temp->dreg = mono_regstate_next_int (cfg->rs);
1616                         ins->sreg2 = temp->dreg;
1617                         ins->opcode = OP_IMUL;
1618                         break;
1619                 case OP_LOAD_MEMBASE:
1620                 case OP_LOADI4_MEMBASE:
1621                 case OP_LOADU4_MEMBASE:
1622                 case OP_LOADU1_MEMBASE:
1623                         /* we can do two things: load the immed in a register
1624                          * and use an indexed load, or see if the immed can be
1625                          * represented as an ad_imm + a load with a smaller offset
1626                          * that fits. We just do the first for now, optimize later.
1627                          */
1628                         if (arm_is_imm12 (ins->inst_offset))
1629                                 break;
1630                         NEW_INS (cfg, ins, temp, OP_ICONST);
1631                         temp->inst_c0 = ins->inst_offset;
1632                         temp->dreg = mono_regstate_next_int (cfg->rs);
1633                         ins->sreg2 = temp->dreg;
1634                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1635                         break;
1636                 case OP_LOADI2_MEMBASE:
1637                 case OP_LOADU2_MEMBASE:
1638                 case OP_LOADI1_MEMBASE:
1639                         if (arm_is_imm8 (ins->inst_offset))
1640                                 break;
1641                         NEW_INS (cfg, ins, temp, OP_ICONST);
1642                         temp->inst_c0 = ins->inst_offset;
1643                         temp->dreg = mono_regstate_next_int (cfg->rs);
1644                         ins->sreg2 = temp->dreg;
1645                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1646                         break;
1647                 case OP_LOADR4_MEMBASE:
1648                 case OP_LOADR8_MEMBASE:
1649                         if (arm_is_fpimm8 (ins->inst_offset))
1650                                 break;
1651                         low_imm = ins->inst_offset & 0x1ff;
1652                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~0x1ff, &rot_amount)) >= 0) {
1653                                 NEW_INS (cfg, ins, temp, OP_ADD_IMM);
1654                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
1655                                 temp->sreg1 = ins->inst_basereg;
1656                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1657                                 ins->inst_basereg = temp->dreg;
1658                                 ins->inst_offset = low_imm;
1659                                 break;
1660                         }
1661                         /* VFP/FPA doesn't have indexed load instructions */
1662                         g_assert_not_reached ();
1663                         break;
1664                 case OP_STORE_MEMBASE_REG:
1665                 case OP_STOREI4_MEMBASE_REG:
1666                 case OP_STOREI1_MEMBASE_REG:
1667                         if (arm_is_imm12 (ins->inst_offset))
1668                                 break;
1669                         NEW_INS (cfg, ins, temp, OP_ICONST);
1670                         temp->inst_c0 = ins->inst_offset;
1671                         temp->dreg = mono_regstate_next_int (cfg->rs);
1672                         ins->sreg2 = temp->dreg;
1673                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1674                         break;
1675                 case OP_STOREI2_MEMBASE_REG:
1676                         if (arm_is_imm8 (ins->inst_offset))
1677                                 break;
1678                         NEW_INS (cfg, ins, temp, OP_ICONST);
1679                         temp->inst_c0 = ins->inst_offset;
1680                         temp->dreg = mono_regstate_next_int (cfg->rs);
1681                         ins->sreg2 = temp->dreg;
1682                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1683                         break;
1684                 case OP_STORER4_MEMBASE_REG:
1685                 case OP_STORER8_MEMBASE_REG:
1686                         if (arm_is_fpimm8 (ins->inst_offset))
1687                                 break;
1688                         low_imm = ins->inst_offset & 0x1ff;
1689                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~ 0x1ff, &rot_amount)) >= 0 && arm_is_fpimm8 (low_imm)) {
1690                                 NEW_INS (cfg, ins, temp, OP_ADD_IMM);
1691                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
1692                                 temp->sreg1 = ins->inst_destbasereg;
1693                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1694                                 ins->inst_destbasereg = temp->dreg;
1695                                 ins->inst_offset = low_imm;
1696                                 break;
1697                         }
1698                         /*g_print ("fail with: %d (%d, %d)\n", ins->inst_offset, ins->inst_offset & ~0x1ff, low_imm);*/
1699                         /* VFP/FPA doesn't have indexed store instructions */
1700                         g_assert_not_reached ();
1701                         break;
1702                 case OP_STORE_MEMBASE_IMM:
1703                 case OP_STOREI1_MEMBASE_IMM:
1704                 case OP_STOREI2_MEMBASE_IMM:
1705                 case OP_STOREI4_MEMBASE_IMM:
1706                         NEW_INS (cfg, ins, temp, OP_ICONST);
1707                         temp->inst_c0 = ins->inst_imm;
1708                         temp->dreg = mono_regstate_next_int (cfg->rs);
1709                         ins->sreg1 = temp->dreg;
1710                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1711                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
1712                 }
1713         }
1714         bb->max_vreg = cfg->rs->next_vreg;
1715 }
1716
1717 static guchar*
1718 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1719 {
1720         /* sreg is a float, dreg is an integer reg  */
1721 #ifdef ARM_FPU_FPA
1722         ARM_FIXZ (code, dreg, sreg);
1723 #elif defined(ARM_FPU_VFP)
1724         if (is_signed)
1725                 ARM_TOSIZD (code, ARM_VFP_F0, sreg);
1726         else
1727                 ARM_TOUIZD (code, ARM_VFP_F0, sreg);
1728         ARM_FMRS (code, dreg, ARM_VFP_F0);
1729 #endif
1730         if (!is_signed) {
1731                 if (size == 1)
1732                         ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff);
1733                 else if (size == 2) {
1734                         ARM_SHL_IMM (code, dreg, dreg, 16);
1735                         ARM_SHR_IMM (code, dreg, dreg, 16);
1736                 }
1737         } else {
1738                 if (size == 1) {
1739                         ARM_SHL_IMM (code, dreg, dreg, 24);
1740                         ARM_SAR_IMM (code, dreg, dreg, 24);
1741                 } else if (size == 2) {
1742                         ARM_SHL_IMM (code, dreg, dreg, 16);
1743                         ARM_SAR_IMM (code, dreg, dreg, 16);
1744                 }
1745         }
1746         return code;
1747 }
1748
1749 typedef struct {
1750         guchar *code;
1751         const guchar *target;
1752         int absolute;
1753         int found;
1754 } PatchData;
1755
1756 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1757
1758 static int
1759 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1760         PatchData *pdata = (PatchData*)user_data;
1761         guchar *code = data;
1762         guint32 *thunks = data;
1763         guint32 *endthunks = (guint32*)(code + bsize);
1764         int count = 0;
1765         int difflow, diffhigh;
1766
1767         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1768         difflow = (char*)pdata->code - (char*)thunks;
1769         diffhigh = (char*)pdata->code - (char*)endthunks;
1770         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1771                 return 0;
1772
1773         /*
1774          * The thunk is composed of 3 words:
1775          * load constant from thunks [2] into ARM_IP
1776          * bx to ARM_IP
1777          * address constant
1778          * Note that the LR register is already setup
1779          */
1780         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1781         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1782                 while (thunks < endthunks) {
1783                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1784                         if (thunks [2] == (guint32)pdata->target) {
1785                                 arm_patch (pdata->code, (guchar*)thunks);
1786                                 mono_arch_flush_icache (pdata->code, 4);
1787                                 pdata->found = 1;
1788                                 return 1;
1789                         } else if ((thunks [0] == 0) && (thunks [1] == 0) && (thunks [2] == 0)) {
1790                                 /* found a free slot instead: emit thunk */
1791                                 /* ARMREG_IP is fine to use since this can't be an IMT call
1792                                  * which is indirect
1793                                  */
1794                                 code = (guchar*)thunks;
1795                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
1796                                 if (thumb_supported)
1797                                         ARM_BX (code, ARMREG_IP);
1798                                 else
1799                                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
1800                                 thunks [2] = (guint32)pdata->target;
1801                                 mono_arch_flush_icache ((guchar*)thunks, 12);
1802
1803                                 arm_patch (pdata->code, (guchar*)thunks);
1804                                 mono_arch_flush_icache (pdata->code, 4);
1805                                 pdata->found = 1;
1806                                 return 1;
1807                         }
1808                         /* skip 12 bytes, the size of the thunk */
1809                         thunks += 3;
1810                         count++;
1811                 }
1812                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1813         }
1814         return 0;
1815 }
1816
1817 static void
1818 handle_thunk (int absolute, guchar *code, const guchar *target) {
1819         MonoDomain *domain = mono_domain_get ();
1820         PatchData pdata;
1821
1822         pdata.code = code;
1823         pdata.target = target;
1824         pdata.absolute = absolute;
1825         pdata.found = 0;
1826
1827         mono_domain_lock (domain);
1828         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1829
1830         if (!pdata.found) {
1831                 /* this uses the first available slot */
1832                 pdata.found = 2;
1833                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1834         }
1835         mono_domain_unlock (domain);
1836
1837         if (pdata.found != 1)
1838                 g_print ("thunk failed for %p from %p\n", target, code);
1839         g_assert (pdata.found == 1);
1840 }
1841
1842 void
1843 arm_patch (guchar *code, const guchar *target)
1844 {
1845         guint32 *code32 = (void*)code;
1846         guint32 ins = *code32;
1847         guint32 prim = (ins >> 25) & 7;
1848         guint32 tval = GPOINTER_TO_UINT (target);
1849
1850         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1851         if (prim == 5) { /* 101b */
1852                 /* the diff starts 8 bytes from the branch opcode */
1853                 gint diff = target - code - 8;
1854                 gint tbits;
1855                 gint tmask = 0xffffffff;
1856                 if (tval & 1) { /* entering thumb mode */
1857                         diff = target - 1 - code - 8;
1858                         g_assert (thumb_supported);
1859                         tbits = 0xf << 28; /* bl->blx bit pattern */
1860                         g_assert ((ins & (1 << 24))); /* it must be a bl, not b instruction */
1861                         /* this low bit of the displacement is moved to bit 24 in the instruction encoding */
1862                         if (diff & 2) {
1863                                 tbits |= 1 << 24;
1864                         }
1865                         tmask = ~(1 << 24); /* clear the link bit */
1866                         /*g_print ("blx to thumb: target: %p, code: %p, diff: %d, mask: %x\n", target, code, diff, tmask);*/
1867                 } else {
1868                         tbits = 0;
1869                 }
1870                 if (diff >= 0) {
1871                         if (diff <= 33554431) {
1872                                 diff >>= 2;
1873                                 ins = (ins & 0xff000000) | diff;
1874                                 ins &= tmask;
1875                                 *code32 = ins | tbits;
1876                                 return;
1877                         }
1878                 } else {
1879                         /* diff between 0 and -33554432 */
1880                         if (diff >= -33554432) {
1881                                 diff >>= 2;
1882                                 ins = (ins & 0xff000000) | (diff & ~0xff000000);
1883                                 ins &= tmask;
1884                                 *code32 = ins | tbits;
1885                                 return;
1886                         }
1887                 }
1888                 
1889                 handle_thunk (TRUE, code, target);
1890                 return;
1891         }
1892
1893         /*
1894          * The alternative call sequences looks like this:
1895          *
1896          *      ldr ip, [pc] // loads the address constant
1897          *      b 1f         // jumps around the constant
1898          *      address constant embedded in the code
1899          *   1f:
1900          *      mov lr, pc
1901          *      mov pc, ip
1902          *
1903          * There are two cases for patching:
1904          * a) at the end of method emission: in this case code points to the start
1905          *    of the call sequence
1906          * b) during runtime patching of the call site: in this case code points
1907          *    to the mov pc, ip instruction
1908          *
1909          * We have to handle also the thunk jump code sequence:
1910          *
1911          *      ldr ip, [pc]
1912          *      mov pc, ip
1913          *      address constant // execution never reaches here
1914          */
1915         if ((ins & 0x0ffffff0) == 0x12fff10) {
1916                 /* Branch and exchange: the address is constructed in a reg 
1917                  * We can patch BX when the code sequence is the following:
1918                  *  ldr     ip, [pc, #0]    ; 0x8
1919                  *  b       0xc
1920                  *  .word code_ptr
1921                  *  mov     lr, pc
1922                  *  bx      ips
1923                  * */
1924                 guint32 ccode [4];
1925                 guint8 *emit = (guint8*)ccode;
1926                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
1927                 ARM_B (emit, 0);
1928                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
1929                 ARM_BX (emit, ARMREG_IP);
1930
1931                 /*patching from magic trampoline*/
1932                 if (ins == ccode [3]) {
1933                         g_assert (code32 [-4] == ccode [0]);
1934                         g_assert (code32 [-3] == ccode [1]);
1935                         g_assert (code32 [-1] == ccode [2]);
1936                         code32 [-2] = (guint32)target;
1937                         return;
1938                 }
1939                 /*patching from JIT*/
1940                 if (ins == ccode [0]) {
1941                         g_assert (code32 [1] == ccode [1]);
1942                         g_assert (code32 [3] == ccode [2]);
1943                         g_assert (code32 [4] == ccode [3]);
1944                         code32 [2] = (guint32)target;
1945                         return;
1946                 }
1947                 g_assert_not_reached ();
1948         } else if ((ins & 0x0ffffff0) == 0x12fff30) {
1949                 /*
1950                  * ldr ip, [pc, #0]
1951                  * b 0xc
1952                  * .word code_ptr
1953                  * blx ip
1954                  */
1955                 guint32 ccode [4];
1956                 guint8 *emit = (guint8*)ccode;
1957                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
1958                 ARM_B (emit, 0);
1959                 ARM_BLX_REG (emit, ARMREG_IP);
1960
1961                 g_assert (code32 [-3] == ccode [0]);
1962                 g_assert (code32 [-2] == ccode [1]);
1963                 g_assert (code32 [0] == ccode [2]);
1964
1965                 code32 [-1] = (guint32)target;
1966         } else {
1967                 guint32 ccode [4];
1968                 guint32 *tmp = ccode;
1969                 guint8 *emit = (guint8*)tmp;
1970                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
1971                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
1972                 ARM_MOV_REG_REG (emit, ARMREG_PC, ARMREG_IP);
1973                 ARM_BX (emit, ARMREG_IP);
1974                 if (ins == ccode [2]) {
1975                         g_assert_not_reached (); // should be -2 ...
1976                         code32 [-1] = (guint32)target;
1977                         return;
1978                 }
1979                 if (ins == ccode [0]) {
1980                         /* handles both thunk jump code and the far call sequence */
1981                         code32 [2] = (guint32)target;
1982                         return;
1983                 }
1984                 g_assert_not_reached ();
1985         }
1986 //      g_print ("patched with 0x%08x\n", ins);
1987 }
1988
1989 /* 
1990  * Return the >= 0 uimm8 value if val can be represented with a byte + rotation
1991  * (with the rotation amount in *rot_amount. rot_amount is already adjusted
1992  * to be used with the emit macros.
1993  * Return -1 otherwise.
1994  */
1995 static int
1996 mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount)
1997 {
1998         guint32 res, i;
1999         for (i = 0; i < 31; i+= 2) {
2000                 res = (val << (32 - i)) | (val >> i);
2001                 if (res & ~0xff)
2002                         continue;
2003                 *rot_amount = i? 32 - i: 0;
2004                 return res;
2005         }
2006         return -1;
2007 }
2008
2009 /*
2010  * Emits in code a sequence of instructions that load the value 'val'
2011  * into the dreg register. Uses at most 4 instructions.
2012  */
2013 guint8*
2014 mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
2015 {
2016         int imm8, rot_amount;
2017 #if 0
2018         ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
2019         /* skip the constant pool */
2020         ARM_B (code, 0);
2021         *(int*)code = val;
2022         code += 4;
2023         return code;
2024 #endif
2025         if ((imm8 = mono_arm_is_rotated_imm8 (val, &rot_amount)) >= 0) {
2026                 ARM_MOV_REG_IMM (code, dreg, imm8, rot_amount);
2027         } else if ((imm8 = mono_arm_is_rotated_imm8 (~val, &rot_amount)) >= 0) {
2028                 ARM_MVN_REG_IMM (code, dreg, imm8, rot_amount);
2029         } else {
2030                 if (val & 0xFF) {
2031                         ARM_MOV_REG_IMM8 (code, dreg, (val & 0xFF));
2032                         if (val & 0xFF00) {
2033                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
2034                         }
2035                         if (val & 0xFF0000) {
2036                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
2037                         }
2038                         if (val & 0xFF000000) {
2039                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
2040                         }
2041                 } else if (val & 0xFF00) {
2042                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF00) >> 8, 24);
2043                         if (val & 0xFF0000) {
2044                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
2045                         }
2046                         if (val & 0xFF000000) {
2047                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
2048                         }
2049                 } else if (val & 0xFF0000) {
2050                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF0000) >> 16, 16);
2051                         if (val & 0xFF000000) {
2052                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
2053                         }
2054                 }
2055                 //g_assert_not_reached ();
2056         }
2057         return code;
2058 }
2059
2060 /*
2061  * emit_load_volatile_arguments:
2062  *
2063  *  Load volatile arguments from the stack to the original input registers.
2064  * Required before a tail call.
2065  */
2066 static guint8*
2067 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2068 {
2069         MonoMethod *method = cfg->method;
2070         MonoMethodSignature *sig;
2071         MonoInst *inst;
2072         CallInfo *cinfo;
2073         guint32 i, pos;
2074
2075         /* FIXME: Generate intermediate code instead */
2076
2077         sig = mono_method_signature (method);
2078
2079         /* This is the opposite of the code in emit_prolog */
2080
2081         pos = 0;
2082
2083         cinfo = calculate_sizes (sig, sig->pinvoke);
2084
2085         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2086                 ArgInfo *ainfo = &cinfo->ret;
2087                 inst = cfg->vret_addr;
2088                 g_assert (arm_is_imm12 (inst->inst_offset));
2089                 ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2090         }
2091         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2092                 ArgInfo *ainfo = cinfo->args + i;
2093                 inst = cfg->args [pos];
2094                 
2095                 if (cfg->verbose_level > 2)
2096                         g_print ("Loading argument %d (type: %d)\n", i, ainfo->regtype);
2097                 if (inst->opcode == OP_REGVAR) {
2098                         if (ainfo->regtype == RegTypeGeneral)
2099                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
2100                         else if (ainfo->regtype == RegTypeFP) {
2101                                 g_assert_not_reached ();
2102                         } else if (ainfo->regtype == RegTypeBase) {
2103                                 // FIXME:
2104                                 NOT_IMPLEMENTED;
2105                                 /*
2106                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
2107                                         ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
2108                                 } else {
2109                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2110                                         ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
2111                                 }
2112                                 */
2113                         } else
2114                                 g_assert_not_reached ();
2115                 } else {
2116                         if (ainfo->regtype == RegTypeGeneral) {
2117                                 switch (ainfo->size) {
2118                                 case 1:
2119                                 case 2:
2120                                         // FIXME:
2121                                         NOT_IMPLEMENTED;
2122                                         break;
2123                                 case 8:
2124                                         g_assert (arm_is_imm12 (inst->inst_offset));
2125                                         ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2126                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
2127                                         ARM_LDR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2128                                         break;
2129                                 default:
2130                                         if (arm_is_imm12 (inst->inst_offset)) {
2131                                                 ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2132                                         } else {
2133                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2134                                                 ARM_LDR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
2135                                         }
2136                                         break;
2137                                 }
2138                         } else if (ainfo->regtype == RegTypeBaseGen) {
2139                                 // FIXME:
2140                                 NOT_IMPLEMENTED;
2141                         } else if (ainfo->regtype == RegTypeBase) {
2142                                 // FIXME:
2143                                 NOT_IMPLEMENTED;
2144                         } else if (ainfo->regtype == RegTypeFP) {
2145                                 g_assert_not_reached ();
2146                         } else if (ainfo->regtype == RegTypeStructByVal) {
2147                                 int doffset = inst->inst_offset;
2148                                 int soffset = 0;
2149                                 int cur_reg;
2150                                 int size = 0;
2151                                 if (mono_class_from_mono_type (inst->inst_vtype))
2152                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
2153                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
2154                                         if (arm_is_imm12 (doffset)) {
2155                                                 ARM_LDR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
2156                                         } else {
2157                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
2158                                                 ARM_LDR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
2159                                         }
2160                                         soffset += sizeof (gpointer);
2161                                         doffset += sizeof (gpointer);
2162                                 }
2163                                 if (ainfo->vtsize)
2164                                         // FIXME:
2165                                         NOT_IMPLEMENTED;
2166                         } else if (ainfo->regtype == RegTypeStructByAddr) {
2167                         } else {
2168                                 // FIXME:
2169                                 NOT_IMPLEMENTED;
2170                         }
2171                 }
2172                 pos ++;
2173         }
2174
2175         g_free (cinfo);
2176
2177         return code;
2178 }
2179
2180 void
2181 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2182 {
2183         MonoInst *ins;
2184         MonoCallInst *call;
2185         guint offset;
2186         guint8 *code = cfg->native_code + cfg->code_len;
2187         guint last_offset = 0;
2188         int max_len, cpos;
2189         int imm8, rot_amount;
2190
2191         /* we don't align basic blocks of loops on arm */
2192
2193         if (cfg->verbose_level > 2)
2194                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2195
2196         cpos = bb->max_offset;
2197
2198         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2199                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2200                 //g_assert (!mono_compile_aot);
2201                 //cpos += 6;
2202                 //if (bb->cil_code)
2203                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2204                 /* this is not thread save, but good enough */
2205                 /* fixme: howto handle overflows? */
2206                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
2207         }
2208
2209     if (mono_break_at_bb_method && mono_method_desc_full_match (mono_break_at_bb_method, cfg->method) && bb->block_num == mono_break_at_bb_bb_num) {
2210                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2211                                                          (gpointer)"mono_break");
2212                 code = emit_call_seq (cfg, code);
2213         }
2214
2215         MONO_BB_FOR_EACH_INS (bb, ins) {
2216                 offset = code - cfg->native_code;
2217
2218                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2219
2220                 if (offset > (cfg->code_size - max_len - 16)) {
2221                         cfg->code_size *= 2;
2222                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2223                         code = cfg->native_code + offset;
2224                 }
2225         //      if (ins->cil_code)
2226         //              g_print ("cil code\n");
2227                 mono_debug_record_line_number (cfg, ins, offset);
2228
2229                 switch (ins->opcode) {
2230                 case OP_MEMORY_BARRIER:
2231                         break;
2232                 case OP_TLS_GET:
2233                         g_assert_not_reached ();
2234                         break;
2235                 /*case OP_BIGMUL:
2236                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
2237                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2238                         break;
2239                 case OP_BIGMUL_UN:
2240                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
2241                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2242                         break;*/
2243                 case OP_STOREI1_MEMBASE_IMM:
2244                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFF);
2245                         g_assert (arm_is_imm12 (ins->inst_offset));
2246                         ARM_STRB_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
2247                         break;
2248                 case OP_STOREI2_MEMBASE_IMM:
2249                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFFFF);
2250                         g_assert (arm_is_imm8 (ins->inst_offset));
2251                         ARM_STRH_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
2252                         break;
2253                 case OP_STORE_MEMBASE_IMM:
2254                 case OP_STOREI4_MEMBASE_IMM:
2255                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm);
2256                         g_assert (arm_is_imm12 (ins->inst_offset));
2257                         ARM_STR_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
2258                         break;
2259                 case OP_STOREI1_MEMBASE_REG:
2260                         g_assert (arm_is_imm12 (ins->inst_offset));
2261                         ARM_STRB_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2262                         break;
2263                 case OP_STOREI2_MEMBASE_REG:
2264                         g_assert (arm_is_imm8 (ins->inst_offset));
2265                         ARM_STRH_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2266                         break;
2267                 case OP_STORE_MEMBASE_REG:
2268                 case OP_STOREI4_MEMBASE_REG:
2269                         /* this case is special, since it happens for spill code after lowering has been called */
2270                         if (arm_is_imm12 (ins->inst_offset)) {
2271                                 ARM_STR_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2272                         } else {
2273                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
2274                                 ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
2275                         }
2276                         break;
2277                 case OP_STOREI1_MEMINDEX:
2278                         ARM_STRB_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
2279                         break;
2280                 case OP_STOREI2_MEMINDEX:
2281                         ARM_STRH_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
2282                         break;
2283                 case OP_STORE_MEMINDEX:
2284                 case OP_STOREI4_MEMINDEX:
2285                         ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
2286                         break;
2287                 case OP_LOADU4_MEM:
2288                         g_assert_not_reached ();
2289                         break;
2290                 case OP_LOAD_MEMINDEX:
2291                 case OP_LOADI4_MEMINDEX:
2292                 case OP_LOADU4_MEMINDEX:
2293                         ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
2294                         break;
2295                 case OP_LOADI1_MEMINDEX:
2296                         ARM_LDRSB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
2297                         break;
2298                 case OP_LOADU1_MEMINDEX:
2299                         ARM_LDRB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
2300                         break;
2301                 case OP_LOADI2_MEMINDEX:
2302                         ARM_LDRSH_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
2303                         break;
2304                 case OP_LOADU2_MEMINDEX:
2305                         ARM_LDRH_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
2306                         break;
2307                 case OP_LOAD_MEMBASE:
2308                 case OP_LOADI4_MEMBASE:
2309                 case OP_LOADU4_MEMBASE:
2310                         /* this case is special, since it happens for spill code after lowering has been called */
2311                         if (arm_is_imm12 (ins->inst_offset)) {
2312                                 ARM_LDR_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2313                         } else {
2314                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
2315                                 ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
2316                         }
2317                         break;
2318                 case OP_LOADI1_MEMBASE:
2319                         g_assert (arm_is_imm8 (ins->inst_offset));
2320                         ARM_LDRSB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2321                         break;
2322                 case OP_LOADU1_MEMBASE:
2323                         g_assert (arm_is_imm12 (ins->inst_offset));
2324                         ARM_LDRB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2325                         break;
2326                 case OP_LOADU2_MEMBASE:
2327                         g_assert (arm_is_imm8 (ins->inst_offset));
2328                         ARM_LDRH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2329                         break;
2330                 case OP_LOADI2_MEMBASE:
2331                         g_assert (arm_is_imm8 (ins->inst_offset));
2332                         ARM_LDRSH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2333                         break;
2334                 case OP_ICONV_TO_I1:
2335                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 24);
2336                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 24);
2337                         break;
2338                 case OP_ICONV_TO_I2:
2339                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
2340                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 16);
2341                         break;
2342                 case OP_ICONV_TO_U1:
2343                         ARM_AND_REG_IMM8 (code, ins->dreg, ins->sreg1, 0xff);
2344                         break;
2345                 case OP_ICONV_TO_U2:
2346                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
2347                         ARM_SHR_IMM (code, ins->dreg, ins->dreg, 16);
2348                         break;
2349                 case OP_COMPARE:
2350                         ARM_CMP_REG_REG (code, ins->sreg1, ins->sreg2);
2351                         break;
2352                 case OP_COMPARE_IMM:
2353                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2354                         g_assert (imm8 >= 0);
2355                         ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount);
2356                         break;
2357                 case OP_BREAK:
2358                         /*
2359                          * gdb does not like encountering the hw breakpoint ins in the debugged code. 
2360                          * So instead of emitting a trap, we emit a call a C function and place a 
2361                          * breakpoint there.
2362                          */
2363                         //*(int*)code = 0xef9f0001;
2364                         //code += 4;
2365                         //ARM_DBRK (code);
2366                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2367                                                                  (gpointer)"mono_break");
2368                         code = emit_call_seq (cfg, code);
2369                         break;
2370                 case OP_ADDCC:
2371                         ARM_ADDS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2372                         break;
2373                 case OP_IADD:
2374                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2375                         break;
2376                 case OP_ADC:
2377                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2378                         break;
2379                 case OP_ADDCC_IMM:
2380                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2381                         g_assert (imm8 >= 0);
2382                         ARM_ADDS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2383                         break;
2384                 case OP_ADD_IMM:
2385                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2386                         g_assert (imm8 >= 0);
2387                         ARM_ADD_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2388                         break;
2389                 case OP_ADC_IMM:
2390                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2391                         g_assert (imm8 >= 0);
2392                         ARM_ADCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2393                         break;
2394                 case OP_IADD_OVF:
2395                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2396                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2397                         break;
2398                 case OP_IADD_OVF_UN:
2399                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2400                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2401                         break;
2402                 case OP_ISUB_OVF:
2403                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2404                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2405                         break;
2406                 case OP_ISUB_OVF_UN:
2407                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2408                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2409                         break;
2410                 case OP_ADD_OVF_CARRY:
2411                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2412                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2413                         break;
2414                 case OP_ADD_OVF_UN_CARRY:
2415                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2416                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2417                         break;
2418                 case OP_SUB_OVF_CARRY:
2419                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2420                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2421                         break;
2422                 case OP_SUB_OVF_UN_CARRY:
2423                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2424                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2425                         break;
2426                 case OP_SUBCC:
2427                         ARM_SUBS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2428                         break;
2429                 case OP_SUBCC_IMM:
2430                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2431                         g_assert (imm8 >= 0);
2432                         ARM_SUBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2433                         break;
2434                 case OP_ISUB:
2435                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2436                         break;
2437                 case OP_SBB:
2438                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2439                         break;
2440                 case OP_SUB_IMM:
2441                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2442                         g_assert (imm8 >= 0);
2443                         ARM_SUB_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2444                         break;
2445                 case OP_SBB_IMM:
2446                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2447                         g_assert (imm8 >= 0);
2448                         ARM_SBCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2449                         break;
2450                 case OP_ARM_RSBS_IMM:
2451                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2452                         g_assert (imm8 >= 0);
2453                         ARM_RSBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2454                         break;
2455                 case OP_ARM_RSC_IMM:
2456                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2457                         g_assert (imm8 >= 0);
2458                         ARM_RSC_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2459                         break;
2460                 case OP_IAND:
2461                         ARM_AND_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2462                         break;
2463                 case OP_AND_IMM:
2464                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2465                         g_assert (imm8 >= 0);
2466                         ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2467                         break;
2468                 case OP_IDIV:
2469                 case OP_IDIV_UN:
2470                 case OP_DIV_IMM:
2471                 case OP_IREM:
2472                 case OP_IREM_UN:
2473                 case OP_REM_IMM:
2474                         /* crappy ARM arch doesn't have a DIV instruction */
2475                         g_assert_not_reached ();
2476                 case OP_IOR:
2477                         ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2478                         break;
2479                 case OP_OR_IMM:
2480                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2481                         g_assert (imm8 >= 0);
2482                         ARM_ORR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2483                         break;
2484                 case OP_IXOR:
2485                         ARM_EOR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2486                         break;
2487                 case OP_XOR_IMM:
2488                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2489                         g_assert (imm8 >= 0);
2490                         ARM_EOR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2491                         break;
2492                 case OP_ISHL:
2493                         ARM_SHL_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2494                         break;
2495                 case OP_SHL_IMM:
2496                         if (ins->inst_imm)
2497                                 ARM_SHL_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2498                         else if (ins->dreg != ins->sreg1)
2499                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2500                         break;
2501                 case OP_ISHR:
2502                         ARM_SAR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2503                         break;
2504                 case OP_SHR_IMM:
2505                         if (ins->inst_imm)
2506                                 ARM_SAR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2507                         else if (ins->dreg != ins->sreg1)
2508                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2509                         break;
2510                 case OP_SHR_UN_IMM:
2511                         if (ins->inst_imm)
2512                                 ARM_SHR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2513                         else if (ins->dreg != ins->sreg1)
2514                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2515                         break;
2516                 case OP_ISHR_UN:
2517                         ARM_SHR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2518                         break;
2519                 case OP_INOT:
2520                         ARM_MVN_REG_REG (code, ins->dreg, ins->sreg1);
2521                         break;
2522                 case OP_INEG:
2523                         ARM_RSB_REG_IMM8 (code, ins->dreg, ins->sreg1, 0);
2524                         break;
2525                 case OP_IMUL:
2526                         if (ins->dreg == ins->sreg2)
2527                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2528                         else
2529                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg2, ins->sreg1);
2530                         break;
2531                 case OP_MUL_IMM:
2532                         g_assert_not_reached ();
2533                         break;
2534                 case OP_IMUL_OVF:
2535                         /* FIXME: handle ovf/ sreg2 != dreg */
2536                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2537                         break;
2538                 case OP_IMUL_OVF_UN:
2539                         /* FIXME: handle ovf/ sreg2 != dreg */
2540                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2541                         break;
2542                 case OP_ICONST:
2543                         code = mono_arm_emit_load_imm (code, ins->dreg, ins->inst_c0);
2544                         break;
2545                 case OP_AOTCONST:
2546                         /* Load the GOT offset */
2547                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2548                         ARM_LDR_IMM (code, ins->dreg, ARMREG_PC, 0);
2549                         ARM_B (code, 0);
2550                         *(gpointer*)code = NULL;
2551                         code += 4;
2552                         /* Load the value from the GOT */
2553                         ARM_LDR_REG_REG (code, ins->dreg, ARMREG_PC, ins->dreg);
2554                         break;
2555                 case OP_ICONV_TO_I4:
2556                 case OP_ICONV_TO_U4:
2557                 case OP_MOVE:
2558                         if (ins->dreg != ins->sreg1)
2559                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2560                         break;
2561                 case OP_SETLRET: {
2562                         int saved = ins->sreg2;
2563                         if (ins->sreg2 == ARM_LSW_REG) {
2564                                 ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg2);
2565                                 saved = ARMREG_LR;
2566                         }
2567                         if (ins->sreg1 != ARM_LSW_REG)
2568                                 ARM_MOV_REG_REG (code, ARM_LSW_REG, ins->sreg1);
2569                         if (saved != ARM_MSW_REG)
2570                                 ARM_MOV_REG_REG (code, ARM_MSW_REG, saved);
2571                         break;
2572                 }
2573                 case OP_FMOVE:
2574 #ifdef ARM_FPU_FPA
2575                         ARM_MVFD (code, ins->dreg, ins->sreg1);
2576 #elif defined(ARM_FPU_VFP)
2577                         ARM_CPYD (code, ins->dreg, ins->sreg1);
2578 #endif
2579                         break;
2580                 case OP_FCONV_TO_R4:
2581 #ifdef ARM_FPU_FPA
2582                         ARM_MVFS (code, ins->dreg, ins->sreg1);
2583 #elif defined(ARM_FPU_VFP)
2584                         ARM_CVTD (code, ins->dreg, ins->sreg1);
2585                         ARM_CVTS (code, ins->dreg, ins->dreg);
2586 #endif
2587                         break;
2588                 case OP_JMP:
2589                         /*
2590                          * Keep in sync with mono_arch_emit_epilog
2591                          */
2592                         g_assert (!cfg->method->save_lmf);
2593
2594                         code = emit_load_volatile_arguments (cfg, code);
2595
2596                         code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
2597                         ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP)) | ((1 << ARMREG_LR)));
2598                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2599                         ARM_B (code, 0);
2600                         break;
2601                 case OP_CHECK_THIS:
2602                         /* ensure ins->sreg1 is not NULL */
2603                         ARM_LDR_IMM (code, ARMREG_LR, ins->sreg1, 0);
2604                         break;
2605                 case OP_ARGLIST: {
2606 #if ARM_PORT
2607                         if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2608                                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2609                         } else {
2610                                 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2611                                 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2612                         }
2613                         ppc_stw (code, ppc_r11, 0, ins->sreg1);
2614 #endif
2615                         break;
2616                 }
2617                 case OP_FCALL:
2618                 case OP_LCALL:
2619                 case OP_VCALL:
2620                 case OP_VOIDCALL:
2621                 case OP_CALL:
2622                         call = (MonoCallInst*)ins;
2623                         if (ins->flags & MONO_INST_HAS_METHOD)
2624                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2625                         else
2626                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2627                         code = emit_call_seq (cfg, code);
2628                         code = emit_move_return_value (cfg, ins, code);
2629                         break;
2630                 case OP_FCALL_REG:
2631                 case OP_LCALL_REG:
2632                 case OP_VCALL_REG:
2633                 case OP_VOIDCALL_REG:
2634                 case OP_CALL_REG:
2635                         code = emit_call_reg (code, ins->sreg1);
2636                         code = emit_move_return_value (cfg, ins, code);
2637                         break;
2638                 case OP_FCALL_MEMBASE:
2639                 case OP_LCALL_MEMBASE:
2640                 case OP_VCALL_MEMBASE:
2641                 case OP_VOIDCALL_MEMBASE:
2642                 case OP_CALL_MEMBASE:
2643                         g_assert (arm_is_imm12 (ins->inst_offset));
2644                         g_assert (ins->sreg1 != ARMREG_LR);
2645                         call = (MonoCallInst*)ins;
2646                         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2647                                 ARM_ADD_REG_IMM8 (code, ARMREG_LR, ARMREG_PC, 4);
2648                                 ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
2649                                 if (cfg->compile_aot) {
2650                                         /* 
2651                                          * We can't embed the method in the code stream in PIC code. Instead,
2652                                          * we put it in V5 in code emitted by mono_arch_emit_imt_argument (),
2653                                          * and embed NULL here to signal the IMT thunk that the call is made
2654                                          * from AOT code.
2655                                          */
2656                                         *((gpointer*)code) = NULL;
2657                                 } else {
2658                                         *((gpointer*)code) = (gpointer)call->method;
2659                                 }
2660                                 code += 4;
2661                         } else {
2662                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2663                                 ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
2664                         }
2665                         code = emit_move_return_value (cfg, ins, code);
2666                         break;
2667                 case OP_OUTARG:
2668                         g_assert_not_reached ();
2669                         break;
2670                 case OP_LOCALLOC: {
2671                         /* keep alignment */
2672                         int alloca_waste = cfg->param_area;
2673                         alloca_waste += 7;
2674                         alloca_waste &= ~7;
2675                         /* round the size to 8 bytes */
2676                         ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
2677                         ARM_BIC_REG_IMM8 (code, ins->dreg, ins->dreg, 7);
2678                         if (alloca_waste)
2679                                 ARM_ADD_REG_IMM8 (code, ins->dreg, ins->dreg, alloca_waste);
2680                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ins->dreg);
2681                         /* memzero the area: dreg holds the size, sp is the pointer */
2682                         if (ins->flags & MONO_INST_INIT) {
2683                                 guint8 *start_loop, *branch_to_cond;
2684                                 ARM_MOV_REG_IMM8 (code, ARMREG_LR, 0);
2685                                 branch_to_cond = code;
2686                                 ARM_B (code, 0);
2687                                 start_loop = code;
2688                                 ARM_STR_REG_REG (code, ARMREG_LR, ARMREG_SP, ins->dreg);
2689                                 arm_patch (branch_to_cond, code);
2690                                 /* decrement by 4 and set flags */
2691                                 ARM_SUBS_REG_IMM8 (code, ins->dreg, ins->dreg, 4);
2692                                 ARM_B_COND (code, ARMCOND_GE, 0);
2693                                 arm_patch (code - 4, start_loop);
2694                         }
2695                         ARM_ADD_REG_IMM8 (code, ins->dreg, ARMREG_SP, alloca_waste);
2696                         break;
2697                 }
2698                 case OP_THROW: {
2699                         if (ins->sreg1 != ARMREG_R0)
2700                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2701                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2702                                              (gpointer)"mono_arch_throw_exception");
2703                         code = emit_call_seq (cfg, code);
2704                         break;
2705                 }
2706                 case OP_RETHROW: {
2707                         if (ins->sreg1 != ARMREG_R0)
2708                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2709                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2710                                              (gpointer)"mono_arch_rethrow_exception");
2711                         code = emit_call_seq (cfg, code);
2712                         break;
2713                 }
2714                 case OP_START_HANDLER:
2715                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2716                                 ARM_STR_IMM (code, ARMREG_LR, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2717                         } else {
2718                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2719                                 ARM_STR_REG_REG (code, ARMREG_LR, ins->inst_left->inst_basereg, ARMREG_IP);
2720                         }
2721                         break;
2722                 case OP_ENDFILTER:
2723                         if (ins->sreg1 != ARMREG_R0)
2724                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2725                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2726                                 ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2727                         } else {
2728                                 g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
2729                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2730                                 ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
2731                         }
2732                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2733                         break;
2734                 case OP_ENDFINALLY:
2735                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2736                                 ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2737                         } else {
2738                                 g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
2739                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2740                                 ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
2741                         }
2742                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2743                         break;
2744                 case OP_CALL_HANDLER: 
2745                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2746                         ARM_BL (code, 0);
2747                         break;
2748                 case OP_LABEL:
2749                         ins->inst_c0 = code - cfg->native_code;
2750                         break;
2751                 case OP_BR:
2752                         if (ins->flags & MONO_INST_BRLABEL) {
2753                                 /*if (ins->inst_i0->inst_c0) {
2754                                         ARM_B (code, 0);
2755                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2756                                 } else*/ {
2757                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2758                                         ARM_B (code, 0);
2759                                 }
2760                         } else {
2761                                 /*if (ins->inst_target_bb->native_offset) {
2762                                         ARM_B (code, 0);
2763                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2764                                 } else*/ {
2765                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2766                                         ARM_B (code, 0);
2767                                 } 
2768                         }
2769                         break;
2770                 case OP_BR_REG:
2771                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
2772                         break;
2773                 case OP_SWITCH:
2774                         /* 
2775                          * In the normal case we have:
2776                          *      ldr pc, [pc, ins->sreg1 << 2]
2777                          *      nop
2778                          * If aot, we have:
2779                          *      ldr lr, [pc, ins->sreg1 << 2]
2780                          *      add pc, pc, lr
2781                          * After follows the data.
2782                          * FIXME: add aot support.
2783                          */
2784                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
2785                         if (offset > (cfg->code_size - max_len - 16)) {
2786                                 cfg->code_size += max_len;
2787                                 cfg->code_size *= 2;
2788                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2789                                 code = cfg->native_code + offset;
2790                         }
2791                         ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_PC, ins->sreg1, ARMSHIFT_LSL, 2);
2792                         ARM_NOP (code);
2793                         code += 4 * GPOINTER_TO_INT (ins->klass);
2794                         break;
2795                 case OP_CEQ:
2796                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
2797                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
2798                         break;
2799                 case OP_CLT:
2800                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2801                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LT);
2802                         break;
2803                 case OP_CLT_UN:
2804                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2805                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LO);
2806                         break;
2807                 case OP_CGT:
2808                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2809                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_GT);
2810                         break;
2811                 case OP_CGT_UN:
2812                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2813                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_HI);
2814                         break;
2815                 case OP_COND_EXC_EQ:
2816                 case OP_COND_EXC_NE_UN:
2817                 case OP_COND_EXC_LT:
2818                 case OP_COND_EXC_LT_UN:
2819                 case OP_COND_EXC_GT:
2820                 case OP_COND_EXC_GT_UN:
2821                 case OP_COND_EXC_GE:
2822                 case OP_COND_EXC_GE_UN:
2823                 case OP_COND_EXC_LE:
2824                 case OP_COND_EXC_LE_UN:
2825                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2826                         break;
2827                 case OP_COND_EXC_C:
2828                 case OP_COND_EXC_OV:
2829                 case OP_COND_EXC_NC:
2830                 case OP_COND_EXC_NO:
2831                         g_assert_not_reached ();
2832                         break;
2833                 case OP_IBEQ:
2834                 case OP_IBNE_UN:
2835                 case OP_IBLT:
2836                 case OP_IBLT_UN:
2837                 case OP_IBGT:
2838                 case OP_IBGT_UN:
2839                 case OP_IBGE:
2840                 case OP_IBGE_UN:
2841                 case OP_IBLE:
2842                 case OP_IBLE_UN:
2843                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
2844                         break;
2845
2846                 /* floating point opcodes */
2847 #ifdef ARM_FPU_FPA
2848                 case OP_R8CONST:
2849                         if (cfg->compile_aot) {
2850                                 ARM_LDFD (code, ins->dreg, ARMREG_PC, 0);
2851                                 ARM_B (code, 1);
2852                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
2853                                 code += 4;
2854                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[1];
2855                                 code += 4;
2856                         } else {
2857                                 /* FIXME: we can optimize the imm load by dealing with part of 
2858                                  * the displacement in LDFD (aligning to 512).
2859                                  */
2860                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2861                                 ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
2862                         }
2863                         break;
2864                 case OP_R4CONST:
2865                         if (cfg->compile_aot) {
2866                                 ARM_LDFS (code, ins->dreg, ARMREG_PC, 0);
2867                                 ARM_B (code, 0);
2868                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
2869                                 code += 4;
2870                         } else {
2871                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2872                                 ARM_LDFS (code, ins->dreg, ARMREG_LR, 0);
2873                         }
2874                         break;
2875                 case OP_STORER8_MEMBASE_REG:
2876                         /* This is generated by the local regalloc pass which runs after the lowering pass */
2877                         if (!arm_is_fpimm8 (ins->inst_offset)) {
2878                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
2879                                 ARM_STFD (code, ins->sreg1, ARMREG_LR, 0);
2880                         } else {
2881                                 ARM_STFD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2882                         }
2883                         break;
2884                 case OP_LOADR8_MEMBASE:
2885                         /* This is generated by the local regalloc pass which runs after the lowering pass */
2886                         if (!arm_is_fpimm8 (ins->inst_offset)) {
2887                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
2888                                 ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
2889                         } else {
2890                                 ARM_LDFD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2891                         }
2892                         break;
2893                 case OP_STORER4_MEMBASE_REG:
2894                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2895                         ARM_STFS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2896                         break;
2897                 case OP_LOADR4_MEMBASE:
2898                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2899                         ARM_LDFS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2900                         break;
2901                 case OP_ICONV_TO_R_UN: {
2902                         int tmpreg;
2903                         tmpreg = ins->dreg == 0? 1: 0;
2904                         ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
2905                         ARM_FLTD (code, ins->dreg, ins->sreg1);
2906                         ARM_B_COND (code, ARMCOND_GE, 8);
2907                         /* save the temp register */
2908                         ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
2909                         ARM_STFD (code, tmpreg, ARMREG_SP, 0);
2910                         ARM_LDFD (code, tmpreg, ARMREG_PC, 12);
2911                         ARM_FPA_ADFD (code, ins->dreg, ins->dreg, tmpreg);
2912                         ARM_LDFD (code, tmpreg, ARMREG_SP, 0);
2913                         ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
2914                         /* skip the constant pool */
2915                         ARM_B (code, 8);
2916                         code += 4;
2917                         *(int*)code = 0x41f00000;
2918                         code += 4;
2919                         *(int*)code = 0;
2920                         code += 4;
2921                         /* FIXME: adjust:
2922                          * ldfltd  ftemp, [pc, #8] 0x41f00000 0x00000000
2923                          * adfltd  fdest, fdest, ftemp
2924                          */
2925                         break;
2926                 }
2927                 case OP_ICONV_TO_R4:
2928                         ARM_FLTS (code, ins->dreg, ins->sreg1);
2929                         break;
2930                 case OP_ICONV_TO_R8:
2931                         ARM_FLTD (code, ins->dreg, ins->sreg1);
2932                         break;
2933 #elif defined(ARM_FPU_VFP)
2934                 case OP_R8CONST:
2935                         if (cfg->compile_aot) {
2936                                 ARM_FLDD (code, ins->dreg, ARMREG_PC, 0);
2937                                 ARM_B (code, 1);
2938                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
2939                                 code += 4;
2940                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[1];
2941                                 code += 4;
2942                         } else {
2943                                 /* FIXME: we can optimize the imm load by dealing with part of 
2944                                  * the displacement in LDFD (aligning to 512).
2945                                  */
2946                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2947                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
2948                         }
2949                         break;
2950                 case OP_R4CONST:
2951                         if (cfg->compile_aot) {
2952                                 ARM_FLDS (code, ins->dreg, ARMREG_PC, 0);
2953                                 ARM_B (code, 0);
2954                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
2955                                 code += 4;
2956                                 ARM_CVTS (code, ins->dreg, ins->dreg);
2957                         } else {
2958                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2959                                 ARM_FLDS (code, ins->dreg, ARMREG_LR, 0);
2960                                 ARM_CVTS (code, ins->dreg, ins->dreg);
2961                         }
2962                         break;
2963                 case OP_STORER8_MEMBASE_REG:
2964                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2965                         ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2966                         break;
2967                 case OP_LOADR8_MEMBASE:
2968                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2969                         ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2970                         break;
2971                 case OP_STORER4_MEMBASE_REG:
2972                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2973                         ARM_FSTS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2974                         break;
2975                 case OP_LOADR4_MEMBASE:
2976                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2977                         ARM_FLDS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2978                         break;
2979                 case OP_ICONV_TO_R_UN: {
2980                         g_assert_not_reached ();
2981                         break;
2982                 }
2983                 case OP_ICONV_TO_R4:
2984                         g_assert_not_reached ();
2985                         //ARM_FLTS (code, ins->dreg, ins->sreg1);
2986                         break;
2987                 case OP_ICONV_TO_R8:
2988                         g_assert_not_reached ();
2989                         //ARM_FLTD (code, ins->dreg, ins->sreg1);
2990                         break;
2991 #endif
2992                 case OP_FCONV_TO_I1:
2993                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2994                         break;
2995                 case OP_FCONV_TO_U1:
2996                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2997                         break;
2998                 case OP_FCONV_TO_I2:
2999                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
3000                         break;
3001                 case OP_FCONV_TO_U2:
3002                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
3003                         break;
3004                 case OP_FCONV_TO_I4:
3005                 case OP_FCONV_TO_I:
3006                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
3007                         break;
3008                 case OP_FCONV_TO_U4:
3009                 case OP_FCONV_TO_U:
3010                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
3011                         break;
3012                 case OP_FCONV_TO_I8:
3013                 case OP_FCONV_TO_U8:
3014                         g_assert_not_reached ();
3015                         /* Implemented as helper calls */
3016                         break;
3017                 case OP_LCONV_TO_R_UN:
3018                         g_assert_not_reached ();
3019                         /* Implemented as helper calls */
3020                         break;
3021                 case OP_LCONV_TO_OVF_I: {
3022 #if ARM_PORT
3023                         guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3024                         // Check if its negative
3025                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3026                         negative_branch = code;
3027                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3028                         // Its positive msword == 0
3029                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3030                         msword_positive_branch = code;
3031                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3032
3033                         ovf_ex_target = code;
3034                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3035                         // Negative
3036                         ppc_patch (negative_branch, code);
3037                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3038                         msword_negative_branch = code;
3039                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3040                         ppc_patch (msword_negative_branch, ovf_ex_target);
3041                         
3042                         ppc_patch (msword_positive_branch, code);
3043                         if (ins->dreg != ins->sreg1)
3044                                 ppc_mr (code, ins->dreg, ins->sreg1);
3045 #endif
3046                         if (ins->dreg != ins->sreg1)
3047                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
3048                         break;
3049                 }
3050 #ifdef ARM_FPU_FPA
3051                 case OP_FADD:
3052                         ARM_FPA_ADFD (code, ins->dreg, ins->sreg1, ins->sreg2);
3053                         break;
3054                 case OP_FSUB:
3055                         ARM_FPA_SUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
3056                         break;          
3057                 case OP_FMUL:
3058                         ARM_FPA_MUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
3059                         break;          
3060                 case OP_FDIV:
3061                         ARM_FPA_DVFD (code, ins->dreg, ins->sreg1, ins->sreg2);
3062                         break;          
3063                 case OP_FNEG:
3064                         ARM_MNFD (code, ins->dreg, ins->sreg1);
3065                         break;
3066 #elif defined(ARM_FPU_VFP)
3067                 case OP_FADD:
3068                         ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2);
3069                         break;
3070                 case OP_FSUB:
3071                         ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2);
3072                         break;          
3073                 case OP_FMUL:
3074                         ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2);
3075                         break;          
3076                 case OP_FDIV:
3077                         ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2);
3078                         break;          
3079                 case OP_FNEG:
3080                         ARM_NEGD (code, ins->dreg, ins->sreg1);
3081                         break;
3082 #endif
3083                 case OP_FREM:
3084                         /* emulated */
3085                         g_assert_not_reached ();
3086                         break;
3087                 case OP_FCOMPARE:
3088                         /* each fp compare op needs to do its own */
3089                         g_assert_not_reached ();
3090                         //ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3091                         break;
3092                 case OP_FCEQ:
3093 #ifdef ARM_FPU_FPA
3094                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3095 #elif defined(ARM_FPU_VFP)
3096                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3097 #endif
3098                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
3099                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
3100                         break;
3101                 case OP_FCLT:
3102 #ifdef ARM_FPU_FPA
3103                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3104 #elif defined(ARM_FPU_VFP)
3105                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3106 #endif
3107                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3108                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
3109                         break;
3110                 case OP_FCLT_UN:
3111 #ifdef ARM_FPU_FPA
3112                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3113 #elif defined(ARM_FPU_VFP)
3114                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3115 #endif
3116                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3117                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
3118                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
3119                         break;
3120                 case OP_FCGT:
3121                         /* swapped */
3122 #ifdef ARM_FPU_FPA
3123                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3124 #elif defined(ARM_FPU_VFP)
3125                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3126 #endif
3127                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3128                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
3129                         break;
3130                 case OP_FCGT_UN:
3131                         /* swapped */
3132 #ifdef ARM_FPU_FPA
3133                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3134 #elif defined(ARM_FPU_VFP)
3135                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3136 #endif
3137                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3138                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
3139                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
3140                         break;
3141                 /* ARM FPA flags table:
3142                  * N        Less than               ARMCOND_MI
3143                  * Z        Equal                   ARMCOND_EQ
3144                  * C        Greater Than or Equal   ARMCOND_CS
3145                  * V        Unordered               ARMCOND_VS
3146                  */
3147                 case OP_FBEQ:
3148 #ifdef ARM_FPU_FPA
3149                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3150 #elif defined(ARM_FPU_VFP)
3151                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3152 #endif
3153                         EMIT_COND_BRANCH (ins, OP_IBEQ - OP_IBEQ);
3154                         break;
3155                 case OP_FBNE_UN:
3156 #ifdef ARM_FPU_FPA
3157                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3158 #elif defined(ARM_FPU_VFP)
3159                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3160 #endif
3161                         EMIT_COND_BRANCH (ins, OP_IBNE_UN - OP_IBEQ);
3162                         break;
3163                 case OP_FBLT:
3164 #ifdef ARM_FPU_FPA
3165                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3166 #elif defined(ARM_FPU_VFP)
3167                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3168 #endif
3169                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
3170                         break;
3171                 case OP_FBLT_UN:
3172 #ifdef ARM_FPU_FPA
3173                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3174 #elif defined(ARM_FPU_VFP)
3175                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3176 #endif
3177                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
3178                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
3179                         break;
3180                 case OP_FBGT:
3181 #ifdef ARM_FPU_FPA
3182                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3183 #elif defined(ARM_FPU_VFP)
3184                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3185 #endif
3186                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
3187                         break;
3188                 case OP_FBGT_UN:
3189 #ifdef ARM_FPU_FPA
3190                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3191 #elif defined(ARM_FPU_VFP)
3192                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3193 #endif
3194                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
3195                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
3196                         break;
3197                 case OP_FBGE:
3198 #ifdef ARM_FPU_FPA
3199                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3200 #elif defined(ARM_FPU_VFP)
3201                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3202 #endif
3203                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
3204                         break;
3205                 case OP_FBGE_UN:
3206 #ifdef ARM_FPU_FPA
3207                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3208 #elif defined(ARM_FPU_VFP)
3209                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3210 #endif
3211                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
3212                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
3213                         break;
3214                 case OP_FBLE:
3215 #ifdef ARM_FPU_FPA
3216                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3217 #elif defined(ARM_FPU_VFP)
3218                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3219 #endif
3220                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); /* swapped */
3221                         break;
3222                 case OP_FBLE_UN:
3223 #ifdef ARM_FPU_FPA
3224                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3225 #elif defined(ARM_FPU_VFP)
3226                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3227 #endif
3228                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
3229                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE); /* swapped */
3230                         break;
3231                 case OP_CKFINITE: {
3232 #ifdef ARM_FPU_FPA
3233                         if (ins->dreg != ins->sreg1)
3234                                 ARM_MVFD (code, ins->dreg, ins->sreg1);
3235 #else
3236                         g_assert_not_reached ();
3237 #endif
3238                         break;
3239                 }
3240                 default:
3241                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3242                         g_assert_not_reached ();
3243                 }
3244
3245                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3246                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3247                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3248                         g_assert_not_reached ();
3249                 }
3250                
3251                 cpos += max_len;
3252
3253                 last_offset = offset;
3254         }
3255
3256         cfg->code_len = code - cfg->native_code;
3257 }
3258
3259 void
3260 mono_arch_register_lowlevel_calls (void)
3261 {
3262 }
3263
3264 #define patch_lis_ori(ip,val) do {\
3265                 guint16 *__lis_ori = (guint16*)(ip);    \
3266                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
3267                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
3268         } while (0)
3269
3270 void
3271 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3272 {
3273         MonoJumpInfo *patch_info;
3274         gboolean compile_aot = !run_cctors;
3275
3276         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3277                 unsigned char *ip = patch_info->ip.i + code;
3278                 const unsigned char *target;
3279
3280                 if (patch_info->type == MONO_PATCH_INFO_SWITCH && !compile_aot) {
3281                         gpointer *jt = (gpointer*)(ip + 8);
3282                         int i;
3283                         /* jt is the inlined jump table, 2 instructions after ip
3284                          * In the normal case we store the absolute addresses,
3285                          * otherwise the displacements.
3286                          */
3287                         for (i = 0; i < patch_info->data.table->table_size; i++)
3288                                 jt [i] = code + (int)patch_info->data.table->table [i];
3289                         continue;
3290                 }
3291                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3292
3293                 if (compile_aot) {
3294                         switch (patch_info->type) {
3295                         case MONO_PATCH_INFO_BB:
3296                         case MONO_PATCH_INFO_LABEL:
3297                                 break;
3298                         default:
3299                                 /* No need to patch these */
3300                                 continue;
3301                         }
3302                 }
3303
3304                 switch (patch_info->type) {
3305                 case MONO_PATCH_INFO_IP:
3306                         g_assert_not_reached ();
3307                         patch_lis_ori (ip, ip);
3308                         continue;
3309                 case MONO_PATCH_INFO_METHOD_REL:
3310                         g_assert_not_reached ();
3311                         *((gpointer *)(ip)) = code + patch_info->data.offset;
3312                         continue;
3313                 case MONO_PATCH_INFO_METHODCONST:
3314                 case MONO_PATCH_INFO_CLASS:
3315                 case MONO_PATCH_INFO_IMAGE:
3316                 case MONO_PATCH_INFO_FIELD:
3317                 case MONO_PATCH_INFO_VTABLE:
3318                 case MONO_PATCH_INFO_IID:
3319                 case MONO_PATCH_INFO_SFLDA:
3320                 case MONO_PATCH_INFO_LDSTR:
3321                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3322                 case MONO_PATCH_INFO_LDTOKEN:
3323                         g_assert_not_reached ();
3324                         /* from OP_AOTCONST : lis + ori */
3325                         patch_lis_ori (ip, target);
3326                         continue;
3327                 case MONO_PATCH_INFO_R4:
3328                 case MONO_PATCH_INFO_R8:
3329                         g_assert_not_reached ();
3330                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3331                         continue;
3332                 case MONO_PATCH_INFO_EXC_NAME:
3333                         g_assert_not_reached ();
3334                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3335                         continue;
3336                 case MONO_PATCH_INFO_NONE:
3337                 case MONO_PATCH_INFO_BB_OVF:
3338                 case MONO_PATCH_INFO_EXC_OVF:
3339                         /* everything is dealt with at epilog output time */
3340                         continue;
3341                 default:
3342                         break;
3343                 }
3344                 arm_patch (ip, target);
3345         }
3346 }
3347
3348 /*
3349  * Stack frame layout:
3350  * 
3351  *   ------------------- fp
3352  *      MonoLMF structure or saved registers
3353  *   -------------------
3354  *      locals
3355  *   -------------------
3356  *      spilled regs
3357  *   -------------------
3358  *      optional 8 bytes for tracing
3359  *   -------------------
3360  *      param area             size is cfg->param_area
3361  *   ------------------- sp
3362  */
3363 guint8 *
3364 mono_arch_emit_prolog (MonoCompile *cfg)
3365 {
3366         MonoMethod *method = cfg->method;
3367         MonoBasicBlock *bb;
3368         MonoMethodSignature *sig;
3369         MonoInst *inst;
3370         int alloc_size, pos, max_offset, i, rot_amount;
3371         guint8 *code;
3372         CallInfo *cinfo;
3373         int tracing = 0;
3374         int lmf_offset = 0;
3375         int prev_sp_offset;
3376
3377         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3378                 tracing = 1;
3379
3380         sig = mono_method_signature (method);
3381         cfg->code_size = 256 + sig->param_count * 20;
3382         code = cfg->native_code = g_malloc (cfg->code_size);
3383
3384         ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
3385
3386         alloc_size = cfg->stack_offset;
3387         pos = 0;
3388
3389         if (!method->save_lmf) {
3390                 ARM_PUSH (code, (cfg->used_int_regs | (1 << ARMREG_IP) | (1 << ARMREG_LR)));
3391                 prev_sp_offset = 8; /* ip and lr */
3392                 for (i = 0; i < 16; ++i) {
3393                         if (cfg->used_int_regs & (1 << i))
3394                                 prev_sp_offset += 4;
3395                 }
3396         } else {
3397                 ARM_PUSH (code, 0x5ff0);
3398                 prev_sp_offset = 4 * 10; /* all but r0-r3, sp and pc */
3399                 pos += sizeof (MonoLMF) - prev_sp_offset;
3400                 lmf_offset = pos;
3401         }
3402         alloc_size += pos;
3403         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
3404         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
3405                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3406                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
3407         }
3408
3409         /* the stack used in the pushed regs */
3410         if (prev_sp_offset & 4)
3411                 alloc_size += 4;
3412         cfg->stack_usage = alloc_size;
3413         if (alloc_size) {
3414                 if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
3415                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
3416                 } else {
3417                         code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
3418                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
3419                 }
3420         }
3421         if (cfg->frame_reg != ARMREG_SP)
3422                 ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
3423         //g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
3424         prev_sp_offset += alloc_size;
3425
3426         /* compute max_offset in order to use short forward jumps
3427          * we could skip do it on arm because the immediate displacement
3428          * for jumps is large enough, it may be useful later for constant pools
3429          */
3430         max_offset = 0;
3431         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3432                 MonoInst *ins;
3433                 bb->max_offset = max_offset;
3434
3435                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3436                         max_offset += 6; 
3437
3438                 MONO_BB_FOR_EACH_INS (bb, ins)
3439                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3440         }
3441
3442         /* load arguments allocated to register from the stack */
3443         pos = 0;
3444
3445         cinfo = calculate_sizes (sig, sig->pinvoke);
3446
3447         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3448                 ArgInfo *ainfo = &cinfo->ret;
3449                 inst = cfg->vret_addr;
3450                 g_assert (arm_is_imm12 (inst->inst_offset));
3451                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3452         }
3453         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3454                 ArgInfo *ainfo = cinfo->args + i;
3455                 inst = cfg->args [pos];
3456                 
3457                 if (cfg->verbose_level > 2)
3458                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3459                 if (inst->opcode == OP_REGVAR) {
3460                         if (ainfo->regtype == RegTypeGeneral)
3461                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
3462                         else if (ainfo->regtype == RegTypeFP) {
3463                                 g_assert_not_reached ();
3464                         } else if (ainfo->regtype == RegTypeBase) {
3465                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
3466                                         ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3467                                 } else {
3468                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3469                                         ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
3470                                 }
3471                         } else
3472                                 g_assert_not_reached ();
3473
3474                         if (cfg->verbose_level > 2)
3475                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3476                 } else {
3477                         /* the argument should be put on the stack: FIXME handle size != word  */
3478                         if (ainfo->regtype == RegTypeGeneral) {
3479                                 switch (ainfo->size) {
3480                                 case 1:
3481                                         if (arm_is_imm12 (inst->inst_offset))
3482                                                 ARM_STRB_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3483                                         else {
3484                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3485                                                 ARM_STRB_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
3486                                         }
3487                                         break;
3488                                 case 2:
3489                                         if (arm_is_imm8 (inst->inst_offset)) {
3490                                                 ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3491                                         } else {
3492                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3493                                                 ARM_STRH_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
3494                                         }
3495                                         break;
3496                                 case 8:
3497                                         g_assert (arm_is_imm12 (inst->inst_offset));
3498                                         ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3499                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
3500                                         ARM_STR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3501                                         break;
3502                                 default:
3503                                         if (arm_is_imm12 (inst->inst_offset)) {
3504                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3505                                         } else {
3506                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3507                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
3508                                         }
3509                                         break;
3510                                 }
3511                         } else if (ainfo->regtype == RegTypeBaseGen) {
3512                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
3513                                 g_assert (arm_is_imm12 (inst->inst_offset));
3514                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3515                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
3516                                 ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset);
3517                         } else if (ainfo->regtype == RegTypeBase) {
3518                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
3519                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3520                                 } else {
3521                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
3522                                         ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
3523                                 }
3524
3525                                 switch (ainfo->size) {
3526                                 case 1:
3527                                         if (arm_is_imm8 (inst->inst_offset)) {
3528                                                 ARM_STRB_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3529                                         } else {
3530                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3531                                                 ARM_STRB_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3532                                         }
3533                                         break;
3534                                 case 2:
3535                                         if (arm_is_imm8 (inst->inst_offset)) {
3536                                                 ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3537                                         } else {
3538                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3539                                                 ARM_STRH_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3540                                         }
3541                                         break;
3542                                 case 8:
3543                                         if (arm_is_imm12 (inst->inst_offset)) {
3544                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3545                                         } else {
3546                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3547                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3548                                         }
3549                                         if (arm_is_imm12 (prev_sp_offset + ainfo->offset + 4)) {
3550                                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset + 4));
3551                                         } else {
3552                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset + 4);
3553                                                 ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
3554                                         }
3555                                         if (arm_is_imm12 (inst->inst_offset + 4)) {
3556                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
3557                                         } else {
3558                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
3559                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3560                                         }
3561                                         break;
3562                                 default:
3563                                         if (arm_is_imm12 (inst->inst_offset)) {
3564                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3565                                         } else {
3566                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3567                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3568                                         }
3569                                         break;
3570                                 }
3571                         } else if (ainfo->regtype == RegTypeFP) {
3572                                 g_assert_not_reached ();
3573                         } else if (ainfo->regtype == RegTypeStructByVal) {
3574                                 int doffset = inst->inst_offset;
3575                                 int soffset = 0;
3576                                 int cur_reg;
3577                                 int size = 0;
3578                                 if (mono_class_from_mono_type (inst->inst_vtype))
3579                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3580                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3581                                         if (arm_is_imm12 (doffset)) {
3582                                                 ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
3583                                         } else {
3584                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
3585                                                 ARM_STR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
3586                                         }
3587                                         soffset += sizeof (gpointer);
3588                                         doffset += sizeof (gpointer);
3589                                 }
3590                                 if (ainfo->vtsize) {
3591                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3592                                         //g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
3593                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
3594                                 }
3595                         } else if (ainfo->regtype == RegTypeStructByAddr) {
3596                                 g_assert_not_reached ();
3597                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3598                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3599                         } else
3600                                 g_assert_not_reached ();
3601                 }
3602                 pos++;
3603         }
3604
3605         if (method->save_lmf) {
3606
3607                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3608                              (gpointer)"mono_get_lmf_addr");
3609                 code = emit_call_seq (cfg, code);
3610                 /* we build the MonoLMF structure on the stack - see mini-arm.h */
3611                 /* lmf_offset is the offset from the previous stack pointer,
3612                  * alloc_size is the total stack space allocated, so the offset
3613                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3614                  * The pointer to the struct is put in r1 (new_lmf).
3615                  * r2 is used as scratch
3616                  * The callee-saved registers are already in the MonoLMF structure
3617                  */
3618                 code = emit_big_add (code, ARMREG_R1, ARMREG_SP, alloc_size - lmf_offset);
3619                 /* r0 is the result from mono_get_lmf_addr () */
3620                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
3621                 /* new_lmf->previous_lmf = *lmf_addr */
3622                 ARM_LDR_IMM (code, ARMREG_R2, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3623                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3624                 /* *(lmf_addr) = r1 */
3625                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3626                 /* Skip method (only needed for trampoline LMF frames) */
3627                 ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
3628                 /* save the current IP */
3629                 ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
3630                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
3631         }
3632
3633         if (tracing)
3634                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3635
3636         cfg->code_len = code - cfg->native_code;
3637         g_assert (cfg->code_len < cfg->code_size);
3638         g_free (cinfo);
3639
3640         return code;
3641 }
3642
3643 void
3644 mono_arch_emit_epilog (MonoCompile *cfg)
3645 {
3646         MonoMethod *method = cfg->method;
3647         int pos, i, rot_amount;
3648         int max_epilog_size = 16 + 20*4;
3649         guint8 *code;
3650
3651         if (cfg->method->save_lmf)
3652                 max_epilog_size += 128;
3653         
3654         if (mono_jit_trace_calls != NULL)
3655                 max_epilog_size += 50;
3656
3657         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3658                 max_epilog_size += 50;
3659
3660         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3661                 cfg->code_size *= 2;
3662                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3663                 mono_jit_stats.code_reallocs++;
3664         }
3665
3666         /*
3667          * Keep in sync with OP_JMP
3668          */
3669         code = cfg->native_code + cfg->code_len;
3670
3671         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3672                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3673         }
3674         pos = 0;
3675
3676         if (method->save_lmf) {
3677                 int lmf_offset;
3678                 /* all but r0-r3, sp and pc */
3679                 pos += sizeof (MonoLMF) - (4 * 10);
3680                 lmf_offset = pos;
3681                 /* r2 contains the pointer to the current LMF */
3682                 code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3683                 /* ip = previous_lmf */
3684                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3685                 /* lr = lmf_addr */
3686                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
3687                 /* *(lmf_addr) = previous_lmf */
3688                 ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3689                 /* FIXME: speedup: there is no actual need to restore the registers if
3690                  * we didn't actually change them (idea from Zoltan).
3691                  */
3692                 /* restore iregs */
3693                 /* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
3694                 ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_R2, (sizeof (MonoLMF) - 10 * sizeof (gulong)));
3695                 ARM_POP_NWB (code, 0xaff0); /* restore ip to sp and lr to pc */
3696         } else {
3697                 if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
3698                         ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
3699                 } else {
3700                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage);
3701                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
3702                 }
3703                 /* FIXME: add v4 thumb interworking support */
3704                 ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP) | (1 << ARMREG_PC)));
3705         }
3706
3707         cfg->code_len = code - cfg->native_code;
3708
3709         g_assert (cfg->code_len < cfg->code_size);
3710
3711 }
3712
3713 /* remove once throw_exception_by_name is eliminated */
3714 static int
3715 exception_id_by_name (const char *name)
3716 {
3717         if (strcmp (name, "IndexOutOfRangeException") == 0)
3718                 return MONO_EXC_INDEX_OUT_OF_RANGE;
3719         if (strcmp (name, "OverflowException") == 0)
3720                 return MONO_EXC_OVERFLOW;
3721         if (strcmp (name, "ArithmeticException") == 0)
3722                 return MONO_EXC_ARITHMETIC;
3723         if (strcmp (name, "DivideByZeroException") == 0)
3724                 return MONO_EXC_DIVIDE_BY_ZERO;
3725         if (strcmp (name, "InvalidCastException") == 0)
3726                 return MONO_EXC_INVALID_CAST;
3727         if (strcmp (name, "NullReferenceException") == 0)
3728                 return MONO_EXC_NULL_REF;
3729         if (strcmp (name, "ArrayTypeMismatchException") == 0)
3730                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3731         g_error ("Unknown intrinsic exception %s\n", name);
3732         return -1;
3733 }
3734
3735 void
3736 mono_arch_emit_exceptions (MonoCompile *cfg)
3737 {
3738         MonoJumpInfo *patch_info;
3739         int i;
3740         guint8 *code;
3741         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3742         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3743         int max_epilog_size = 50;
3744
3745         /* count the number of exception infos */
3746      
3747         /* 
3748          * make sure we have enough space for exceptions
3749          */
3750         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3751                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3752                         i = exception_id_by_name (patch_info->data.target);
3753                         if (!exc_throw_found [i]) {
3754                                 max_epilog_size += 32;
3755                                 exc_throw_found [i] = TRUE;
3756                         }
3757                 }
3758         }
3759
3760         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3761                 cfg->code_size *= 2;
3762                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3763                 mono_jit_stats.code_reallocs++;
3764         }
3765
3766         code = cfg->native_code + cfg->code_len;
3767
3768         /* add code to raise exceptions */
3769         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3770                 switch (patch_info->type) {
3771                 case MONO_PATCH_INFO_EXC: {
3772                         MonoClass *exc_class;
3773                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3774
3775                         i = exception_id_by_name (patch_info->data.target);
3776                         if (exc_throw_pos [i]) {
3777                                 arm_patch (ip, exc_throw_pos [i]);
3778                                 patch_info->type = MONO_PATCH_INFO_NONE;
3779                                 break;
3780                         } else {
3781                                 exc_throw_pos [i] = code;
3782                         }
3783                         arm_patch (ip, code);
3784
3785                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
3786                         g_assert (exc_class);
3787
3788                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR);
3789                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
3790                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3791                         patch_info->data.name = "mono_arch_throw_corlib_exception";
3792                         patch_info->ip.i = code - cfg->native_code;
3793                         ARM_BL (code, 0);
3794                         *(guint32*)(gpointer)code = exc_class->type_token;
3795                         code += 4;
3796                         break;
3797                 }
3798                 default:
3799                         /* do nothing */
3800                         break;
3801                 }
3802         }
3803
3804         cfg->code_len = code - cfg->native_code;
3805
3806         g_assert (cfg->code_len < cfg->code_size);
3807
3808 }
3809
3810 void
3811 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3812 {
3813 }
3814
3815 void
3816 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3817 {
3818 }
3819
3820 void
3821 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3822 {
3823         
3824         int this_dreg = ARMREG_R0;
3825         
3826         if (vt_reg != -1)
3827                 this_dreg = ARMREG_R1;
3828
3829         /* add the this argument */
3830         if (this_reg != -1) {
3831                 MonoInst *this;
3832                 MONO_INST_NEW (cfg, this, OP_MOVE);
3833                 this->type = this_type;
3834                 this->sreg1 = this_reg;
3835                 this->dreg = mono_regstate_next_int (cfg->rs);
3836                 mono_bblock_add_inst (cfg->cbb, this);
3837                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3838         }
3839
3840         if (vt_reg != -1) {
3841                 MonoInst *vtarg;
3842                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
3843                 vtarg->type = STACK_MP;
3844                 vtarg->sreg1 = vt_reg;
3845                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3846                 mono_bblock_add_inst (cfg->cbb, vtarg);
3847                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ARMREG_R0, FALSE);
3848         }
3849 }
3850
3851 MonoInst*
3852 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3853 {
3854         return NULL;
3855 }
3856
3857 gboolean
3858 mono_arch_print_tree (MonoInst *tree, int arity)
3859 {
3860         return 0;
3861 }
3862
3863 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3864 {
3865         return NULL;
3866 }
3867
3868 MonoInst* 
3869 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3870 {
3871         return NULL;
3872 }
3873
3874 guint32
3875 mono_arch_get_patch_offset (guint8 *code)
3876 {
3877         /* OP_AOTCONST */
3878         return 8;
3879 }
3880
3881 void
3882 mono_arch_flush_register_windows (void)
3883 {
3884 }
3885
3886 void
3887 mono_arch_fixup_jinfo (MonoCompile *cfg)
3888 {
3889         /* max encoded stack usage is 64KB * 4 */
3890         g_assert ((cfg->stack_usage & ~(0xffff << 2)) == 0);
3891         cfg->jit_info->used_regs |= cfg->stack_usage << 14;
3892 }
3893
3894 #ifdef MONO_ARCH_HAVE_IMT
3895
3896 void
3897 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
3898 {
3899         if (cfg->compile_aot) {
3900                 int method_reg = mono_regstate_next_int (cfg->rs);
3901                 MonoInst *ins;
3902
3903                 MONO_INST_NEW (cfg, ins, OP_AOTCONST);
3904                 ins->dreg = method_reg;
3905                 ins->inst_p0 = call->method;
3906                 ins->inst_c1 = MONO_PATCH_INFO_METHODCONST;
3907                 MONO_ADD_INS (cfg->cbb, ins);
3908
3909                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
3910         }
3911 }
3912
3913 MonoMethod*
3914 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
3915 {
3916         guint32 *code_ptr = (guint32*)code;
3917         code_ptr -= 2;
3918         /* The IMT value is stored in the code stream right after the LDC instruction. */
3919         if (!IS_LDR_PC (code_ptr [0])) {
3920                 g_warning ("invalid code stream, instruction before IMT value is not a LDC in %s() (code %p value 0: 0x%x -1: 0x%x -2: 0x%x)", __FUNCTION__, code, code_ptr [2], code_ptr [1], code_ptr [0]);
3921                 g_assert (IS_LDR_PC (code_ptr [0]));
3922         }
3923         if (code_ptr [1] == 0)
3924                 /* This is AOTed code, the IMT method is in V5 */
3925                 return (MonoMethod*)regs [ARMREG_V5];
3926         else
3927                 return (MonoMethod*) code_ptr [1];
3928 }
3929
3930 MonoObject*
3931 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
3932 {
3933         return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
3934 }
3935
3936
3937 #define ENABLE_WRONG_METHOD_CHECK 0
3938 #define BASE_SIZE (6 * 4)
3939 #define BSEARCH_ENTRY_SIZE (4 * 4)
3940 #define CMP_SIZE (3 * 4)
3941 #define BRANCH_SIZE (1 * 4)
3942 #define CALL_SIZE (2 * 4)
3943 #define WMC_SIZE (5 * 4)
3944 #define DISTANCE(A, B) (((gint32)(B)) - ((gint32)(A)))
3945
3946 static arminstr_t *
3947 arm_emit_value_and_patch_ldr (arminstr_t *code, arminstr_t *target, guint32 value)
3948 {
3949         guint32 delta = DISTANCE (target, code);
3950         delta -= 8;
3951         g_assert (delta >= 0 && delta <= 0xFFF);
3952         *target = *target | delta;
3953         *code = value;
3954         return code + 1;
3955 }
3956
3957 gpointer
3958 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
3959 {
3960         int size, i, extra_space = 0;
3961         arminstr_t *code, *start, *vtable_target = NULL;
3962         size = BASE_SIZE;
3963
3964         for (i = 0; i < count; ++i) {
3965                 MonoIMTCheckItem *item = imt_entries [i];
3966                 if (item->is_equals) {
3967                         g_assert (arm_is_imm12 (DISTANCE (vtable, &vtable->vtable[item->vtable_slot])));
3968
3969                         if (item->check_target_idx) {
3970                                 if (!item->compare_done)
3971                                         item->chunk_size += CMP_SIZE;
3972                                 item->chunk_size += BRANCH_SIZE;
3973                         } else {
3974 #if ENABLE_WRONG_METHOD_CHECK
3975                                 item->chunk_size += WMC_SIZE;
3976 #endif
3977                         }
3978                         item->chunk_size += CALL_SIZE;
3979                 } else {
3980                         item->chunk_size += BSEARCH_ENTRY_SIZE;
3981                         imt_entries [item->check_target_idx]->compare_done = TRUE;
3982                 }
3983                 size += item->chunk_size;
3984         }
3985
3986         start = code = mono_code_manager_reserve (domain->code_mp, size);
3987
3988 #if DEBUG_IMT
3989         printf ("building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable);
3990         for (i = 0; i < count; ++i) {
3991                 MonoIMTCheckItem *item = imt_entries [i];
3992                 printf ("method %d (%p) %s vtable slot %p is_equals %d chunk size %d\n", i, item->method, item->method->name, &vtable->vtable [item->vtable_slot], item->is_equals, item->chunk_size);
3993         }
3994 #endif
3995
3996         ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
3997         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
3998         vtable_target = code;
3999         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
4000
4001         /* R0 == 0 means we are called from AOT code. In this case, V5 contains the IMT method */
4002         ARM_CMP_REG_IMM8 (code, ARMREG_R0, 0);
4003         ARM_MOV_REG_REG_COND (code, ARMREG_R0, ARMREG_V5, ARMCOND_EQ);
4004
4005         for (i = 0; i < count; ++i) {
4006                 MonoIMTCheckItem *item = imt_entries [i];
4007                 arminstr_t *imt_method = NULL;
4008                 item->code_target = (guint8*)code;
4009
4010                 if (item->is_equals) {
4011                         if (item->check_target_idx) {
4012                                 if (!item->compare_done) {
4013                                         imt_method = code;
4014                                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
4015                                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
4016                                 }
4017                                 item->jmp_code = (guint8*)code;
4018                                 ARM_B_COND (code, ARMCOND_NE, 0);
4019
4020                                 ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
4021                                 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, DISTANCE (vtable, &vtable->vtable[item->vtable_slot]));
4022                         } else {
4023                                 /*Enable the commented code to assert on wrong method*/
4024 #if ENABLE_WRONG_METHOD_CHECK
4025                                 imt_method = code;
4026                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
4027                                 ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
4028                                 ARM_B_COND (code, ARMCOND_NE, 1);
4029 #endif
4030                                 ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
4031                                 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, DISTANCE (vtable, &vtable->vtable[item->vtable_slot]));
4032
4033 #if ENABLE_WRONG_METHOD_CHECK
4034                                 ARM_DBRK (code);
4035 #endif
4036                         }
4037
4038                         if (imt_method)
4039                                 code = arm_emit_value_and_patch_ldr (code, imt_method, (guint32)item->method);
4040
4041                         /*must emit after unconditional branch*/
4042                         if (vtable_target) {
4043                                 code = arm_emit_value_and_patch_ldr (code, vtable_target, (guint32)vtable);
4044                                 item->chunk_size += 4;
4045                                 vtable_target = NULL;
4046                         }
4047
4048                         /*We reserve the space for bsearch IMT values after the first entry with an absolute jump*/
4049                         if (extra_space) {
4050                                 code += extra_space;
4051                                 extra_space = 0;
4052                         }
4053                 } else {
4054                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
4055                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
4056
4057                         item->jmp_code = (guint8*)code;
4058                         ARM_B_COND (code, ARMCOND_GE, 0);
4059                         ++extra_space;
4060                 }
4061         }
4062
4063         for (i = 0; i < count; ++i) {
4064                 MonoIMTCheckItem *item = imt_entries [i];
4065                 if (item->jmp_code) {
4066                         if (item->check_target_idx)
4067                                 arm_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4068                 }
4069                 if (i > 0 && item->is_equals) {
4070                         int j;
4071                         arminstr_t *space_start = (arminstr_t*)(item->code_target + item->chunk_size);
4072                         for (j = i - 1; j >= 0 && !imt_entries [j]->is_equals; --j) {
4073                                 space_start = arm_emit_value_and_patch_ldr (space_start, (arminstr_t*)imt_entries [j]->code_target, (guint32)imt_entries [j]->method);
4074                         }
4075                 }
4076         }
4077
4078 #if DEBUG_IMT
4079         {
4080                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
4081                 mono_disassemble_code (NULL, (guint8*)start, size, buff);
4082                 g_free (buff);
4083         }
4084 #endif
4085
4086         mono_arch_flush_icache ((guint8*)start, size);
4087         mono_stats.imt_thunks_size += code - start;
4088
4089         g_assert (DISTANCE (start, code) <= size);
4090         return start;
4091 }
4092
4093 #endif
4094
4095 gpointer
4096 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4097 {
4098         /* FIXME: implement */
4099         g_assert_not_reached ();
4100 }