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