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