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