2008-02-08 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 void
1282 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1283 {
1284 }
1285
1286 void
1287 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1288 {
1289         MonoInst *ins, *n;
1290
1291         MONO_INST_LIST_FOR_EACH_ENTRY_SAFE (ins, n, &bb->ins_list, node) {
1292                 MonoInst *last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1293
1294                 switch (ins->opcode) {
1295                 case OP_MUL_IMM: 
1296                         /* remove unnecessary multiplication with 1 */
1297                         if (ins->inst_imm == 1) {
1298                                 if (ins->dreg != ins->sreg1) {
1299                                         ins->opcode = OP_MOVE;
1300                                 } else {
1301                                         MONO_DEL_INS (ins);
1302                                         continue;
1303                                 }
1304                         } else {
1305                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1306                                 if (power2 > 0) {
1307                                         ins->opcode = OP_SHL_IMM;
1308                                         ins->inst_imm = power2;
1309                                 }
1310                         }
1311                         break;
1312                 case OP_LOAD_MEMBASE:
1313                 case OP_LOADI4_MEMBASE:
1314                         /* 
1315                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1316                          * OP_LOAD_MEMBASE offset(basereg), reg
1317                          */
1318                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1319                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1320                             ins->inst_basereg == last_ins->inst_destbasereg &&
1321                             ins->inst_offset == last_ins->inst_offset) {
1322                                 if (ins->dreg == last_ins->sreg1) {
1323                                         MONO_DEL_INS (ins);
1324                                         continue;
1325                                 } else {
1326                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1327                                         ins->opcode = OP_MOVE;
1328                                         ins->sreg1 = last_ins->sreg1;
1329                                 }
1330
1331                         /* 
1332                          * Note: reg1 must be different from the basereg in the second load
1333                          * OP_LOAD_MEMBASE offset(basereg), reg1
1334                          * OP_LOAD_MEMBASE offset(basereg), reg2
1335                          * -->
1336                          * OP_LOAD_MEMBASE offset(basereg), reg1
1337                          * OP_MOVE reg1, reg2
1338                          */
1339                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1340                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1341                               ins->inst_basereg != last_ins->dreg &&
1342                               ins->inst_basereg == last_ins->inst_basereg &&
1343                               ins->inst_offset == last_ins->inst_offset) {
1344
1345                                 if (ins->dreg == last_ins->dreg) {
1346                                         MONO_DEL_INS (ins);
1347                                         continue;
1348                                 } else {
1349                                         ins->opcode = OP_MOVE;
1350                                         ins->sreg1 = last_ins->dreg;
1351                                 }
1352
1353                                 //g_assert_not_reached ();
1354
1355 #if 0
1356                         /* 
1357                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1358                          * OP_LOAD_MEMBASE offset(basereg), reg
1359                          * -->
1360                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1361                          * OP_ICONST reg, imm
1362                          */
1363                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1364                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1365                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1366                                    ins->inst_offset == last_ins->inst_offset) {
1367                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1368                                 ins->opcode = OP_ICONST;
1369                                 ins->inst_c0 = last_ins->inst_imm;
1370                                 g_assert_not_reached (); // check this rule
1371 #endif
1372                         }
1373                         break;
1374                 case OP_LOADU1_MEMBASE:
1375                 case OP_LOADI1_MEMBASE:
1376                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1377                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1378                                         ins->inst_offset == last_ins->inst_offset) {
1379                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
1380                                 ins->sreg1 = last_ins->sreg1;                           
1381                         }
1382                         break;
1383                 case OP_LOADU2_MEMBASE:
1384                 case OP_LOADI2_MEMBASE:
1385                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1386                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1387                                         ins->inst_offset == last_ins->inst_offset) {
1388                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
1389                                 ins->sreg1 = last_ins->sreg1;                           
1390                         }
1391                         break;
1392                 case OP_MOVE:
1393                         ins->opcode = OP_MOVE;
1394                         /* 
1395                          * OP_MOVE reg, reg 
1396                          */
1397                         if (ins->dreg == ins->sreg1) {
1398                                 MONO_DEL_INS (ins);
1399                                 continue;
1400                         }
1401                         /* 
1402                          * OP_MOVE sreg, dreg 
1403                          * OP_MOVE dreg, sreg
1404                          */
1405                         if (last_ins && last_ins->opcode == OP_MOVE &&
1406                             ins->sreg1 == last_ins->dreg &&
1407                             ins->dreg == last_ins->sreg1) {
1408                                 MONO_DEL_INS (ins);
1409                                 continue;
1410                         }
1411                         break;
1412                 }
1413         }
1414 }
1415
1416 /* 
1417  * the branch_cc_table should maintain the order of these
1418  * opcodes.
1419 case CEE_BEQ:
1420 case CEE_BGE:
1421 case CEE_BGT:
1422 case CEE_BLE:
1423 case CEE_BLT:
1424 case CEE_BNE_UN:
1425 case CEE_BGE_UN:
1426 case CEE_BGT_UN:
1427 case CEE_BLE_UN:
1428 case CEE_BLT_UN:
1429  */
1430 static const guchar 
1431 branch_cc_table [] = {
1432         ARMCOND_EQ, 
1433         ARMCOND_GE, 
1434         ARMCOND_GT, 
1435         ARMCOND_LE,
1436         ARMCOND_LT, 
1437         
1438         ARMCOND_NE, 
1439         ARMCOND_HS, 
1440         ARMCOND_HI, 
1441         ARMCOND_LS,
1442         ARMCOND_LO
1443 };
1444
1445
1446 #define NEW_INS(cfg,ins,dest,op) do {                                   \
1447                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
1448                 (dest)->opcode = (op);  \
1449                 MONO_INST_LIST_ADD_TAIL (&(dest)->node, &(ins)->node); \
1450         } while (0)
1451
1452 static int
1453 map_to_reg_reg_op (int op)
1454 {
1455         switch (op) {
1456         case OP_ADD_IMM:
1457                 return OP_IADD;
1458         case OP_SUB_IMM:
1459                 return OP_ISUB;
1460         case OP_AND_IMM:
1461                 return OP_IAND;
1462         case OP_COMPARE_IMM:
1463                 return OP_COMPARE;
1464         case OP_ADDCC_IMM:
1465                 return OP_ADDCC;
1466         case OP_ADC_IMM:
1467                 return OP_ADC;
1468         case OP_SUBCC_IMM:
1469                 return OP_SUBCC;
1470         case OP_SBB_IMM:
1471                 return OP_SBB;
1472         case OP_OR_IMM:
1473                 return OP_IOR;
1474         case OP_XOR_IMM:
1475                 return OP_IXOR;
1476         case OP_LOAD_MEMBASE:
1477                 return OP_LOAD_MEMINDEX;
1478         case OP_LOADI4_MEMBASE:
1479                 return OP_LOADI4_MEMINDEX;
1480         case OP_LOADU4_MEMBASE:
1481                 return OP_LOADU4_MEMINDEX;
1482         case OP_LOADU1_MEMBASE:
1483                 return OP_LOADU1_MEMINDEX;
1484         case OP_LOADI2_MEMBASE:
1485                 return OP_LOADI2_MEMINDEX;
1486         case OP_LOADU2_MEMBASE:
1487                 return OP_LOADU2_MEMINDEX;
1488         case OP_LOADI1_MEMBASE:
1489                 return OP_LOADI1_MEMINDEX;
1490         case OP_STOREI1_MEMBASE_REG:
1491                 return OP_STOREI1_MEMINDEX;
1492         case OP_STOREI2_MEMBASE_REG:
1493                 return OP_STOREI2_MEMINDEX;
1494         case OP_STOREI4_MEMBASE_REG:
1495                 return OP_STOREI4_MEMINDEX;
1496         case OP_STORE_MEMBASE_REG:
1497                 return OP_STORE_MEMINDEX;
1498         case OP_STORER4_MEMBASE_REG:
1499                 return OP_STORER4_MEMINDEX;
1500         case OP_STORER8_MEMBASE_REG:
1501                 return OP_STORER8_MEMINDEX;
1502         case OP_STORE_MEMBASE_IMM:
1503                 return OP_STORE_MEMBASE_REG;
1504         case OP_STOREI1_MEMBASE_IMM:
1505                 return OP_STOREI1_MEMBASE_REG;
1506         case OP_STOREI2_MEMBASE_IMM:
1507                 return OP_STOREI2_MEMBASE_REG;
1508         case OP_STOREI4_MEMBASE_IMM:
1509                 return OP_STOREI4_MEMBASE_REG;
1510         }
1511         g_assert_not_reached ();
1512 }
1513
1514 /*
1515  * Remove from the instruction list the instructions that can't be
1516  * represented with very simple instructions with no register
1517  * requirements.
1518  */
1519 void
1520 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1521 {
1522         int rot_amount, imm8, low_imm;
1523         MonoInst *ins, *temp;
1524
1525         /* setup the virtual reg allocator */
1526         if (bb->max_vreg > cfg->rs->next_vreg)
1527                 cfg->rs->next_vreg = bb->max_vreg;
1528
1529         MONO_BB_FOR_EACH_INS (bb, ins) {
1530                 MonoInst *last_ins;
1531
1532 loop_start:
1533                 last_ins = mono_inst_list_prev (&ins->node, &bb->ins_list);
1534                 switch (ins->opcode) {
1535                 case OP_ADD_IMM:
1536                 case OP_SUB_IMM:
1537                 case OP_AND_IMM:
1538                 case OP_COMPARE_IMM:
1539                 case OP_ADDCC_IMM:
1540                 case OP_ADC_IMM:
1541                 case OP_SUBCC_IMM:
1542                 case OP_SBB_IMM:
1543                 case OP_OR_IMM:
1544                 case OP_XOR_IMM:
1545                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
1546                                 NEW_INS (cfg, ins, temp, OP_ICONST);
1547                                 temp->inst_c0 = ins->inst_imm;
1548                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1549                                 ins->sreg2 = temp->dreg;
1550                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1551                         }
1552                         break;
1553                 case OP_MUL_IMM:
1554                         if (ins->inst_imm == 1) {
1555                                 ins->opcode = OP_MOVE;
1556                                 break;
1557                         }
1558                         if (ins->inst_imm == 0) {
1559                                 ins->opcode = OP_ICONST;
1560                                 ins->inst_c0 = 0;
1561                                 break;
1562                         }
1563                         imm8 = mono_is_power_of_two (ins->inst_imm);
1564                         if (imm8 > 0) {
1565                                 ins->opcode = OP_SHL_IMM;
1566                                 ins->inst_imm = imm8;
1567                                 break;
1568                         }
1569                         NEW_INS (cfg, ins, temp, OP_ICONST);
1570                         temp->inst_c0 = ins->inst_imm;
1571                         temp->dreg = mono_regstate_next_int (cfg->rs);
1572                         ins->sreg2 = temp->dreg;
1573                         ins->opcode = OP_IMUL;
1574                         break;
1575                 case OP_LOAD_MEMBASE:
1576                 case OP_LOADI4_MEMBASE:
1577                 case OP_LOADU4_MEMBASE:
1578                 case OP_LOADU1_MEMBASE:
1579                         /* we can do two things: load the immed in a register
1580                          * and use an indexed load, or see if the immed can be
1581                          * represented as an ad_imm + a load with a smaller offset
1582                          * that fits. We just do the first for now, optimize later.
1583                          */
1584                         if (arm_is_imm12 (ins->inst_offset))
1585                                 break;
1586                         NEW_INS (cfg, ins, temp, OP_ICONST);
1587                         temp->inst_c0 = ins->inst_offset;
1588                         temp->dreg = mono_regstate_next_int (cfg->rs);
1589                         ins->sreg2 = temp->dreg;
1590                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1591                         break;
1592                 case OP_LOADI2_MEMBASE:
1593                 case OP_LOADU2_MEMBASE:
1594                 case OP_LOADI1_MEMBASE:
1595                         if (arm_is_imm8 (ins->inst_offset))
1596                                 break;
1597                         NEW_INS (cfg, ins, temp, OP_ICONST);
1598                         temp->inst_c0 = ins->inst_offset;
1599                         temp->dreg = mono_regstate_next_int (cfg->rs);
1600                         ins->sreg2 = temp->dreg;
1601                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1602                         break;
1603                 case OP_LOADR4_MEMBASE:
1604                 case OP_LOADR8_MEMBASE:
1605                         if (arm_is_fpimm8 (ins->inst_offset))
1606                                 break;
1607                         low_imm = ins->inst_offset & 0x1ff;
1608                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~0x1ff, &rot_amount)) >= 0) {
1609                                 NEW_INS (cfg, ins, temp, OP_ADD_IMM);
1610                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
1611                                 temp->sreg1 = ins->inst_basereg;
1612                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1613                                 ins->inst_basereg = temp->dreg;
1614                                 ins->inst_offset = low_imm;
1615                                 break;
1616                         }
1617                         /* VFP/FPA doesn't have indexed load instructions */
1618                         g_assert_not_reached ();
1619                         break;
1620                 case OP_STORE_MEMBASE_REG:
1621                 case OP_STOREI4_MEMBASE_REG:
1622                 case OP_STOREI1_MEMBASE_REG:
1623                         if (arm_is_imm12 (ins->inst_offset))
1624                                 break;
1625                         NEW_INS (cfg, ins, temp, OP_ICONST);
1626                         temp->inst_c0 = ins->inst_offset;
1627                         temp->dreg = mono_regstate_next_int (cfg->rs);
1628                         ins->sreg2 = temp->dreg;
1629                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1630                         break;
1631                 case OP_STOREI2_MEMBASE_REG:
1632                         if (arm_is_imm8 (ins->inst_offset))
1633                                 break;
1634                         NEW_INS (cfg, ins, temp, OP_ICONST);
1635                         temp->inst_c0 = ins->inst_offset;
1636                         temp->dreg = mono_regstate_next_int (cfg->rs);
1637                         ins->sreg2 = temp->dreg;
1638                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1639                         break;
1640                 case OP_STORER4_MEMBASE_REG:
1641                 case OP_STORER8_MEMBASE_REG:
1642                         if (arm_is_fpimm8 (ins->inst_offset))
1643                                 break;
1644                         low_imm = ins->inst_offset & 0x1ff;
1645                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~ 0x1ff, &rot_amount)) >= 0 && arm_is_fpimm8 (low_imm)) {
1646                                 NEW_INS (cfg, ins, temp, OP_ADD_IMM);
1647                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
1648                                 temp->sreg1 = ins->inst_destbasereg;
1649                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1650                                 ins->inst_destbasereg = temp->dreg;
1651                                 ins->inst_offset = low_imm;
1652                                 break;
1653                         }
1654                         /*g_print ("fail with: %d (%d, %d)\n", ins->inst_offset, ins->inst_offset & ~0x1ff, low_imm);*/
1655                         /* VFP/FPA doesn't have indexed store instructions */
1656                         g_assert_not_reached ();
1657                         break;
1658                 case OP_STORE_MEMBASE_IMM:
1659                 case OP_STOREI1_MEMBASE_IMM:
1660                 case OP_STOREI2_MEMBASE_IMM:
1661                 case OP_STOREI4_MEMBASE_IMM:
1662                         NEW_INS (cfg, ins, temp, OP_ICONST);
1663                         temp->inst_c0 = ins->inst_imm;
1664                         temp->dreg = mono_regstate_next_int (cfg->rs);
1665                         ins->sreg1 = temp->dreg;
1666                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1667                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
1668                 }
1669         }
1670         bb->max_vreg = cfg->rs->next_vreg;
1671 }
1672
1673 static guchar*
1674 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1675 {
1676         /* sreg is a float, dreg is an integer reg  */
1677 #ifdef ARM_FPU_FPA
1678         ARM_FIXZ (code, dreg, sreg);
1679 #elif defined(ARM_FPU_VFP)
1680         if (is_signed)
1681                 ARM_TOSIZD (code, ARM_VFP_F0, sreg);
1682         else
1683                 ARM_TOUIZD (code, ARM_VFP_F0, sreg);
1684         ARM_FMRS (code, dreg, ARM_VFP_F0);
1685 #endif
1686         if (!is_signed) {
1687                 if (size == 1)
1688                         ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff);
1689                 else if (size == 2) {
1690                         ARM_SHL_IMM (code, dreg, dreg, 16);
1691                         ARM_SHR_IMM (code, dreg, dreg, 16);
1692                 }
1693         } else {
1694                 if (size == 1) {
1695                         ARM_SHL_IMM (code, dreg, dreg, 24);
1696                         ARM_SAR_IMM (code, dreg, dreg, 24);
1697                 } else if (size == 2) {
1698                         ARM_SHL_IMM (code, dreg, dreg, 16);
1699                         ARM_SAR_IMM (code, dreg, dreg, 16);
1700                 }
1701         }
1702         return code;
1703 }
1704
1705 typedef struct {
1706         guchar *code;
1707         const guchar *target;
1708         int absolute;
1709         int found;
1710 } PatchData;
1711
1712 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1713
1714 static int
1715 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1716         PatchData *pdata = (PatchData*)user_data;
1717         guchar *code = data;
1718         guint32 *thunks = data;
1719         guint32 *endthunks = (guint32*)(code + bsize);
1720         int count = 0;
1721         int difflow, diffhigh;
1722
1723         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1724         difflow = (char*)pdata->code - (char*)thunks;
1725         diffhigh = (char*)pdata->code - (char*)endthunks;
1726         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1727                 return 0;
1728
1729         /*
1730          * The thunk is composed of 3 words:
1731          * load constant from thunks [2] into ARM_IP
1732          * bx to ARM_IP
1733          * address constant
1734          * Note that the LR register is already setup
1735          */
1736         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1737         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1738                 while (thunks < endthunks) {
1739                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1740                         if (thunks [2] == (guint32)pdata->target) {
1741                                 arm_patch (pdata->code, (guchar*)thunks);
1742                                 mono_arch_flush_icache (pdata->code, 4);
1743                                 pdata->found = 1;
1744                                 return 1;
1745                         } else if ((thunks [0] == 0) && (thunks [1] == 0) && (thunks [2] == 0)) {
1746                                 /* found a free slot instead: emit thunk */
1747                                 /* ARMREG_IP is fine to use since this can't be an IMT call
1748                                  * which is indirect
1749                                  */
1750                                 code = (guchar*)thunks;
1751                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
1752                                 if (thumb_supported)
1753                                         ARM_BX (code, ARMREG_IP);
1754                                 else
1755                                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
1756                                 thunks [2] = (guint32)pdata->target;
1757                                 mono_arch_flush_icache ((guchar*)thunks, 12);
1758
1759                                 arm_patch (pdata->code, (guchar*)thunks);
1760                                 mono_arch_flush_icache (pdata->code, 4);
1761                                 pdata->found = 1;
1762                                 return 1;
1763                         }
1764                         /* skip 12 bytes, the size of the thunk */
1765                         thunks += 3;
1766                         count++;
1767                 }
1768                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1769         }
1770         return 0;
1771 }
1772
1773 static void
1774 handle_thunk (int absolute, guchar *code, const guchar *target) {
1775         MonoDomain *domain = mono_domain_get ();
1776         PatchData pdata;
1777
1778         pdata.code = code;
1779         pdata.target = target;
1780         pdata.absolute = absolute;
1781         pdata.found = 0;
1782
1783         mono_domain_lock (domain);
1784         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1785
1786         if (!pdata.found) {
1787                 /* this uses the first available slot */
1788                 pdata.found = 2;
1789                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1790         }
1791         mono_domain_unlock (domain);
1792
1793         if (pdata.found != 1)
1794                 g_print ("thunk failed for %p from %p\n", target, code);
1795         g_assert (pdata.found == 1);
1796 }
1797
1798 void
1799 arm_patch (guchar *code, const guchar *target)
1800 {
1801         guint32 *code32 = (void*)code;
1802         guint32 ins = *code32;
1803         guint32 prim = (ins >> 25) & 7;
1804         guint32 tval = GPOINTER_TO_UINT (target);
1805
1806         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1807         if (prim == 5) { /* 101b */
1808                 /* the diff starts 8 bytes from the branch opcode */
1809                 gint diff = target - code - 8;
1810                 gint tbits;
1811                 gint tmask = 0xffffffff;
1812                 if (tval & 1) { /* entering thumb mode */
1813                         diff = target - 1 - code - 8;
1814                         g_assert (thumb_supported);
1815                         tbits = 0xf << 28; /* bl->blx bit pattern */
1816                         g_assert ((ins & (1 << 24))); /* it must be a bl, not b instruction */
1817                         /* this low bit of the displacement is moved to bit 24 in the instruction encoding */
1818                         if (diff & 2) {
1819                                 tbits |= 1 << 24;
1820                         }
1821                         tmask = ~(1 << 24); /* clear the link bit */
1822                         /*g_print ("blx to thumb: target: %p, code: %p, diff: %d, mask: %x\n", target, code, diff, tmask);*/
1823                 } else {
1824                         tbits = 0;
1825                 }
1826                 if (diff >= 0) {
1827                         if (diff <= 33554431) {
1828                                 diff >>= 2;
1829                                 ins = (ins & 0xff000000) | diff;
1830                                 ins &= tmask;
1831                                 *code32 = ins | tbits;
1832                                 return;
1833                         }
1834                 } else {
1835                         /* diff between 0 and -33554432 */
1836                         if (diff >= -33554432) {
1837                                 diff >>= 2;
1838                                 ins = (ins & 0xff000000) | (diff & ~0xff000000);
1839                                 ins &= tmask;
1840                                 *code32 = ins | tbits;
1841                                 return;
1842                         }
1843                 }
1844                 
1845                 handle_thunk (TRUE, code, target);
1846                 return;
1847         }
1848
1849         /*
1850          * The alternative call sequences looks like this:
1851          *
1852          *      ldr ip, [pc] // loads the address constant
1853          *      b 1f         // jumps around the constant
1854          *      address constant embedded in the code
1855          *   1f:
1856          *      mov lr, pc
1857          *      mov pc, ip
1858          *
1859          * There are two cases for patching:
1860          * a) at the end of method emission: in this case code points to the start
1861          *    of the call sequence
1862          * b) during runtime patching of the call site: in this case code points
1863          *    to the mov pc, ip instruction
1864          *
1865          * We have to handle also the thunk jump code sequence:
1866          *
1867          *      ldr ip, [pc]
1868          *      mov pc, ip
1869          *      address constant // execution never reaches here
1870          */
1871         if ((ins & 0x0ffffff0) == 0x12fff10) {
1872                 /* Branch and exchange: the address is constructed in a reg 
1873                  * We can patch BX when the code sequence is the following:
1874                  *  ldr     ip, [pc, #0]    ; 0x8
1875                  *  b       0xc
1876                  *  .word code_ptr
1877                  *  mov     lr, pc
1878                  *  bx      ips
1879                  * */
1880                 guint32 ccode [4];
1881                 guint8 *emit = (guint8*)ccode;
1882                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
1883                 ARM_B (emit, 0);
1884                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
1885                 ARM_BX (emit, ARMREG_IP);
1886
1887                 /*patching from magic trampoline*/
1888                 if (ins == ccode [3]) {
1889                         g_assert (code32 [-4] == ccode [0]);
1890                         g_assert (code32 [-3] == ccode [1]);
1891                         g_assert (code32 [-1] == ccode [2]);
1892                         code32 [-2] = (guint32)target;
1893                         return;
1894                 }
1895                 /*patching from JIT*/
1896                 if (ins == ccode [0]) {
1897                         g_assert (code32 [1] == ccode [1]);
1898                         g_assert (code32 [3] == ccode [2]);
1899                         g_assert (code32 [4] == ccode [3]);
1900                         code32 [2] = (guint32)target;
1901                         return;
1902                 }
1903                 g_assert_not_reached ();
1904         } else if ((ins & 0x0ffffff0) == 0x12fff30) {
1905                 /*
1906                  * ldr ip, [pc, #0]
1907                  * b 0xc
1908                  * .word code_ptr
1909                  * blx ip
1910                  */
1911                 guint32 ccode [4];
1912                 guint8 *emit = (guint8*)ccode;
1913                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
1914                 ARM_B (emit, 0);
1915                 ARM_BLX_REG (emit, ARMREG_IP);
1916
1917                 g_assert (code32 [-3] == ccode [0]);
1918                 g_assert (code32 [-2] == ccode [1]);
1919                 g_assert (code32 [0] == ccode [2]);
1920
1921                 code32 [-1] = (guint32)target;
1922         } else {
1923                 guint32 ccode [4];
1924                 guint32 *tmp = ccode;
1925                 guint8 *emit = (guint8*)tmp;
1926                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
1927                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
1928                 ARM_MOV_REG_REG (emit, ARMREG_PC, ARMREG_IP);
1929                 ARM_BX (emit, ARMREG_IP);
1930                 if (ins == ccode [2]) {
1931                         g_assert_not_reached (); // should be -2 ...
1932                         code32 [-1] = (guint32)target;
1933                         return;
1934                 }
1935                 if (ins == ccode [0]) {
1936                         /* handles both thunk jump code and the far call sequence */
1937                         code32 [2] = (guint32)target;
1938                         return;
1939                 }
1940                 g_assert_not_reached ();
1941         }
1942 //      g_print ("patched with 0x%08x\n", ins);
1943 }
1944
1945 /* 
1946  * Return the >= 0 uimm8 value if val can be represented with a byte + rotation
1947  * (with the rotation amount in *rot_amount. rot_amount is already adjusted
1948  * to be used with the emit macros.
1949  * Return -1 otherwise.
1950  */
1951 static int
1952 mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount)
1953 {
1954         guint32 res, i;
1955         for (i = 0; i < 31; i+= 2) {
1956                 res = (val << (32 - i)) | (val >> i);
1957                 if (res & ~0xff)
1958                         continue;
1959                 *rot_amount = i? 32 - i: 0;
1960                 return res;
1961         }
1962         return -1;
1963 }
1964
1965 /*
1966  * Emits in code a sequence of instructions that load the value 'val'
1967  * into the dreg register. Uses at most 4 instructions.
1968  */
1969 guint8*
1970 mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
1971 {
1972         int imm8, rot_amount;
1973 #if 0
1974         ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
1975         /* skip the constant pool */
1976         ARM_B (code, 0);
1977         *(int*)code = val;
1978         code += 4;
1979         return code;
1980 #endif
1981         if ((imm8 = mono_arm_is_rotated_imm8 (val, &rot_amount)) >= 0) {
1982                 ARM_MOV_REG_IMM (code, dreg, imm8, rot_amount);
1983         } else if ((imm8 = mono_arm_is_rotated_imm8 (~val, &rot_amount)) >= 0) {
1984                 ARM_MVN_REG_IMM (code, dreg, imm8, rot_amount);
1985         } else {
1986                 if (val & 0xFF) {
1987                         ARM_MOV_REG_IMM8 (code, dreg, (val & 0xFF));
1988                         if (val & 0xFF00) {
1989                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
1990                         }
1991                         if (val & 0xFF0000) {
1992                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
1993                         }
1994                         if (val & 0xFF000000) {
1995                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
1996                         }
1997                 } else if (val & 0xFF00) {
1998                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF00) >> 8, 24);
1999                         if (val & 0xFF0000) {
2000                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
2001                         }
2002                         if (val & 0xFF000000) {
2003                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
2004                         }
2005                 } else if (val & 0xFF0000) {
2006                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF0000) >> 16, 16);
2007                         if (val & 0xFF000000) {
2008                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
2009                         }
2010                 }
2011                 //g_assert_not_reached ();
2012         }
2013         return code;
2014 }
2015
2016 void
2017 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2018 {
2019         MonoInst *ins;
2020         MonoCallInst *call;
2021         guint offset;
2022         guint8 *code = cfg->native_code + cfg->code_len;
2023         guint last_offset = 0;
2024         int max_len, cpos;
2025         int imm8, rot_amount;
2026
2027         /* we don't align basic blocks of loops on arm */
2028
2029         if (cfg->verbose_level > 2)
2030                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2031
2032         cpos = bb->max_offset;
2033
2034         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2035                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
2036                 //g_assert (!mono_compile_aot);
2037                 //cpos += 6;
2038                 //if (bb->cil_code)
2039                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
2040                 /* this is not thread save, but good enough */
2041                 /* fixme: howto handle overflows? */
2042                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
2043         }
2044
2045         MONO_BB_FOR_EACH_INS (bb, ins) {
2046                 offset = code - cfg->native_code;
2047
2048                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2049
2050                 if (offset > (cfg->code_size - max_len - 16)) {
2051                         cfg->code_size *= 2;
2052                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2053                         code = cfg->native_code + offset;
2054                 }
2055         //      if (ins->cil_code)
2056         //              g_print ("cil code\n");
2057                 mono_debug_record_line_number (cfg, ins, offset);
2058
2059                 switch (ins->opcode) {
2060                 case OP_MEMORY_BARRIER:
2061                         break;
2062                 case OP_TLS_GET:
2063                         g_assert_not_reached ();
2064                         break;
2065                 /*case OP_BIGMUL:
2066                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
2067                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
2068                         break;
2069                 case OP_BIGMUL_UN:
2070                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
2071                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
2072                         break;*/
2073                 case OP_STOREI1_MEMBASE_IMM:
2074                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFF);
2075                         g_assert (arm_is_imm12 (ins->inst_offset));
2076                         ARM_STRB_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
2077                         break;
2078                 case OP_STOREI2_MEMBASE_IMM:
2079                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFFFF);
2080                         g_assert (arm_is_imm8 (ins->inst_offset));
2081                         ARM_STRH_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
2082                         break;
2083                 case OP_STORE_MEMBASE_IMM:
2084                 case OP_STOREI4_MEMBASE_IMM:
2085                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm);
2086                         g_assert (arm_is_imm12 (ins->inst_offset));
2087                         ARM_STR_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
2088                         break;
2089                 case OP_STOREI1_MEMBASE_REG:
2090                         g_assert (arm_is_imm12 (ins->inst_offset));
2091                         ARM_STRB_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2092                         break;
2093                 case OP_STOREI2_MEMBASE_REG:
2094                         g_assert (arm_is_imm8 (ins->inst_offset));
2095                         ARM_STRH_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2096                         break;
2097                 case OP_STORE_MEMBASE_REG:
2098                 case OP_STOREI4_MEMBASE_REG:
2099                         /* this case is special, since it happens for spill code after lowering has been called */
2100                         if (arm_is_imm12 (ins->inst_offset)) {
2101                                 ARM_STR_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2102                         } else {
2103                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
2104                                 ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
2105                         }
2106                         break;
2107                 case OP_STOREI1_MEMINDEX:
2108                         ARM_STRB_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
2109                         break;
2110                 case OP_STOREI2_MEMINDEX:
2111                         /* note: the args are reversed in the macro */
2112                         ARM_STRH_REG_REG (code, ins->inst_destbasereg, ins->sreg1, ins->sreg2);
2113                         break;
2114                 case OP_STORE_MEMINDEX:
2115                 case OP_STOREI4_MEMINDEX:
2116                         ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
2117                         break;
2118                 case OP_LOADU4_MEM:
2119                         g_assert_not_reached ();
2120                         break;
2121                 case OP_LOAD_MEMINDEX:
2122                 case OP_LOADI4_MEMINDEX:
2123                 case OP_LOADU4_MEMINDEX:
2124                         ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
2125                         break;
2126                 case OP_LOADI1_MEMINDEX:
2127                         /* note: the args are reversed in the macro */
2128                         ARM_LDRSB_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
2129                         break;
2130                 case OP_LOADU1_MEMINDEX:
2131                         ARM_LDRB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
2132                         break;
2133                 case OP_LOADI2_MEMINDEX:
2134                         /* note: the args are reversed in the macro */
2135                         ARM_LDRSH_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
2136                         break;
2137                 case OP_LOADU2_MEMINDEX:
2138                         /* note: the args are reversed in the macro */
2139                         ARM_LDRH_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
2140                         break;
2141                 case OP_LOAD_MEMBASE:
2142                 case OP_LOADI4_MEMBASE:
2143                 case OP_LOADU4_MEMBASE:
2144                         /* this case is special, since it happens for spill code after lowering has been called */
2145                         if (arm_is_imm12 (ins->inst_offset)) {
2146                                 ARM_LDR_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2147                         } else {
2148                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
2149                                 ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
2150                         }
2151                         break;
2152                 case OP_LOADI1_MEMBASE:
2153                         g_assert (arm_is_imm8 (ins->inst_offset));
2154                         ARM_LDRSB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2155                         break;
2156                 case OP_LOADU1_MEMBASE:
2157                         g_assert (arm_is_imm12 (ins->inst_offset));
2158                         ARM_LDRB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2159                         break;
2160                 case OP_LOADU2_MEMBASE:
2161                         g_assert (arm_is_imm8 (ins->inst_offset));
2162                         ARM_LDRH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2163                         break;
2164                 case OP_LOADI2_MEMBASE:
2165                         g_assert (arm_is_imm8 (ins->inst_offset));
2166                         ARM_LDRSH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2167                         break;
2168                 case OP_ICONV_TO_I1:
2169                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 24);
2170                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 24);
2171                         break;
2172                 case OP_ICONV_TO_I2:
2173                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
2174                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 16);
2175                         break;
2176                 case OP_ICONV_TO_U1:
2177                         ARM_AND_REG_IMM8 (code, ins->dreg, ins->sreg1, 0xff);
2178                         break;
2179                 case OP_ICONV_TO_U2:
2180                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
2181                         ARM_SHR_IMM (code, ins->dreg, ins->dreg, 16);
2182                         break;
2183                 case OP_COMPARE:
2184                         ARM_CMP_REG_REG (code, ins->sreg1, ins->sreg2);
2185                         break;
2186                 case OP_COMPARE_IMM:
2187                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2188                         g_assert (imm8 >= 0);
2189                         ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount);
2190                         break;
2191                 case OP_BREAK:
2192                         *(int*)code = 0xe7f001f0;
2193                         *(int*)code = 0xef9f0001;
2194                         code += 4;
2195                         //ARM_DBRK (code);
2196                         break;
2197                 case OP_ADDCC:
2198                         ARM_ADDS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2199                         break;
2200                 case OP_IADD:
2201                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2202                         break;
2203                 case OP_ADC:
2204                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2205                         break;
2206                 case OP_ADDCC_IMM:
2207                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2208                         g_assert (imm8 >= 0);
2209                         ARM_ADDS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2210                         break;
2211                 case OP_ADD_IMM:
2212                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2213                         g_assert (imm8 >= 0);
2214                         ARM_ADD_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2215                         break;
2216                 case OP_ADC_IMM:
2217                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2218                         g_assert (imm8 >= 0);
2219                         ARM_ADCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2220                         break;
2221                 case OP_IADD_OVF:
2222                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2223                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2224                         break;
2225                 case OP_IADD_OVF_UN:
2226                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2227                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2228                         break;
2229                 case OP_ISUB_OVF:
2230                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2231                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2232                         break;
2233                 case OP_ISUB_OVF_UN:
2234                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2235                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2236                         break;
2237                 case OP_ADD_OVF_CARRY:
2238                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2239                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2240                         break;
2241                 case OP_ADD_OVF_UN_CARRY:
2242                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2243                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2244                         break;
2245                 case OP_SUB_OVF_CARRY:
2246                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2247                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
2248                         break;
2249                 case OP_SUB_OVF_UN_CARRY:
2250                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2251                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
2252                         break;
2253                 case OP_SUBCC:
2254                         ARM_SUBS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2255                         break;
2256                 case OP_SUBCC_IMM:
2257                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2258                         g_assert (imm8 >= 0);
2259                         ARM_SUBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2260                         break;
2261                 case OP_ISUB:
2262                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2263                         break;
2264                 case OP_SBB:
2265                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2266                         break;
2267                 case OP_SUB_IMM:
2268                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2269                         g_assert (imm8 >= 0);
2270                         ARM_SUB_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2271                         break;
2272                 case OP_SBB_IMM:
2273                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2274                         g_assert (imm8 >= 0);
2275                         ARM_SBCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2276                         break;
2277                 case OP_ARM_RSBS_IMM:
2278                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2279                         g_assert (imm8 >= 0);
2280                         ARM_RSBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2281                         break;
2282                 case OP_ARM_RSC_IMM:
2283                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2284                         g_assert (imm8 >= 0);
2285                         ARM_RSC_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2286                         break;
2287                 case OP_IAND:
2288                         ARM_AND_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2289                         break;
2290                 case OP_AND_IMM:
2291                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2292                         g_assert (imm8 >= 0);
2293                         ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2294                         break;
2295                 case OP_IDIV:
2296                 case OP_IDIV_UN:
2297                 case OP_DIV_IMM:
2298                 case OP_IREM:
2299                 case OP_IREM_UN:
2300                 case OP_REM_IMM:
2301                         /* crappy ARM arch doesn't have a DIV instruction */
2302                         g_assert_not_reached ();
2303                 case OP_IOR:
2304                         ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2305                         break;
2306                 case OP_OR_IMM:
2307                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2308                         g_assert (imm8 >= 0);
2309                         ARM_ORR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2310                         break;
2311                 case OP_IXOR:
2312                         ARM_EOR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2313                         break;
2314                 case OP_XOR_IMM:
2315                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2316                         g_assert (imm8 >= 0);
2317                         ARM_EOR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2318                         break;
2319                 case OP_ISHL:
2320                         ARM_SHL_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2321                         break;
2322                 case OP_SHL_IMM:
2323                         if (ins->inst_imm)
2324                                 ARM_SHL_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2325                         break;
2326                 case OP_ISHR:
2327                         ARM_SAR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2328                         break;
2329                 case OP_SHR_IMM:
2330                         if (ins->inst_imm)
2331                                 ARM_SAR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2332                         break;
2333                 case OP_SHR_UN_IMM:
2334                         if (ins->inst_imm)
2335                                 ARM_SHR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2336                         break;
2337                 case OP_ISHR_UN:
2338                         ARM_SHR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2339                         break;
2340                 case OP_INOT:
2341                         ARM_MVN_REG_REG (code, ins->dreg, ins->sreg1);
2342                         break;
2343                 case OP_INEG:
2344                         ARM_RSB_REG_IMM8 (code, ins->dreg, ins->sreg1, 0);
2345                         break;
2346                 case OP_IMUL:
2347                         if (ins->dreg == ins->sreg2)
2348                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2349                         else
2350                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg2, ins->sreg1);
2351                         break;
2352                 case OP_MUL_IMM:
2353                         g_assert_not_reached ();
2354                         break;
2355                 case OP_IMUL_OVF:
2356                         /* FIXME: handle ovf/ sreg2 != dreg */
2357                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2358                         break;
2359                 case OP_IMUL_OVF_UN:
2360                         /* FIXME: handle ovf/ sreg2 != dreg */
2361                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2362                         break;
2363                 case OP_ICONST:
2364                         code = mono_arm_emit_load_imm (code, ins->dreg, ins->inst_c0);
2365                         break;
2366                 case OP_AOTCONST:
2367                         /* Load the GOT offset */
2368                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2369                         ARM_LDR_IMM (code, ins->dreg, ARMREG_PC, 0);
2370                         ARM_B (code, 0);
2371                         *(gpointer*)code = NULL;
2372                         code += 4;
2373                         /* Load the value from the GOT */
2374                         ARM_LDR_REG_REG (code, ins->dreg, ARMREG_PC, ins->dreg);
2375                         break;
2376                 case OP_ICONV_TO_I4:
2377                 case OP_ICONV_TO_U4:
2378                 case OP_MOVE:
2379                         if (ins->dreg != ins->sreg1)
2380                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2381                         break;
2382                 case OP_SETLRET: {
2383                         int saved = ins->sreg2;
2384                         if (ins->sreg2 == ARM_LSW_REG) {
2385                                 ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg2);
2386                                 saved = ARMREG_LR;
2387                         }
2388                         if (ins->sreg1 != ARM_LSW_REG)
2389                                 ARM_MOV_REG_REG (code, ARM_LSW_REG, ins->sreg1);
2390                         if (saved != ARM_MSW_REG)
2391                                 ARM_MOV_REG_REG (code, ARM_MSW_REG, saved);
2392                         break;
2393                 }
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 OP_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 OP_THROW: {
2507                         if (ins->sreg1 != ARMREG_R0)
2508                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2509                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2510                                              (gpointer)"mono_arch_throw_exception");
2511                         code = emit_call_seq (cfg, code);
2512                         break;
2513                 }
2514                 case OP_RETHROW: {
2515                         if (ins->sreg1 != ARMREG_R0)
2516                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2517                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2518                                              (gpointer)"mono_arch_rethrow_exception");
2519                         code = emit_call_seq (cfg, code);
2520                         break;
2521                 }
2522                 case OP_START_HANDLER:
2523                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2524                                 ARM_STR_IMM (code, ARMREG_LR, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2525                         } else {
2526                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2527                                 ARM_STR_REG_REG (code, ARMREG_LR, ins->inst_left->inst_basereg, ARMREG_IP);
2528                         }
2529                         break;
2530                 case OP_ENDFILTER:
2531                         if (ins->sreg1 != ARMREG_R0)
2532                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2533                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2534                                 ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2535                         } else {
2536                                 g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
2537                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2538                                 ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
2539                         }
2540                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2541                         break;
2542                 case OP_ENDFINALLY:
2543                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2544                                 ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2545                         } else {
2546                                 g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
2547                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2548                                 ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
2549                         }
2550                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2551                         break;
2552                 case OP_CALL_HANDLER: 
2553                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2554                         ARM_BL (code, 0);
2555                         break;
2556                 case OP_LABEL:
2557                         ins->inst_c0 = code - cfg->native_code;
2558                         break;
2559                 case OP_BR:
2560                         if (ins->flags & MONO_INST_BRLABEL) {
2561                                 /*if (ins->inst_i0->inst_c0) {
2562                                         ARM_B (code, 0);
2563                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2564                                 } else*/ {
2565                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2566                                         ARM_B (code, 0);
2567                                 }
2568                         } else {
2569                                 /*if (ins->inst_target_bb->native_offset) {
2570                                         ARM_B (code, 0);
2571                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2572                                 } else*/ {
2573                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2574                                         ARM_B (code, 0);
2575                                 } 
2576                         }
2577                         break;
2578                 case OP_BR_REG:
2579                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
2580                         break;
2581                 case OP_SWITCH:
2582                         /* 
2583                          * In the normal case we have:
2584                          *      ldr pc, [pc, ins->sreg1 << 2]
2585                          *      nop
2586                          * If aot, we have:
2587                          *      ldr lr, [pc, ins->sreg1 << 2]
2588                          *      add pc, pc, lr
2589                          * After follows the data.
2590                          * FIXME: add aot support.
2591                          */
2592                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
2593                         if (offset > (cfg->code_size - max_len - 16)) {
2594                                 cfg->code_size += max_len;
2595                                 cfg->code_size *= 2;
2596                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2597                                 code = cfg->native_code + offset;
2598                         }
2599                         ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_PC, ins->sreg1, ARMSHIFT_LSL, 2);
2600                         ARM_NOP (code);
2601                         code += 4 * GPOINTER_TO_INT (ins->klass);
2602                         break;
2603                 case OP_CEQ:
2604                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
2605                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
2606                         break;
2607                 case OP_CLT:
2608                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2609                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LT);
2610                         break;
2611                 case OP_CLT_UN:
2612                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2613                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LO);
2614                         break;
2615                 case OP_CGT:
2616                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2617                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_GT);
2618                         break;
2619                 case OP_CGT_UN:
2620                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2621                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_HI);
2622                         break;
2623                 case OP_COND_EXC_EQ:
2624                 case OP_COND_EXC_NE_UN:
2625                 case OP_COND_EXC_LT:
2626                 case OP_COND_EXC_LT_UN:
2627                 case OP_COND_EXC_GT:
2628                 case OP_COND_EXC_GT_UN:
2629                 case OP_COND_EXC_GE:
2630                 case OP_COND_EXC_GE_UN:
2631                 case OP_COND_EXC_LE:
2632                 case OP_COND_EXC_LE_UN:
2633                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2634                         break;
2635                 case OP_COND_EXC_C:
2636                 case OP_COND_EXC_OV:
2637                 case OP_COND_EXC_NC:
2638                 case OP_COND_EXC_NO:
2639                         g_assert_not_reached ();
2640                         break;
2641                 case OP_IBEQ:
2642                 case OP_IBNE_UN:
2643                 case OP_IBLT:
2644                 case OP_IBLT_UN:
2645                 case OP_IBGT:
2646                 case OP_IBGT_UN:
2647                 case OP_IBGE:
2648                 case OP_IBGE_UN:
2649                 case OP_IBLE:
2650                 case OP_IBLE_UN:
2651                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
2652                         break;
2653
2654                 /* floating point opcodes */
2655 #ifdef ARM_FPU_FPA
2656                 case OP_R8CONST:
2657                         if (cfg->compile_aot) {
2658                                 ARM_LDFD (code, ins->dreg, ARMREG_PC, 0);
2659                                 ARM_B (code, 1);
2660                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
2661                                 code += 4;
2662                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[1];
2663                                 code += 4;
2664                         } else {
2665                                 /* FIXME: we can optimize the imm load by dealing with part of 
2666                                  * the displacement in LDFD (aligning to 512).
2667                                  */
2668                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2669                                 ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
2670                         }
2671                         break;
2672                 case OP_R4CONST:
2673                         if (cfg->compile_aot) {
2674                                 ARM_LDFS (code, ins->dreg, ARMREG_PC, 0);
2675                                 ARM_B (code, 0);
2676                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
2677                                 code += 4;
2678                         } else {
2679                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2680                                 ARM_LDFS (code, ins->dreg, ARMREG_LR, 0);
2681                         }
2682                         break;
2683                 case OP_STORER8_MEMBASE_REG:
2684                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2685                         ARM_STFD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2686                         break;
2687                 case OP_LOADR8_MEMBASE:
2688                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2689                         ARM_LDFD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2690                         break;
2691                 case OP_STORER4_MEMBASE_REG:
2692                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2693                         ARM_STFS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2694                         break;
2695                 case OP_LOADR4_MEMBASE:
2696                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2697                         ARM_LDFS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2698                         break;
2699                 case OP_ICONV_TO_R_UN: {
2700                         int tmpreg;
2701                         tmpreg = ins->dreg == 0? 1: 0;
2702                         ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
2703                         ARM_FLTD (code, ins->dreg, ins->sreg1);
2704                         ARM_B_COND (code, ARMCOND_GE, 8);
2705                         /* save the temp register */
2706                         ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
2707                         ARM_STFD (code, tmpreg, ARMREG_SP, 0);
2708                         ARM_LDFD (code, tmpreg, ARMREG_PC, 12);
2709                         ARM_FPA_ADFD (code, ins->dreg, ins->dreg, tmpreg);
2710                         ARM_LDFD (code, tmpreg, ARMREG_SP, 0);
2711                         ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
2712                         /* skip the constant pool */
2713                         ARM_B (code, 8);
2714                         code += 4;
2715                         *(int*)code = 0x41f00000;
2716                         code += 4;
2717                         *(int*)code = 0;
2718                         code += 4;
2719                         /* FIXME: adjust:
2720                          * ldfltd  ftemp, [pc, #8] 0x41f00000 0x00000000
2721                          * adfltd  fdest, fdest, ftemp
2722                          */
2723                         break;
2724                 }
2725                 case OP_ICONV_TO_R4:
2726                         ARM_FLTS (code, ins->dreg, ins->sreg1);
2727                         break;
2728                 case OP_ICONV_TO_R8:
2729                         ARM_FLTD (code, ins->dreg, ins->sreg1);
2730                         break;
2731 #elif defined(ARM_FPU_VFP)
2732                 case OP_R8CONST:
2733                         if (cfg->compile_aot) {
2734                                 ARM_LDFD (code, ins->dreg, ARMREG_PC, 0);
2735                                 ARM_B (code, 1);
2736                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
2737                                 code += 4;
2738                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[1];
2739                                 code += 4;
2740                         } else {
2741                                 /* FIXME: we can optimize the imm load by dealing with part of 
2742                                  * the displacement in LDFD (aligning to 512).
2743                                  */
2744                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2745                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
2746                         }
2747                         break;
2748                 case OP_R4CONST:
2749                         if (cfg->compile_aot) {
2750                                 ARM_FLDS (code, ins->dreg, ARMREG_PC, 0);
2751                                 ARM_B (code, 0);
2752                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
2753                                 code += 4;
2754                                 ARM_CVTS (code, ins->dreg, ins->dreg);
2755                         } else {
2756                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2757                                 ARM_FLDS (code, ins->dreg, ARMREG_LR, 0);
2758                                 ARM_CVTS (code, ins->dreg, ins->dreg);
2759                         }
2760                         break;
2761                 case OP_STORER8_MEMBASE_REG:
2762                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2763                         ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2764                         break;
2765                 case OP_LOADR8_MEMBASE:
2766                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2767                         ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2768                         break;
2769                 case OP_STORER4_MEMBASE_REG:
2770                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2771                         ARM_FSTS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2772                         break;
2773                 case OP_LOADR4_MEMBASE:
2774                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2775                         ARM_FLDS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2776                         break;
2777                 case OP_ICONV_TO_R_UN: {
2778                         g_assert_not_reached ();
2779                         break;
2780                 }
2781                 case OP_ICONV_TO_R4:
2782                         g_assert_not_reached ();
2783                         //ARM_FLTS (code, ins->dreg, ins->sreg1);
2784                         break;
2785                 case OP_ICONV_TO_R8:
2786                         g_assert_not_reached ();
2787                         //ARM_FLTD (code, ins->dreg, ins->sreg1);
2788                         break;
2789 #endif
2790                 case OP_FCONV_TO_I1:
2791                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2792                         break;
2793                 case OP_FCONV_TO_U1:
2794                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2795                         break;
2796                 case OP_FCONV_TO_I2:
2797                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2798                         break;
2799                 case OP_FCONV_TO_U2:
2800                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2801                         break;
2802                 case OP_FCONV_TO_I4:
2803                 case OP_FCONV_TO_I:
2804                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2805                         break;
2806                 case OP_FCONV_TO_U4:
2807                 case OP_FCONV_TO_U:
2808                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2809                         break;
2810                 case OP_FCONV_TO_I8:
2811                 case OP_FCONV_TO_U8:
2812                         g_assert_not_reached ();
2813                         /* Implemented as helper calls */
2814                         break;
2815                 case OP_LCONV_TO_R_UN:
2816                         g_assert_not_reached ();
2817                         /* Implemented as helper calls */
2818                         break;
2819                 case OP_LCONV_TO_OVF_I: {
2820 #if ARM_PORT
2821                         guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2822                         // Check if its negative
2823                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2824                         negative_branch = code;
2825                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2826                         // Its positive msword == 0
2827                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2828                         msword_positive_branch = code;
2829                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2830
2831                         ovf_ex_target = code;
2832                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2833                         // Negative
2834                         ppc_patch (negative_branch, code);
2835                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2836                         msword_negative_branch = code;
2837                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2838                         ppc_patch (msword_negative_branch, ovf_ex_target);
2839                         
2840                         ppc_patch (msword_positive_branch, code);
2841                         if (ins->dreg != ins->sreg1)
2842                                 ppc_mr (code, ins->dreg, ins->sreg1);
2843 #endif
2844                         if (ins->dreg != ins->sreg1)
2845                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2846                         break;
2847                 }
2848 #ifdef ARM_FPU_FPA
2849                 case OP_FADD:
2850                         ARM_FPA_ADFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2851                         break;
2852                 case OP_FSUB:
2853                         ARM_FPA_SUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2854                         break;          
2855                 case OP_FMUL:
2856                         ARM_FPA_MUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2857                         break;          
2858                 case OP_FDIV:
2859                         ARM_FPA_DVFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2860                         break;          
2861                 case OP_FNEG:
2862                         ARM_MNFD (code, ins->dreg, ins->sreg1);
2863                         break;
2864 #elif defined(ARM_FPU_VFP)
2865                 case OP_FADD:
2866                         ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2);
2867                         break;
2868                 case OP_FSUB:
2869                         ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2);
2870                         break;          
2871                 case OP_FMUL:
2872                         ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2);
2873                         break;          
2874                 case OP_FDIV:
2875                         ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2);
2876                         break;          
2877                 case OP_FNEG:
2878                         ARM_NEGD (code, ins->dreg, ins->sreg1);
2879                         break;
2880 #endif
2881                 case OP_FREM:
2882                         /* emulated */
2883                         g_assert_not_reached ();
2884                         break;
2885                 case OP_FCOMPARE:
2886                         /* each fp compare op needs to do its own */
2887                         g_assert_not_reached ();
2888                         //ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2889                         break;
2890                 case OP_FCEQ:
2891 #ifdef ARM_FPU_FPA
2892                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2893 #elif defined(ARM_FPU_VFP)
2894                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2895 #endif
2896                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
2897                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
2898                         break;
2899                 case OP_FCLT:
2900 #ifdef ARM_FPU_FPA
2901                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2902 #elif defined(ARM_FPU_VFP)
2903                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2904 #endif
2905                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2906                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2907                         break;
2908                 case OP_FCLT_UN:
2909 #ifdef ARM_FPU_FPA
2910                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2911 #elif defined(ARM_FPU_VFP)
2912                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2913 #endif
2914                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2915                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2916                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
2917                         break;
2918                 case OP_FCGT:
2919                         /* swapped */
2920 #ifdef ARM_FPU_FPA
2921                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2922 #elif defined(ARM_FPU_VFP)
2923                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2924 #endif
2925                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2926                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2927                         break;
2928                 case OP_FCGT_UN:
2929                         /* swapped */
2930 #ifdef ARM_FPU_FPA
2931                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2932 #elif defined(ARM_FPU_VFP)
2933                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2934 #endif
2935                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2936                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2937                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
2938                         break;
2939                 /* ARM FPA flags table:
2940                  * N        Less than               ARMCOND_MI
2941                  * Z        Equal                   ARMCOND_EQ
2942                  * C        Greater Than or Equal   ARMCOND_CS
2943                  * V        Unordered               ARMCOND_VS
2944                  */
2945                 case OP_FBEQ:
2946 #ifdef ARM_FPU_FPA
2947                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2948 #elif defined(ARM_FPU_VFP)
2949                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2950 #endif
2951                         EMIT_COND_BRANCH (ins, OP_IBEQ - OP_IBEQ);
2952                         break;
2953                 case OP_FBNE_UN:
2954 #ifdef ARM_FPU_FPA
2955                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2956 #elif defined(ARM_FPU_VFP)
2957                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2958 #endif
2959                         EMIT_COND_BRANCH (ins, OP_IBNE_UN - OP_IBEQ);
2960                         break;
2961                 case OP_FBLT:
2962 #ifdef ARM_FPU_FPA
2963                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2964 #elif defined(ARM_FPU_VFP)
2965                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2966 #endif
2967                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
2968                         break;
2969                 case OP_FBLT_UN:
2970 #ifdef ARM_FPU_FPA
2971                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2972 #elif defined(ARM_FPU_VFP)
2973                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
2974 #endif
2975                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2976                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
2977                         break;
2978                 case OP_FBGT:
2979 #ifdef ARM_FPU_FPA
2980                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2981 #elif defined(ARM_FPU_VFP)
2982                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2983 #endif
2984                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
2985                         break;
2986                 case OP_FBGT_UN:
2987 #ifdef ARM_FPU_FPA
2988                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2989 #elif defined(ARM_FPU_VFP)
2990                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
2991 #endif
2992                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2993                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
2994                         break;
2995                 case OP_FBGE:
2996 #ifdef ARM_FPU_FPA
2997                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2998 #elif defined(ARM_FPU_VFP)
2999                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3000 #endif
3001                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
3002                         break;
3003                 case OP_FBGE_UN:
3004 #ifdef ARM_FPU_FPA
3005                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3006 #elif defined(ARM_FPU_VFP)
3007                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3008 #endif
3009                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
3010                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
3011                         break;
3012                 case OP_FBLE:
3013 #ifdef ARM_FPU_FPA
3014                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3015 #elif defined(ARM_FPU_VFP)
3016                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3017 #endif
3018                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); /* swapped */
3019                         break;
3020                 case OP_FBLE_UN:
3021 #ifdef ARM_FPU_FPA
3022                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3023 #elif defined(ARM_FPU_VFP)
3024                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3025 #endif
3026                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
3027                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE); /* swapped */
3028                         break;
3029                 case OP_CKFINITE: {
3030                         /*ppc_stfd (code, ins->sreg1, -8, ppc_sp);
3031                         ppc_lwz (code, ppc_r11, -8, ppc_sp);
3032                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
3033                         ppc_addis (code, ppc_r11, ppc_r11, -32752);
3034                         ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
3035                         EMIT_COND_SYSTEM_EXCEPTION (OP_IBEQ - OP_IBEQ, "ArithmeticException");*/
3036                         g_assert_not_reached ();
3037                         break;
3038                 }
3039                 default:
3040                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3041                         g_assert_not_reached ();
3042                 }
3043
3044                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3045                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3046                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3047                         g_assert_not_reached ();
3048                 }
3049                
3050                 cpos += max_len;
3051
3052                 last_offset = offset;
3053         }
3054
3055         cfg->code_len = code - cfg->native_code;
3056 }
3057
3058 void
3059 mono_arch_register_lowlevel_calls (void)
3060 {
3061 }
3062
3063 #define patch_lis_ori(ip,val) do {\
3064                 guint16 *__lis_ori = (guint16*)(ip);    \
3065                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
3066                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
3067         } while (0)
3068
3069 void
3070 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3071 {
3072         MonoJumpInfo *patch_info;
3073         gboolean compile_aot = !run_cctors;
3074
3075         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3076                 unsigned char *ip = patch_info->ip.i + code;
3077                 const unsigned char *target;
3078
3079                 if (patch_info->type == MONO_PATCH_INFO_SWITCH && !compile_aot) {
3080                         gpointer *jt = (gpointer*)(ip + 8);
3081                         int i;
3082                         /* jt is the inlined jump table, 2 instructions after ip
3083                          * In the normal case we store the absolute addresses,
3084                          * otherwise the displacements.
3085                          */
3086                         for (i = 0; i < patch_info->data.table->table_size; i++)
3087                                 jt [i] = code + (int)patch_info->data.table->table [i];
3088                         continue;
3089                 }
3090                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3091
3092                 if (compile_aot) {
3093                         switch (patch_info->type) {
3094                         case MONO_PATCH_INFO_BB:
3095                         case MONO_PATCH_INFO_LABEL:
3096                                 break;
3097                         default:
3098                                 /* No need to patch these */
3099                                 continue;
3100                         }
3101                 }
3102
3103                 switch (patch_info->type) {
3104                 case MONO_PATCH_INFO_IP:
3105                         g_assert_not_reached ();
3106                         patch_lis_ori (ip, ip);
3107                         continue;
3108                 case MONO_PATCH_INFO_METHOD_REL:
3109                         g_assert_not_reached ();
3110                         *((gpointer *)(ip)) = code + patch_info->data.offset;
3111                         continue;
3112                 case MONO_PATCH_INFO_METHODCONST:
3113                 case MONO_PATCH_INFO_CLASS:
3114                 case MONO_PATCH_INFO_IMAGE:
3115                 case MONO_PATCH_INFO_FIELD:
3116                 case MONO_PATCH_INFO_VTABLE:
3117                 case MONO_PATCH_INFO_IID:
3118                 case MONO_PATCH_INFO_SFLDA:
3119                 case MONO_PATCH_INFO_LDSTR:
3120                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3121                 case MONO_PATCH_INFO_LDTOKEN:
3122                         g_assert_not_reached ();
3123                         /* from OP_AOTCONST : lis + ori */
3124                         patch_lis_ori (ip, target);
3125                         continue;
3126                 case MONO_PATCH_INFO_R4:
3127                 case MONO_PATCH_INFO_R8:
3128                         g_assert_not_reached ();
3129                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3130                         continue;
3131                 case MONO_PATCH_INFO_EXC_NAME:
3132                         g_assert_not_reached ();
3133                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3134                         continue;
3135                 case MONO_PATCH_INFO_NONE:
3136                 case MONO_PATCH_INFO_BB_OVF:
3137                 case MONO_PATCH_INFO_EXC_OVF:
3138                         /* everything is dealt with at epilog output time */
3139                         continue;
3140                 default:
3141                         break;
3142                 }
3143                 arm_patch (ip, target);
3144         }
3145 }
3146
3147 /*
3148  * Stack frame layout:
3149  * 
3150  *   ------------------- fp
3151  *      MonoLMF structure or saved registers
3152  *   -------------------
3153  *      locals
3154  *   -------------------
3155  *      spilled regs
3156  *   -------------------
3157  *      optional 8 bytes for tracing
3158  *   -------------------
3159  *      param area             size is cfg->param_area
3160  *   ------------------- sp
3161  */
3162 guint8 *
3163 mono_arch_emit_prolog (MonoCompile *cfg)
3164 {
3165         MonoMethod *method = cfg->method;
3166         MonoBasicBlock *bb;
3167         MonoMethodSignature *sig;
3168         MonoInst *inst;
3169         int alloc_size, pos, max_offset, i, rot_amount;
3170         guint8 *code;
3171         CallInfo *cinfo;
3172         int tracing = 0;
3173         int lmf_offset = 0;
3174         int prev_sp_offset;
3175
3176         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3177                 tracing = 1;
3178
3179         sig = mono_method_signature (method);
3180         cfg->code_size = 256 + sig->param_count * 20;
3181         code = cfg->native_code = g_malloc (cfg->code_size);
3182
3183         ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
3184
3185         alloc_size = cfg->stack_offset;
3186         pos = 0;
3187
3188         if (!method->save_lmf) {
3189                 ARM_PUSH (code, (cfg->used_int_regs | (1 << ARMREG_IP) | (1 << ARMREG_LR)));
3190                 prev_sp_offset = 8; /* ip and lr */
3191                 for (i = 0; i < 16; ++i) {
3192                         if (cfg->used_int_regs & (1 << i))
3193                                 prev_sp_offset += 4;
3194                 }
3195         } else {
3196                 ARM_PUSH (code, 0x5ff0);
3197                 prev_sp_offset = 4 * 10; /* all but r0-r3, sp and pc */
3198                 pos += sizeof (MonoLMF) - prev_sp_offset;
3199                 lmf_offset = pos;
3200         }
3201         alloc_size += pos;
3202         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
3203         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
3204                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3205                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
3206         }
3207
3208         /* the stack used in the pushed regs */
3209         if (prev_sp_offset & 4)
3210                 alloc_size += 4;
3211         cfg->stack_usage = alloc_size;
3212         if (alloc_size) {
3213                 if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
3214                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
3215                 } else {
3216                         code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
3217                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
3218                 }
3219         }
3220         if (cfg->frame_reg != ARMREG_SP)
3221                 ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
3222         //g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
3223         prev_sp_offset += alloc_size;
3224
3225         /* compute max_offset in order to use short forward jumps
3226          * we could skip do it on arm because the immediate displacement
3227          * for jumps is large enough, it may be useful later for constant pools
3228          */
3229         max_offset = 0;
3230         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3231                 MonoInst *ins;
3232                 bb->max_offset = max_offset;
3233
3234                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3235                         max_offset += 6; 
3236
3237                 MONO_BB_FOR_EACH_INS (bb, ins)
3238                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3239         }
3240
3241         /* load arguments allocated to register from the stack */
3242         pos = 0;
3243
3244         cinfo = calculate_sizes (sig, sig->pinvoke);
3245
3246         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3247                 ArgInfo *ainfo = &cinfo->ret;
3248                 inst = cfg->ret;
3249                 g_assert (arm_is_imm12 (inst->inst_offset));
3250                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3251         }
3252         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3253                 ArgInfo *ainfo = cinfo->args + i;
3254                 inst = cfg->args [pos];
3255                 
3256                 if (cfg->verbose_level > 2)
3257                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3258                 if (inst->opcode == OP_REGVAR) {
3259                         if (ainfo->regtype == RegTypeGeneral)
3260                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
3261                         else if (ainfo->regtype == RegTypeFP) {
3262                                 g_assert_not_reached ();
3263                         } else if (ainfo->regtype == RegTypeBase) {
3264                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
3265                                 ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3266                         } else
3267                                 g_assert_not_reached ();
3268
3269                         if (cfg->verbose_level > 2)
3270                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3271                 } else {
3272                         /* the argument should be put on the stack: FIXME handle size != word  */
3273                         if (ainfo->regtype == RegTypeGeneral) {
3274                                 switch (ainfo->size) {
3275                                 case 1:
3276                                         if (arm_is_imm12 (inst->inst_offset))
3277                                                 ARM_STRB_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3278                                         else {
3279                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3280                                                 ARM_STRB_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
3281                                         }
3282                                         break;
3283                                 case 2:
3284                                         if (arm_is_imm8 (inst->inst_offset)) {
3285                                                 ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3286                                         } else {
3287                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3288                                                 ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
3289                                                 ARM_STRH_IMM (code, ainfo->reg, ARMREG_IP, 0);
3290                                         }
3291                                         break;
3292                                 case 8:
3293                                         g_assert (arm_is_imm12 (inst->inst_offset));
3294                                         ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3295                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
3296                                         ARM_STR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3297                                         break;
3298                                 default:
3299                                         if (arm_is_imm12 (inst->inst_offset)) {
3300                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3301                                         } else {
3302                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3303                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
3304                                         }
3305                                         break;
3306                                 }
3307                         } else if (ainfo->regtype == RegTypeBaseGen) {
3308                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
3309                                 g_assert (arm_is_imm12 (inst->inst_offset));
3310                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3311                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
3312                                 ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset);
3313                         } else if (ainfo->regtype == RegTypeBase) {
3314                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
3315                                 switch (ainfo->size) {
3316                                 case 1:
3317                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3318                                         g_assert (arm_is_imm12 (inst->inst_offset));
3319                                         ARM_STRB_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3320                                         break;
3321                                 case 2:
3322                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3323                                         if (arm_is_imm8 (inst->inst_offset)) {
3324                                                 ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3325                                         } else {
3326                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3327                                                 ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
3328                                                 ARM_STRH_IMM (code, ARMREG_LR, ARMREG_IP, 0);
3329                                         }
3330                                         break;
3331                                 case 8:
3332                                         g_assert (arm_is_imm12 (inst->inst_offset));
3333                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3334                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3335                                         g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset + 4));
3336                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
3337                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset + 4));
3338                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
3339                                         break;
3340                                 default:
3341                                         g_assert (arm_is_imm12 (inst->inst_offset));
3342                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3343                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3344                                         break;
3345                                 }
3346                         } else if (ainfo->regtype == RegTypeFP) {
3347                                 g_assert_not_reached ();
3348                         } else if (ainfo->regtype == RegTypeStructByVal) {
3349                                 int doffset = inst->inst_offset;
3350                                 int soffset = 0;
3351                                 int cur_reg;
3352                                 int size = 0;
3353                                 if (mono_class_from_mono_type (inst->inst_vtype))
3354                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3355                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3356                                         g_assert (arm_is_imm12 (doffset));
3357                                         ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
3358                                         soffset += sizeof (gpointer);
3359                                         doffset += sizeof (gpointer);
3360                                 }
3361                                 if (ainfo->vtsize) {
3362                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3363                                         //g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
3364                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
3365                                 }
3366                         } else if (ainfo->regtype == RegTypeStructByAddr) {
3367                                 g_assert_not_reached ();
3368                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3369                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3370                         } else
3371                                 g_assert_not_reached ();
3372                 }
3373                 pos++;
3374         }
3375
3376         if (method->save_lmf) {
3377
3378                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3379                              (gpointer)"mono_get_lmf_addr");
3380                 code = emit_call_seq (cfg, code);
3381                 /* we build the MonoLMF structure on the stack - see mini-arm.h */
3382                 /* lmf_offset is the offset from the previous stack pointer,
3383                  * alloc_size is the total stack space allocated, so the offset
3384                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3385                  * The pointer to the struct is put in r1 (new_lmf).
3386                  * r2 is used as scratch
3387                  * The callee-saved registers are already in the MonoLMF structure
3388                  */
3389                 code = emit_big_add (code, ARMREG_R1, ARMREG_SP, alloc_size - lmf_offset);
3390                 /* r0 is the result from mono_get_lmf_addr () */
3391                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
3392                 /* new_lmf->previous_lmf = *lmf_addr */
3393                 ARM_LDR_IMM (code, ARMREG_R2, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3394                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3395                 /* *(lmf_addr) = r1 */
3396                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3397                 /* save method info */
3398                 code = mono_arm_emit_load_imm (code, ARMREG_R2, GPOINTER_TO_INT (method));
3399                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, method));
3400                 ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
3401                 /* save the current IP */
3402                 ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
3403                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
3404         }
3405
3406         if (tracing)
3407                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3408
3409         cfg->code_len = code - cfg->native_code;
3410         g_assert (cfg->code_len < cfg->code_size);
3411         g_free (cinfo);
3412
3413         return code;
3414 }
3415
3416 void
3417 mono_arch_emit_epilog (MonoCompile *cfg)
3418 {
3419         MonoMethod *method = cfg->method;
3420         int pos, i, rot_amount;
3421         int max_epilog_size = 16 + 20*4;
3422         guint8 *code;
3423
3424         if (cfg->method->save_lmf)
3425                 max_epilog_size += 128;
3426         
3427         if (mono_jit_trace_calls != NULL)
3428                 max_epilog_size += 50;
3429
3430         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3431                 max_epilog_size += 50;
3432
3433         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3434                 cfg->code_size *= 2;
3435                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3436                 mono_jit_stats.code_reallocs++;
3437         }
3438
3439         /*
3440          * Keep in sync with OP_JMP
3441          */
3442         code = cfg->native_code + cfg->code_len;
3443
3444         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
3445                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3446         }
3447         pos = 0;
3448
3449         if (method->save_lmf) {
3450                 int lmf_offset;
3451                 /* all but r0-r3, sp and pc */
3452                 pos += sizeof (MonoLMF) - (4 * 10);
3453                 lmf_offset = pos;
3454                 /* r2 contains the pointer to the current LMF */
3455                 code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, cfg->stack_usage - lmf_offset);
3456                 /* ip = previous_lmf */
3457                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3458                 /* lr = lmf_addr */
3459                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
3460                 /* *(lmf_addr) = previous_lmf */
3461                 ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3462                 /* FIXME: speedup: there is no actual need to restore the registers if
3463                  * we didn't actually change them (idea from Zoltan).
3464                  */
3465                 /* restore iregs */
3466                 /* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
3467                 ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_R2, (sizeof (MonoLMF) - 10 * sizeof (gulong)));
3468                 ARM_POP_NWB (code, 0xaff0); /* restore ip to sp and lr to pc */
3469         } else {
3470                 if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
3471                         ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
3472                 } else {
3473                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage);
3474                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
3475                 }
3476                 /* FIXME: add v4 thumb interworking support */
3477                 ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP) | (1 << ARMREG_PC)));
3478         }
3479
3480         cfg->code_len = code - cfg->native_code;
3481
3482         g_assert (cfg->code_len < cfg->code_size);
3483
3484 }
3485
3486 /* remove once throw_exception_by_name is eliminated */
3487 static int
3488 exception_id_by_name (const char *name)
3489 {
3490         if (strcmp (name, "IndexOutOfRangeException") == 0)
3491                 return MONO_EXC_INDEX_OUT_OF_RANGE;
3492         if (strcmp (name, "OverflowException") == 0)
3493                 return MONO_EXC_OVERFLOW;
3494         if (strcmp (name, "ArithmeticException") == 0)
3495                 return MONO_EXC_ARITHMETIC;
3496         if (strcmp (name, "DivideByZeroException") == 0)
3497                 return MONO_EXC_DIVIDE_BY_ZERO;
3498         if (strcmp (name, "InvalidCastException") == 0)
3499                 return MONO_EXC_INVALID_CAST;
3500         if (strcmp (name, "NullReferenceException") == 0)
3501                 return MONO_EXC_NULL_REF;
3502         if (strcmp (name, "ArrayTypeMismatchException") == 0)
3503                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3504         g_error ("Unknown intrinsic exception %s\n", name);
3505         return -1;
3506 }
3507
3508 void
3509 mono_arch_emit_exceptions (MonoCompile *cfg)
3510 {
3511         MonoJumpInfo *patch_info;
3512         int i;
3513         guint8 *code;
3514         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3515         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3516         int max_epilog_size = 50;
3517
3518         /* count the number of exception infos */
3519      
3520         /* 
3521          * make sure we have enough space for exceptions
3522          * 12 is the simulated call to throw_exception_by_name
3523          */
3524         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3525                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3526                         i = exception_id_by_name (patch_info->data.target);
3527                         if (!exc_throw_found [i]) {
3528                                 max_epilog_size += 12;
3529                                 exc_throw_found [i] = TRUE;
3530                         }
3531                 }
3532         }
3533
3534         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3535                 cfg->code_size *= 2;
3536                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3537                 mono_jit_stats.code_reallocs++;
3538         }
3539
3540         code = cfg->native_code + cfg->code_len;
3541
3542         /* add code to raise exceptions */
3543         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3544                 switch (patch_info->type) {
3545                 case MONO_PATCH_INFO_EXC: {
3546                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3547                         const char *ex_name = patch_info->data.target;
3548                         i = exception_id_by_name (patch_info->data.target);
3549                         if (exc_throw_pos [i]) {
3550                                 arm_patch (ip, exc_throw_pos [i]);
3551                                 patch_info->type = MONO_PATCH_INFO_NONE;
3552                                 break;
3553                         } else {
3554                                 exc_throw_pos [i] = code;
3555                         }
3556                         arm_patch (ip, code);
3557                         //*(int*)code = 0xef9f0001;
3558                         //code += 4;
3559                         ARM_NOP (code);
3560                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3561                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
3562                         /* we got here from a conditional call, so the calling ip is set in lr already */
3563                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3564                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3565                         patch_info->ip.i = code - cfg->native_code;
3566                         ARM_B (code, 0);
3567                         *(gconstpointer*)code = ex_name;
3568                         code += 4;
3569                         break;
3570                 }
3571                 default:
3572                         /* do nothing */
3573                         break;
3574                 }
3575         }
3576
3577         cfg->code_len = code - cfg->native_code;
3578
3579         g_assert (cfg->code_len < cfg->code_size);
3580
3581 }
3582
3583 void
3584 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3585 {
3586 }
3587
3588 void
3589 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3590 {
3591 }
3592
3593 void
3594 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3595 {
3596         
3597         int this_dreg = ARMREG_R0;
3598         
3599         if (vt_reg != -1)
3600                 this_dreg = ARMREG_R1;
3601
3602         /* add the this argument */
3603         if (this_reg != -1) {
3604                 MonoInst *this;
3605                 MONO_INST_NEW (cfg, this, OP_MOVE);
3606                 this->type = this_type;
3607                 this->sreg1 = this_reg;
3608                 this->dreg = mono_regstate_next_int (cfg->rs);
3609                 mono_bblock_add_inst (cfg->cbb, this);
3610                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3611         }
3612
3613         if (vt_reg != -1) {
3614                 MonoInst *vtarg;
3615                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
3616                 vtarg->type = STACK_MP;
3617                 vtarg->sreg1 = vt_reg;
3618                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3619                 mono_bblock_add_inst (cfg->cbb, vtarg);
3620                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ARMREG_R0, FALSE);
3621         }
3622 }
3623
3624 MonoInst*
3625 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3626 {
3627         return NULL;
3628 }
3629
3630 gboolean
3631 mono_arch_print_tree (MonoInst *tree, int arity)
3632 {
3633         return 0;
3634 }
3635
3636 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3637 {
3638         return NULL;
3639 }
3640
3641 MonoInst* 
3642 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3643 {
3644         return NULL;
3645 }
3646
3647 guint32
3648 mono_arch_get_patch_offset (guint8 *code)
3649 {
3650         /* OP_AOTCONST */
3651         return 8;
3652 }
3653
3654 void
3655 mono_arch_flush_register_windows (void)
3656 {
3657 }
3658
3659 void
3660 mono_arch_fixup_jinfo (MonoCompile *cfg)
3661 {
3662         /* max encoded stack usage is 64KB * 4 */
3663         g_assert ((cfg->stack_usage & ~(0xffff << 2)) == 0);
3664         cfg->jit_info->used_regs |= cfg->stack_usage << 14;
3665 }
3666
3667 #ifdef MONO_ARCH_HAVE_IMT
3668
3669 void
3670 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
3671 {
3672 }
3673
3674 MonoMethod*
3675 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
3676 {
3677         guint32 *code_ptr = (guint32*)code;
3678         code_ptr -= 2;
3679         /* The IMT value is stored in the code stream right after the LDC instruction. */
3680         if (!IS_LDR_PC (code_ptr [0])) {
3681                 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]);
3682                 g_assert (IS_LDR_PC (code_ptr [0]));
3683         }
3684         return (MonoMethod*) code_ptr [1];
3685 }
3686
3687 MonoObject*
3688 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method)
3689 {
3690         return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
3691 }
3692
3693
3694 #define ENABLE_WRONG_METHOD_CHECK 0
3695 #define BASE_SIZE (4 * 4)
3696 #define BSEARCH_ENTRY_SIZE (4 * 4)
3697 #define CMP_SIZE (3 * 4)
3698 #define BRANCH_SIZE (1 * 4)
3699 #define CALL_SIZE (2 * 4)
3700 #define WMC_SIZE (5 * 4)
3701 #define DISTANCE(A, B) (((gint32)(B)) - ((gint32)(A)))
3702
3703 static arminstr_t *
3704 arm_emit_value_and_patch_ldr (arminstr_t *code, arminstr_t *target, guint32 value)
3705 {
3706         guint32 delta = DISTANCE (target, code);
3707         delta -= 8;
3708         g_assert (delta >= 0 && delta <= 0xFFF);
3709         *target = *target | delta;
3710         *code = value;
3711         return code + 1;
3712 }
3713
3714 gpointer
3715 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
3716 {
3717         int size, i, extra_space = 0;
3718         arminstr_t *code, *start, *vtable_target = NULL;
3719         size = BASE_SIZE;
3720
3721         for (i = 0; i < count; ++i) {
3722                 MonoIMTCheckItem *item = imt_entries [i];
3723                 if (item->is_equals) {
3724                         g_assert (arm_is_imm12 (DISTANCE (vtable, &vtable->vtable[item->vtable_slot])));
3725
3726                         if (item->check_target_idx) {
3727                                 if (!item->compare_done)
3728                                         item->chunk_size += CMP_SIZE;
3729                                 item->chunk_size += BRANCH_SIZE;
3730                         } else {
3731 #if ENABLE_WRONG_METHOD_CHECK
3732                                 item->chunk_size += WMC_SIZE;
3733 #endif
3734                         }
3735                         item->chunk_size += CALL_SIZE;
3736                 } else {
3737                         item->chunk_size += BSEARCH_ENTRY_SIZE;
3738                         imt_entries [item->check_target_idx]->compare_done = TRUE;
3739                 }
3740                 size += item->chunk_size;
3741         }
3742
3743         start = code = mono_code_manager_reserve (domain->code_mp, size);
3744
3745 #if DEBUG_IMT
3746         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);
3747         for (i = 0; i < count; ++i) {
3748                 MonoIMTCheckItem *item = imt_entries [i];
3749                 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);
3750         }
3751 #endif
3752
3753         ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
3754         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
3755         vtable_target = code;
3756         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
3757
3758         for (i = 0; i < count; ++i) {
3759                 MonoIMTCheckItem *item = imt_entries [i];
3760                 arminstr_t *imt_method = NULL;
3761                 item->code_target = (guint8*)code;
3762
3763                 if (item->is_equals) {
3764                         if (item->check_target_idx) {
3765                                 if (!item->compare_done) {
3766                                         imt_method = code;
3767                                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
3768                                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
3769                                 }
3770                                 item->jmp_code = (guint8*)code;
3771                                 ARM_B_COND (code, ARMCOND_NE, 0);
3772
3773                                 ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
3774                                 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, DISTANCE (vtable, &vtable->vtable[item->vtable_slot]));
3775                         } else {
3776                                 /*Enable the commented code to assert on wrong method*/
3777 #if ENABLE_WRONG_METHOD_CHECK
3778                                 imt_method = code;
3779                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
3780                                 ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
3781                                 ARM_B_COND (code, ARMCOND_NE, 1);
3782 #endif
3783                                 ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
3784                                 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, DISTANCE (vtable, &vtable->vtable[item->vtable_slot]));
3785
3786 #if ENABLE_WRONG_METHOD_CHECK
3787                                 ARM_DBRK (code);
3788 #endif
3789                         }
3790
3791                         if (imt_method)
3792                                 code = arm_emit_value_and_patch_ldr (code, imt_method, (guint32)item->method);
3793
3794                         /*must emit after unconditional branch*/
3795                         if (vtable_target) {
3796                                 code = arm_emit_value_and_patch_ldr (code, vtable_target, (guint32)vtable);
3797                                 item->chunk_size += 4;
3798                                 vtable_target = NULL;
3799                         }
3800
3801                         /*We reserve the space for bsearch IMT values after the first entry with an absolute jump*/
3802                         if (extra_space) {
3803                                 code += extra_space;
3804                                 extra_space = 0;
3805                         }
3806                 } else {
3807                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
3808                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
3809
3810                         item->jmp_code = (guint8*)code;
3811                         ARM_B_COND (code, ARMCOND_GE, 0);
3812                         ++extra_space;
3813                 }
3814         }
3815
3816         for (i = 0; i < count; ++i) {
3817                 MonoIMTCheckItem *item = imt_entries [i];
3818                 if (item->jmp_code) {
3819                         if (item->check_target_idx)
3820                                 arm_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
3821                 }
3822                 if (i > 0 && item->is_equals) {
3823                         int j;
3824                         arminstr_t *space_start = (arminstr_t*)(item->code_target + item->chunk_size);
3825                         for (j = i - 1; j >= 0 && !imt_entries [j]->is_equals; --j) {
3826                                 space_start = arm_emit_value_and_patch_ldr (space_start, (arminstr_t*)imt_entries [j]->code_target, (guint32)imt_entries [j]->method);
3827                         }
3828                 }
3829         }
3830
3831 #if DEBUG_IMT
3832         {
3833                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
3834                 mono_disassemble_code (NULL, (guint8*)start, size, buff);
3835                 g_free (buff);
3836         }
3837 #endif
3838
3839         mono_arch_flush_icache ((guint8*)start, size);
3840         mono_stats.imt_thunks_size += code - start;
3841
3842         g_assert (DISTANCE (start, code) <= size);
3843         return start;
3844 }
3845
3846 #endif
3847
3848