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