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