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