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