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