2008-07-28 Marek Habersack <mhabersack@novell.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 #if ARM_PORT
3424                         guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
3425                         // Check if its negative
3426                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
3427                         negative_branch = code;
3428                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
3429                         // Its positive msword == 0
3430                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
3431                         msword_positive_branch = code;
3432                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
3433
3434                         ovf_ex_target = code;
3435                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
3436                         // Negative
3437                         ppc_patch (negative_branch, code);
3438                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
3439                         msword_negative_branch = code;
3440                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
3441                         ppc_patch (msword_negative_branch, ovf_ex_target);
3442                         
3443                         ppc_patch (msword_positive_branch, code);
3444                         if (ins->dreg != ins->sreg1)
3445                                 ppc_mr (code, ins->dreg, ins->sreg1);
3446 #endif
3447                         if (ins->dreg != ins->sreg1)
3448                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
3449                         break;
3450                 }
3451 #ifdef ARM_FPU_FPA
3452                 case OP_FADD:
3453                         ARM_FPA_ADFD (code, ins->dreg, ins->sreg1, ins->sreg2);
3454                         break;
3455                 case OP_FSUB:
3456                         ARM_FPA_SUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
3457                         break;          
3458                 case OP_FMUL:
3459                         ARM_FPA_MUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
3460                         break;          
3461                 case OP_FDIV:
3462                         ARM_FPA_DVFD (code, ins->dreg, ins->sreg1, ins->sreg2);
3463                         break;          
3464                 case OP_FNEG:
3465                         ARM_MNFD (code, ins->dreg, ins->sreg1);
3466                         break;
3467 #elif defined(ARM_FPU_VFP)
3468                 case OP_FADD:
3469                         ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2);
3470                         break;
3471                 case OP_FSUB:
3472                         ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2);
3473                         break;          
3474                 case OP_FMUL:
3475                         ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2);
3476                         break;          
3477                 case OP_FDIV:
3478                         ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2);
3479                         break;          
3480                 case OP_FNEG:
3481                         ARM_NEGD (code, ins->dreg, ins->sreg1);
3482                         break;
3483 #endif
3484                 case OP_FREM:
3485                         /* emulated */
3486                         g_assert_not_reached ();
3487                         break;
3488                 case OP_FCOMPARE:
3489 #ifdef ARM_FPU_FPA
3490                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3491 #elif defined(ARM_FPU_VFP)
3492                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3493 #endif
3494                         break;
3495                 case OP_FCEQ:
3496 #ifdef ARM_FPU_FPA
3497                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3498 #elif defined(ARM_FPU_VFP)
3499                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3500 #endif
3501                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
3502                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
3503                         break;
3504                 case OP_FCLT:
3505 #ifdef ARM_FPU_FPA
3506                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3507 #elif defined(ARM_FPU_VFP)
3508                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3509 #endif
3510                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3511                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
3512                         break;
3513                 case OP_FCLT_UN:
3514 #ifdef ARM_FPU_FPA
3515                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
3516 #elif defined(ARM_FPU_VFP)
3517                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
3518 #endif
3519                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3520                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
3521                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
3522                         break;
3523                 case OP_FCGT:
3524                         /* swapped */
3525 #ifdef ARM_FPU_FPA
3526                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3527 #elif defined(ARM_FPU_VFP)
3528                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3529 #endif
3530                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3531                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
3532                         break;
3533                 case OP_FCGT_UN:
3534                         /* swapped */
3535 #ifdef ARM_FPU_FPA
3536                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
3537 #elif defined(ARM_FPU_VFP)
3538                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
3539 #endif
3540                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3541                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
3542                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
3543                         break;
3544                 /* ARM FPA flags table:
3545                  * N        Less than               ARMCOND_MI
3546                  * Z        Equal                   ARMCOND_EQ
3547                  * C        Greater Than or Equal   ARMCOND_CS
3548                  * V        Unordered               ARMCOND_VS
3549                  */
3550                 case OP_FBEQ:
3551                         EMIT_COND_BRANCH (ins, OP_IBEQ - OP_IBEQ);
3552                         break;
3553                 case OP_FBNE_UN:
3554                         EMIT_COND_BRANCH (ins, OP_IBNE_UN - OP_IBEQ);
3555                         break;
3556                 case OP_FBLT:
3557                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
3558                         break;
3559                 case OP_FBLT_UN:
3560                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
3561                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
3562                         break;
3563                 case OP_FBGT:
3564                 case OP_FBGT_UN:
3565                 case OP_FBLE:
3566                 case OP_FBLE_UN:
3567                         g_assert_not_reached ();
3568                         break;
3569                 case OP_FBGE:
3570                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
3571                         break;
3572                 case OP_FBGE_UN:
3573                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
3574                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
3575                         break;
3576
3577                 case OP_CKFINITE: {
3578 #ifdef ARM_FPU_FPA
3579                         if (ins->dreg != ins->sreg1)
3580                                 ARM_MVFD (code, ins->dreg, ins->sreg1);
3581 #else
3582                         g_assert_not_reached ();
3583 #endif
3584                         break;
3585                 }
3586                 default:
3587                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
3588                         g_assert_not_reached ();
3589                 }
3590
3591                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
3592                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3593                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3594                         g_assert_not_reached ();
3595                 }
3596                
3597                 cpos += max_len;
3598
3599                 last_ins = ins;
3600                 last_offset = offset;
3601         }
3602
3603         cfg->code_len = code - cfg->native_code;
3604 }
3605
3606 void
3607 mono_arch_register_lowlevel_calls (void)
3608 {
3609 }
3610
3611 #define patch_lis_ori(ip,val) do {\
3612                 guint16 *__lis_ori = (guint16*)(ip);    \
3613                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
3614                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
3615         } while (0)
3616
3617 void
3618 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3619 {
3620         MonoJumpInfo *patch_info;
3621         gboolean compile_aot = !run_cctors;
3622
3623         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3624                 unsigned char *ip = patch_info->ip.i + code;
3625                 const unsigned char *target;
3626
3627                 if (patch_info->type == MONO_PATCH_INFO_SWITCH && !compile_aot) {
3628                         gpointer *jt = (gpointer*)(ip + 8);
3629                         int i;
3630                         /* jt is the inlined jump table, 2 instructions after ip
3631                          * In the normal case we store the absolute addresses,
3632                          * otherwise the displacements.
3633                          */
3634                         for (i = 0; i < patch_info->data.table->table_size; i++)
3635                                 jt [i] = code + (int)patch_info->data.table->table [i];
3636                         continue;
3637                 }
3638                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3639
3640                 if (compile_aot) {
3641                         switch (patch_info->type) {
3642                         case MONO_PATCH_INFO_BB:
3643                         case MONO_PATCH_INFO_LABEL:
3644                                 break;
3645                         default:
3646                                 /* No need to patch these */
3647                                 continue;
3648                         }
3649                 }
3650
3651                 switch (patch_info->type) {
3652                 case MONO_PATCH_INFO_IP:
3653                         g_assert_not_reached ();
3654                         patch_lis_ori (ip, ip);
3655                         continue;
3656                 case MONO_PATCH_INFO_METHOD_REL:
3657                         g_assert_not_reached ();
3658                         *((gpointer *)(ip)) = code + patch_info->data.offset;
3659                         continue;
3660                 case MONO_PATCH_INFO_METHODCONST:
3661                 case MONO_PATCH_INFO_CLASS:
3662                 case MONO_PATCH_INFO_IMAGE:
3663                 case MONO_PATCH_INFO_FIELD:
3664                 case MONO_PATCH_INFO_VTABLE:
3665                 case MONO_PATCH_INFO_IID:
3666                 case MONO_PATCH_INFO_SFLDA:
3667                 case MONO_PATCH_INFO_LDSTR:
3668                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
3669                 case MONO_PATCH_INFO_LDTOKEN:
3670                         g_assert_not_reached ();
3671                         /* from OP_AOTCONST : lis + ori */
3672                         patch_lis_ori (ip, target);
3673                         continue;
3674                 case MONO_PATCH_INFO_R4:
3675                 case MONO_PATCH_INFO_R8:
3676                         g_assert_not_reached ();
3677                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
3678                         continue;
3679                 case MONO_PATCH_INFO_EXC_NAME:
3680                         g_assert_not_reached ();
3681                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
3682                         continue;
3683                 case MONO_PATCH_INFO_NONE:
3684                 case MONO_PATCH_INFO_BB_OVF:
3685                 case MONO_PATCH_INFO_EXC_OVF:
3686                         /* everything is dealt with at epilog output time */
3687                         continue;
3688                 default:
3689                         break;
3690                 }
3691                 arm_patch (ip, target);
3692         }
3693 }
3694
3695 /*
3696  * Stack frame layout:
3697  * 
3698  *   ------------------- fp
3699  *      MonoLMF structure or saved registers
3700  *   -------------------
3701  *      locals
3702  *   -------------------
3703  *      spilled regs
3704  *   -------------------
3705  *      optional 8 bytes for tracing
3706  *   -------------------
3707  *      param area             size is cfg->param_area
3708  *   ------------------- sp
3709  */
3710 guint8 *
3711 mono_arch_emit_prolog (MonoCompile *cfg)
3712 {
3713         MonoMethod *method = cfg->method;
3714         MonoBasicBlock *bb;
3715         MonoMethodSignature *sig;
3716         MonoInst *inst;
3717         int alloc_size, pos, max_offset, i, rot_amount;
3718         guint8 *code;
3719         CallInfo *cinfo;
3720         int tracing = 0;
3721         int lmf_offset = 0;
3722         int prev_sp_offset;
3723
3724         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3725                 tracing = 1;
3726
3727         sig = mono_method_signature (method);
3728         cfg->code_size = 256 + sig->param_count * 20;
3729         code = cfg->native_code = g_malloc (cfg->code_size);
3730
3731         ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
3732
3733         alloc_size = cfg->stack_offset;
3734         pos = 0;
3735
3736         if (!method->save_lmf) {
3737                 ARM_PUSH (code, (cfg->used_int_regs | (1 << ARMREG_IP) | (1 << ARMREG_LR)));
3738                 prev_sp_offset = 8; /* ip and lr */
3739                 for (i = 0; i < 16; ++i) {
3740                         if (cfg->used_int_regs & (1 << i))
3741                                 prev_sp_offset += 4;
3742                 }
3743         } else {
3744                 ARM_PUSH (code, 0x5ff0);
3745                 prev_sp_offset = 4 * 10; /* all but r0-r3, sp and pc */
3746                 pos += sizeof (MonoLMF) - prev_sp_offset;
3747                 lmf_offset = pos;
3748         }
3749         alloc_size += pos;
3750         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
3751         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
3752                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
3753                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
3754         }
3755
3756         /* the stack used in the pushed regs */
3757         if (prev_sp_offset & 4)
3758                 alloc_size += 4;
3759         cfg->stack_usage = alloc_size;
3760         if (alloc_size) {
3761                 if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
3762                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
3763                 } else {
3764                         code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
3765                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
3766                 }
3767         }
3768         if (cfg->frame_reg != ARMREG_SP)
3769                 ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
3770         //g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
3771         prev_sp_offset += alloc_size;
3772
3773         /* compute max_offset in order to use short forward jumps
3774          * we could skip do it on arm because the immediate displacement
3775          * for jumps is large enough, it may be useful later for constant pools
3776          */
3777         max_offset = 0;
3778         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3779                 MonoInst *ins = bb->code;
3780                 bb->max_offset = max_offset;
3781
3782                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3783                         max_offset += 6; 
3784
3785                 MONO_BB_FOR_EACH_INS (bb, ins)
3786                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3787         }
3788
3789         /* load arguments allocated to register from the stack */
3790         pos = 0;
3791
3792         cinfo = calculate_sizes (sig, sig->pinvoke);
3793
3794         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
3795                 ArgInfo *ainfo = &cinfo->ret;
3796                 inst = cfg->vret_addr;
3797                 g_assert (arm_is_imm12 (inst->inst_offset));
3798                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3799         }
3800         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3801                 ArgInfo *ainfo = cinfo->args + i;
3802                 inst = cfg->args [pos];
3803                 
3804                 if (cfg->verbose_level > 2)
3805                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
3806                 if (inst->opcode == OP_REGVAR) {
3807                         if (ainfo->regtype == RegTypeGeneral)
3808                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
3809                         else if (ainfo->regtype == RegTypeFP) {
3810                                 g_assert_not_reached ();
3811                         } else if (ainfo->regtype == RegTypeBase) {
3812                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
3813                                         ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3814                                 } else {
3815                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3816                                         ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
3817                                 }
3818                         } else
3819                                 g_assert_not_reached ();
3820
3821                         if (cfg->verbose_level > 2)
3822                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3823                 } else {
3824                         /* the argument should be put on the stack: FIXME handle size != word  */
3825                         if (ainfo->regtype == RegTypeGeneral) {
3826                                 switch (ainfo->size) {
3827                                 case 1:
3828                                         if (arm_is_imm12 (inst->inst_offset))
3829                                                 ARM_STRB_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3830                                         else {
3831                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3832                                                 ARM_STRB_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
3833                                         }
3834                                         break;
3835                                 case 2:
3836                                         if (arm_is_imm8 (inst->inst_offset)) {
3837                                                 ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3838                                         } else {
3839                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3840                                                 ARM_STRH_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
3841                                         }
3842                                         break;
3843                                 case 8:
3844                                         g_assert (arm_is_imm12 (inst->inst_offset));
3845                                         ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3846                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
3847                                         ARM_STR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
3848                                         break;
3849                                 default:
3850                                         if (arm_is_imm12 (inst->inst_offset)) {
3851                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
3852                                         } else {
3853                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3854                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
3855                                         }
3856                                         break;
3857                                 }
3858                         } else if (ainfo->regtype == RegTypeBaseGen) {
3859                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
3860                                 g_assert (arm_is_imm12 (inst->inst_offset));
3861                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3862                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
3863                                 ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset);
3864                         } else if (ainfo->regtype == RegTypeBase) {
3865                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
3866                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
3867                                 } else {
3868                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
3869                                         ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
3870                                 }
3871
3872                                 switch (ainfo->size) {
3873                                 case 1:
3874                                         if (arm_is_imm8 (inst->inst_offset)) {
3875                                                 ARM_STRB_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3876                                         } else {
3877                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3878                                                 ARM_STRB_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3879                                         }
3880                                         break;
3881                                 case 2:
3882                                         if (arm_is_imm8 (inst->inst_offset)) {
3883                                                 ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3884                                         } else {
3885                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3886                                                 ARM_STRH_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3887                                         }
3888                                         break;
3889                                 case 8:
3890                                         if (arm_is_imm12 (inst->inst_offset)) {
3891                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3892                                         } else {
3893                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3894                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3895                                         }
3896                                         if (arm_is_imm12 (prev_sp_offset + ainfo->offset + 4)) {
3897                                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset + 4));
3898                                         } else {
3899                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset + 4);
3900                                                 ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
3901                                         }
3902                                         if (arm_is_imm12 (inst->inst_offset + 4)) {
3903                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
3904                                         } else {
3905                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
3906                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3907                                         }
3908                                         break;
3909                                 default:
3910                                         if (arm_is_imm12 (inst->inst_offset)) {
3911                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
3912                                         } else {
3913                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
3914                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
3915                                         }
3916                                         break;
3917                                 }
3918                         } else if (ainfo->regtype == RegTypeFP) {
3919                                 g_assert_not_reached ();
3920                         } else if (ainfo->regtype == RegTypeStructByVal) {
3921                                 int doffset = inst->inst_offset;
3922                                 int soffset = 0;
3923                                 int cur_reg;
3924                                 int size = 0;
3925                                 if (mono_class_from_mono_type (inst->inst_vtype))
3926                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3927                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3928                                         if (arm_is_imm12 (doffset)) {
3929                                                 ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
3930                                         } else {
3931                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
3932                                                 ARM_STR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
3933                                         }
3934                                         soffset += sizeof (gpointer);
3935                                         doffset += sizeof (gpointer);
3936                                 }
3937                                 if (ainfo->vtsize) {
3938                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3939                                         //g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
3940                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
3941                                 }
3942                         } else if (ainfo->regtype == RegTypeStructByAddr) {
3943                                 g_assert_not_reached ();
3944                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
3945                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
3946                         } else
3947                                 g_assert_not_reached ();
3948                 }
3949                 pos++;
3950         }
3951
3952         if (method->save_lmf) {
3953
3954                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3955                              (gpointer)"mono_get_lmf_addr");
3956                 code = emit_call_seq (cfg, code);
3957                 /* we build the MonoLMF structure on the stack - see mini-arm.h */
3958                 /* lmf_offset is the offset from the previous stack pointer,
3959                  * alloc_size is the total stack space allocated, so the offset
3960                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
3961                  * The pointer to the struct is put in r1 (new_lmf).
3962                  * r2 is used as scratch
3963                  * The callee-saved registers are already in the MonoLMF structure
3964                  */
3965                 code = emit_big_add (code, ARMREG_R1, ARMREG_SP, alloc_size - lmf_offset);
3966                 /* r0 is the result from mono_get_lmf_addr () */
3967                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
3968                 /* new_lmf->previous_lmf = *lmf_addr */
3969                 ARM_LDR_IMM (code, ARMREG_R2, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3970                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3971                 /* *(lmf_addr) = r1 */
3972                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3973                 /* Skip method (only needed for trampoline LMF frames) */
3974                 ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
3975                 /* save the current IP */
3976                 ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
3977                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
3978         }
3979
3980         if (tracing)
3981                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3982
3983         cfg->code_len = code - cfg->native_code;
3984         g_assert (cfg->code_len < cfg->code_size);
3985         g_free (cinfo);
3986
3987         return code;
3988 }
3989
3990 void
3991 mono_arch_emit_epilog (MonoCompile *cfg)
3992 {
3993         MonoMethod *method = cfg->method;
3994         int pos, i, rot_amount;
3995         int max_epilog_size = 16 + 20*4;
3996         guint8 *code;
3997
3998         if (cfg->method->save_lmf)
3999                 max_epilog_size += 128;
4000         
4001         if (mono_jit_trace_calls != NULL)
4002                 max_epilog_size += 50;
4003
4004         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4005                 max_epilog_size += 50;
4006
4007         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4008                 cfg->code_size *= 2;
4009                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4010                 mono_jit_stats.code_reallocs++;
4011         }
4012
4013         /*
4014          * Keep in sync with OP_JMP
4015          */
4016         code = cfg->native_code + cfg->code_len;
4017
4018         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4019                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4020         }
4021         pos = 0;
4022
4023         if (method->save_lmf) {
4024                 int lmf_offset;
4025                 /* all but r0-r3, sp and pc */
4026                 pos += sizeof (MonoLMF) - (4 * 10);
4027                 lmf_offset = pos;
4028                 /* r2 contains the pointer to the current LMF */
4029                 code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4030                 /* ip = previous_lmf */
4031                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
4032                 /* lr = lmf_addr */
4033                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
4034                 /* *(lmf_addr) = previous_lmf */
4035                 ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
4036                 /* FIXME: speedup: there is no actual need to restore the registers if
4037                  * we didn't actually change them (idea from Zoltan).
4038                  */
4039                 /* restore iregs */
4040                 /* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
4041                 ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_R2, (sizeof (MonoLMF) - 10 * sizeof (gulong)));
4042                 ARM_POP_NWB (code, 0xaff0); /* restore ip to sp and lr to pc */
4043         } else {
4044                 if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
4045                         ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
4046                 } else {
4047                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage);
4048                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
4049                 }
4050                 /* FIXME: add v4 thumb interworking support */
4051                 ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP) | (1 << ARMREG_PC)));
4052         }
4053
4054         cfg->code_len = code - cfg->native_code;
4055
4056         g_assert (cfg->code_len < cfg->code_size);
4057
4058 }
4059
4060 /* remove once throw_exception_by_name is eliminated */
4061 static int
4062 exception_id_by_name (const char *name)
4063 {
4064         if (strcmp (name, "IndexOutOfRangeException") == 0)
4065                 return MONO_EXC_INDEX_OUT_OF_RANGE;
4066         if (strcmp (name, "OverflowException") == 0)
4067                 return MONO_EXC_OVERFLOW;
4068         if (strcmp (name, "ArithmeticException") == 0)
4069                 return MONO_EXC_ARITHMETIC;
4070         if (strcmp (name, "DivideByZeroException") == 0)
4071                 return MONO_EXC_DIVIDE_BY_ZERO;
4072         if (strcmp (name, "InvalidCastException") == 0)
4073                 return MONO_EXC_INVALID_CAST;
4074         if (strcmp (name, "NullReferenceException") == 0)
4075                 return MONO_EXC_NULL_REF;
4076         if (strcmp (name, "ArrayTypeMismatchException") == 0)
4077                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4078         g_error ("Unknown intrinsic exception %s\n", name);
4079         return -1;
4080 }
4081
4082 void
4083 mono_arch_emit_exceptions (MonoCompile *cfg)
4084 {
4085         MonoJumpInfo *patch_info;
4086         int i;
4087         guint8 *code;
4088         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4089         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4090         int max_epilog_size = 50;
4091
4092         /* count the number of exception infos */
4093      
4094         /* 
4095          * make sure we have enough space for exceptions
4096          */
4097         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4098                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4099                         i = exception_id_by_name (patch_info->data.target);
4100                         if (!exc_throw_found [i]) {
4101                                 max_epilog_size += 32;
4102                                 exc_throw_found [i] = TRUE;
4103                         }
4104                 }
4105         }
4106
4107         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4108                 cfg->code_size *= 2;
4109                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4110                 mono_jit_stats.code_reallocs++;
4111         }
4112
4113         code = cfg->native_code + cfg->code_len;
4114
4115         /* add code to raise exceptions */
4116         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4117                 switch (patch_info->type) {
4118                 case MONO_PATCH_INFO_EXC: {
4119                         MonoClass *exc_class;
4120                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4121
4122                         i = exception_id_by_name (patch_info->data.target);
4123                         if (exc_throw_pos [i]) {
4124                                 arm_patch (ip, exc_throw_pos [i]);
4125                                 patch_info->type = MONO_PATCH_INFO_NONE;
4126                                 break;
4127                         } else {
4128                                 exc_throw_pos [i] = code;
4129                         }
4130                         arm_patch (ip, code);
4131
4132                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4133                         g_assert (exc_class);
4134
4135                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR);
4136                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
4137                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4138                         patch_info->data.name = "mono_arch_throw_corlib_exception";
4139                         patch_info->ip.i = code - cfg->native_code;
4140                         ARM_BL (code, 0);
4141                         *(guint32*)(gpointer)code = exc_class->type_token;
4142                         code += 4;
4143                         break;
4144                 }
4145                 default:
4146                         /* do nothing */
4147                         break;
4148                 }
4149         }
4150
4151         cfg->code_len = code - cfg->native_code;
4152
4153         g_assert (cfg->code_len < cfg->code_size);
4154
4155 }
4156
4157 void
4158 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4159 {
4160 }
4161
4162 void
4163 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4164 {
4165 }
4166
4167 void
4168 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4169 {
4170         
4171         int this_dreg = ARMREG_R0;
4172         
4173         if (vt_reg != -1)
4174                 this_dreg = ARMREG_R1;
4175
4176         /* add the this argument */
4177         if (this_reg != -1) {
4178                 MonoInst *this;
4179                 MONO_INST_NEW (cfg, this, OP_MOVE);
4180                 this->type = this_type;
4181                 this->sreg1 = this_reg;
4182                 this->dreg = mono_regstate_next_int (cfg->rs);
4183                 mono_bblock_add_inst (cfg->cbb, this);
4184                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
4185         }
4186
4187         if (vt_reg != -1) {
4188                 MonoInst *vtarg;
4189                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4190                 vtarg->type = STACK_MP;
4191                 vtarg->sreg1 = vt_reg;
4192                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
4193                 mono_bblock_add_inst (cfg->cbb, vtarg);
4194                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ARMREG_R0, FALSE);
4195         }
4196 }
4197
4198 MonoInst*
4199 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4200 {
4201         return NULL;
4202 }
4203
4204 MonoInst*
4205 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4206 {
4207         /* FIXME: */
4208         return NULL;
4209 }
4210
4211 gboolean
4212 mono_arch_print_tree (MonoInst *tree, int arity)
4213 {
4214         return 0;
4215 }
4216
4217 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4218 {
4219         return NULL;
4220 }
4221
4222 MonoInst* 
4223 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4224 {
4225         return NULL;
4226 }
4227
4228 guint32
4229 mono_arch_get_patch_offset (guint8 *code)
4230 {
4231         /* OP_AOTCONST */
4232         return 8;
4233 }
4234
4235 void
4236 mono_arch_flush_register_windows (void)
4237 {
4238 }
4239
4240 void
4241 mono_arch_fixup_jinfo (MonoCompile *cfg)
4242 {
4243         /* max encoded stack usage is 64KB * 4 */
4244         g_assert ((cfg->stack_usage & ~(0xffff << 2)) == 0);
4245         cfg->jit_info->used_regs |= cfg->stack_usage << 14;
4246 }
4247
4248 #ifdef MONO_ARCH_HAVE_IMT
4249
4250 void
4251 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call)
4252 {
4253         if (cfg->compile_aot) {
4254                 int method_reg = mono_regstate_next_int (cfg->rs);
4255                 MonoInst *ins;
4256
4257                 MONO_INST_NEW (cfg, ins, OP_AOTCONST);
4258                 ins->dreg = method_reg;
4259                 ins->inst_p0 = call->method;
4260                 ins->inst_c1 = MONO_PATCH_INFO_METHODCONST;
4261                 MONO_ADD_INS (cfg->cbb, ins);
4262
4263                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
4264         }
4265 }
4266
4267 MonoMethod*
4268 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4269 {
4270         guint32 *code_ptr = (guint32*)code;
4271         code_ptr -= 2;
4272         /* The IMT value is stored in the code stream right after the LDC instruction. */
4273         if (!IS_LDR_PC (code_ptr [0])) {
4274                 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]);
4275                 g_assert (IS_LDR_PC (code_ptr [0]));
4276         }
4277         if (code_ptr [1] == 0)
4278                 /* This is AOTed code, the IMT method is in V5 */
4279                 return (MonoMethod*)regs [ARMREG_V5];
4280         else
4281                 return (MonoMethod*) code_ptr [1];
4282 }
4283
4284 MonoObject*
4285 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4286 {
4287         return mono_arch_get_this_arg_from_call (gsctx, mono_method_signature (method), (gssize*)regs, NULL);
4288 }
4289
4290
4291 #define ENABLE_WRONG_METHOD_CHECK 0
4292 #define BASE_SIZE (6 * 4)
4293 #define BSEARCH_ENTRY_SIZE (4 * 4)
4294 #define CMP_SIZE (3 * 4)
4295 #define BRANCH_SIZE (1 * 4)
4296 #define CALL_SIZE (2 * 4)
4297 #define WMC_SIZE (5 * 4)
4298 #define DISTANCE(A, B) (((gint32)(B)) - ((gint32)(A)))
4299
4300 static arminstr_t *
4301 arm_emit_value_and_patch_ldr (arminstr_t *code, arminstr_t *target, guint32 value)
4302 {
4303         guint32 delta = DISTANCE (target, code);
4304         delta -= 8;
4305         g_assert (delta >= 0 && delta <= 0xFFF);
4306         *target = *target | delta;
4307         *code = value;
4308         return code + 1;
4309 }
4310
4311 gpointer
4312 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4313 {
4314         int size, i, extra_space = 0;
4315         arminstr_t *code, *start, *vtable_target = NULL;
4316         size = BASE_SIZE;
4317
4318         for (i = 0; i < count; ++i) {
4319                 MonoIMTCheckItem *item = imt_entries [i];
4320                 if (item->is_equals) {
4321                         g_assert (arm_is_imm12 (DISTANCE (vtable, &vtable->vtable[item->vtable_slot])));
4322
4323                         if (item->check_target_idx) {
4324                                 if (!item->compare_done)
4325                                         item->chunk_size += CMP_SIZE;
4326                                 item->chunk_size += BRANCH_SIZE;
4327                         } else {
4328 #if ENABLE_WRONG_METHOD_CHECK
4329                                 item->chunk_size += WMC_SIZE;
4330 #endif
4331                         }
4332                         item->chunk_size += CALL_SIZE;
4333                 } else {
4334                         item->chunk_size += BSEARCH_ENTRY_SIZE;
4335                         imt_entries [item->check_target_idx]->compare_done = TRUE;
4336                 }
4337                 size += item->chunk_size;
4338         }
4339
4340         start = code = mono_code_manager_reserve (domain->code_mp, size);
4341
4342 #if DEBUG_IMT
4343         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);
4344         for (i = 0; i < count; ++i) {
4345                 MonoIMTCheckItem *item = imt_entries [i];
4346                 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);
4347         }
4348 #endif
4349
4350         ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
4351         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
4352         vtable_target = code;
4353         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
4354
4355         /* R0 == 0 means we are called from AOT code. In this case, V5 contains the IMT method */
4356         ARM_CMP_REG_IMM8 (code, ARMREG_R0, 0);
4357         ARM_MOV_REG_REG_COND (code, ARMREG_R0, ARMREG_V5, ARMCOND_EQ);
4358
4359         for (i = 0; i < count; ++i) {
4360                 MonoIMTCheckItem *item = imt_entries [i];
4361                 arminstr_t *imt_method = NULL;
4362                 item->code_target = (guint8*)code;
4363
4364                 if (item->is_equals) {
4365                         if (item->check_target_idx) {
4366                                 if (!item->compare_done) {
4367                                         imt_method = code;
4368                                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
4369                                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
4370                                 }
4371                                 item->jmp_code = (guint8*)code;
4372                                 ARM_B_COND (code, ARMCOND_NE, 0);
4373
4374                                 ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
4375                                 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, DISTANCE (vtable, &vtable->vtable[item->vtable_slot]));
4376                         } else {
4377                                 /*Enable the commented code to assert on wrong method*/
4378 #if ENABLE_WRONG_METHOD_CHECK
4379                                 imt_method = code;
4380                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
4381                                 ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
4382                                 ARM_B_COND (code, ARMCOND_NE, 1);
4383 #endif
4384                                 ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
4385                                 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, DISTANCE (vtable, &vtable->vtable[item->vtable_slot]));
4386
4387 #if ENABLE_WRONG_METHOD_CHECK
4388                                 ARM_DBRK (code);
4389 #endif
4390                         }
4391
4392                         if (imt_method)
4393                                 code = arm_emit_value_and_patch_ldr (code, imt_method, (guint32)item->method);
4394
4395                         /*must emit after unconditional branch*/
4396                         if (vtable_target) {
4397                                 code = arm_emit_value_and_patch_ldr (code, vtable_target, (guint32)vtable);
4398                                 item->chunk_size += 4;
4399                                 vtable_target = NULL;
4400                         }
4401
4402                         /*We reserve the space for bsearch IMT values after the first entry with an absolute jump*/
4403                         if (extra_space) {
4404                                 code += extra_space;
4405                                 extra_space = 0;
4406                         }
4407                 } else {
4408                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
4409                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
4410
4411                         item->jmp_code = (guint8*)code;
4412                         ARM_B_COND (code, ARMCOND_GE, 0);
4413                         ++extra_space;
4414                 }
4415         }
4416
4417         for (i = 0; i < count; ++i) {
4418                 MonoIMTCheckItem *item = imt_entries [i];
4419                 if (item->jmp_code) {
4420                         if (item->check_target_idx)
4421                                 arm_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4422                 }
4423                 if (i > 0 && item->is_equals) {
4424                         int j;
4425                         arminstr_t *space_start = (arminstr_t*)(item->code_target + item->chunk_size);
4426                         for (j = i - 1; j >= 0 && !imt_entries [j]->is_equals; --j) {
4427                                 space_start = arm_emit_value_and_patch_ldr (space_start, (arminstr_t*)imt_entries [j]->code_target, (guint32)imt_entries [j]->method);
4428                         }
4429                 }
4430         }
4431
4432 #if DEBUG_IMT
4433         {
4434                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
4435                 mono_disassemble_code (NULL, (guint8*)start, size, buff);
4436                 g_free (buff);
4437         }
4438 #endif
4439
4440         mono_arch_flush_icache ((guint8*)start, size);
4441         mono_stats.imt_thunks_size += code - start;
4442
4443         g_assert (DISTANCE (start, code) <= size);
4444         return start;
4445 }
4446
4447 #endif
4448
4449 gpointer
4450 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4451 {
4452         /* FIXME: implement */
4453         g_assert_not_reached ();
4454 }