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