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