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