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