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