[MSBuild] Fix minor assembly resolution issue
[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  * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12 #include "mini.h"
13 #include <string.h>
14
15 #include <mono/metadata/abi-details.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/profiler-private.h>
18 #include <mono/metadata/debug-helpers.h>
19 #include <mono/utils/mono-mmap.h>
20 #include <mono/utils/mono-hwcap-arm.h>
21 #include <mono/utils/mono-memory-model.h>
22
23 #include "mini-arm.h"
24 #include "cpu-arm.h"
25 #include "trace.h"
26 #include "ir-emit.h"
27 #include "debugger-agent.h"
28 #include "mini-gc.h"
29 #include "mono/arch/arm/arm-vfp-codegen.h"
30
31 /* Sanity check: This makes no sense */
32 #if defined(ARM_FPU_NONE) && (defined(ARM_FPU_VFP) || defined(ARM_FPU_VFP_HARD))
33 #error "ARM_FPU_NONE is defined while one of ARM_FPU_VFP/ARM_FPU_VFP_HARD is defined"
34 #endif
35
36 /*
37  * IS_SOFT_FLOAT: Is full software floating point used?
38  * IS_HARD_FLOAT: Is full hardware floating point used?
39  * IS_VFP: Is hardware floating point with software ABI used?
40  *
41  * These are not necessarily constants, e.g. IS_SOFT_FLOAT and
42  * IS_VFP may delegate to mono_arch_is_soft_float ().
43  */
44
45 #if defined(ARM_FPU_VFP_HARD)
46 #define IS_SOFT_FLOAT (FALSE)
47 #define IS_HARD_FLOAT (TRUE)
48 #define IS_VFP (TRUE)
49 #elif defined(ARM_FPU_NONE)
50 #define IS_SOFT_FLOAT (mono_arch_is_soft_float ())
51 #define IS_HARD_FLOAT (FALSE)
52 #define IS_VFP (!mono_arch_is_soft_float ())
53 #else
54 #define IS_SOFT_FLOAT (FALSE)
55 #define IS_HARD_FLOAT (FALSE)
56 #define IS_VFP (TRUE)
57 #endif
58
59 #if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__)
60 #define HAVE_AEABI_READ_TP 1
61 #endif
62
63 #define THUNK_SIZE (3 * 4)
64
65 #ifdef __native_client_codegen__
66 const guint kNaClAlignment = kNaClAlignmentARM;
67 const guint kNaClAlignmentMask = kNaClAlignmentMaskARM;
68 gint8 nacl_align_byte = -1; /* 0xff */
69
70 guint8 *
71 mono_arch_nacl_pad (guint8 *code, int pad)
72 {
73   /* Not yet properly implemented. */
74   g_assert_not_reached ();
75   return code;
76 }
77
78 guint8 *
79 mono_arch_nacl_skip_nops (guint8 *code)
80 {
81   /* Not yet properly implemented. */
82   g_assert_not_reached ();
83   return code;
84 }
85
86 #endif /* __native_client_codegen__ */
87
88 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
89
90 #if __APPLE__
91 void sys_icache_invalidate (void *start, size_t len);
92 #endif
93
94 /* This mutex protects architecture specific caches */
95 #define mono_mini_arch_lock() mono_mutex_lock (&mini_arch_mutex)
96 #define mono_mini_arch_unlock() mono_mutex_unlock (&mini_arch_mutex)
97 static mono_mutex_t mini_arch_mutex;
98
99 static gboolean v5_supported = FALSE;
100 static gboolean v6_supported = FALSE;
101 static gboolean v7_supported = FALSE;
102 static gboolean v7s_supported = FALSE;
103 static gboolean thumb_supported = FALSE;
104 static gboolean thumb2_supported = FALSE;
105 /*
106  * Whenever to use the ARM EABI
107  */
108 static gboolean eabi_supported = FALSE;
109
110 /* 
111  * Whenever to use the iphone ABI extensions:
112  * http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/index.html
113  * Basically, r7 is used as a frame pointer and it should point to the saved r7 + lr.
114  * This is required for debugging/profiling tools to work, but it has some overhead so it should
115  * only be turned on in debug builds.
116  */
117 static gboolean iphone_abi = FALSE;
118
119 /*
120  * The FPU we are generating code for. This is NOT runtime configurable right now,
121  * since some things like MONO_ARCH_CALLEE_FREGS still depend on defines.
122  */
123 static MonoArmFPU arm_fpu;
124
125 #if defined(ARM_FPU_VFP_HARD)
126 /*
127  * On armhf, d0-d7 are used for argument passing and d8-d15
128  * must be preserved across calls, which leaves us no room
129  * for scratch registers. So we use d14-d15 but back up their
130  * previous contents to a stack slot before using them - see
131  * mono_arm_emit_vfp_scratch_save/_restore ().
132  */
133 static int vfp_scratch1 = ARM_VFP_D14;
134 static int vfp_scratch2 = ARM_VFP_D15;
135 #else
136 /*
137  * On armel, d0-d7 do not need to be preserved, so we can
138  * freely make use of them as scratch registers.
139  */
140 static int vfp_scratch1 = ARM_VFP_D0;
141 static int vfp_scratch2 = ARM_VFP_D1;
142 #endif
143
144 static int i8_align;
145
146 static volatile int ss_trigger_var = 0;
147
148 static gpointer single_step_tramp, breakpoint_tramp;
149
150 /*
151  * The code generated for sequence points reads from this location, which is
152  * made read-only when single stepping is enabled.
153  */
154 static gpointer ss_trigger_page;
155
156 /* Enabled breakpoints read from this trigger page */
157 static gpointer bp_trigger_page;
158
159 /*
160  * TODO:
161  * floating point support: on ARM it is a mess, there are at least 3
162  * different setups, each of which binary incompat with the other.
163  * 1) FPA: old and ugly, but unfortunately what current distros use
164  *    the double binary format has the two words swapped. 8 double registers.
165  *    Implemented usually by kernel emulation.
166  * 2) softfloat: the compiler emulates all the fp ops. Usually uses the
167  *    ugly swapped double format (I guess a softfloat-vfp exists, too, though).
168  * 3) VFP: the new and actually sensible and useful FP support. Implemented
169  *    in HW or kernel-emulated, requires new tools. I think this is what symbian uses.
170  *
171  * We do not care about FPA. We will support soft float and VFP.
172  */
173 int mono_exc_esp_offset = 0;
174
175 #define arm_is_imm12(v) ((v) > -4096 && (v) < 4096)
176 #define arm_is_imm8(v) ((v) > -256 && (v) < 256)
177 #define arm_is_fpimm8(v) ((v) >= -1020 && (v) <= 1020)
178
179 #define LDR_MASK ((0xf << ARMCOND_SHIFT) | (3 << 26) | (1 << 22) | (1 << 20) | (15 << 12))
180 #define LDR_PC_VAL ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 26) | (0 << 22) | (1 << 20) | (15 << 12))
181 #define IS_LDR_PC(val) (((val) & LDR_MASK) == LDR_PC_VAL)
182
183 //#define DEBUG_IMT 0
184
185 #ifndef DISABLE_JIT
186 static void mono_arch_compute_omit_fp (MonoCompile *cfg);
187 #endif
188
189 const char*
190 mono_arch_regname (int reg)
191 {
192         static const char * rnames[] = {
193                 "arm_r0", "arm_r1", "arm_r2", "arm_r3", "arm_v1",
194                 "arm_v2", "arm_v3", "arm_v4", "arm_v5", "arm_v6",
195                 "arm_v7", "arm_fp", "arm_ip", "arm_sp", "arm_lr",
196                 "arm_pc"
197         };
198         if (reg >= 0 && reg < 16)
199                 return rnames [reg];
200         return "unknown";
201 }
202
203 const char*
204 mono_arch_fregname (int reg)
205 {
206         static const char * rnames[] = {
207                 "arm_f0", "arm_f1", "arm_f2", "arm_f3", "arm_f4",
208                 "arm_f5", "arm_f6", "arm_f7", "arm_f8", "arm_f9",
209                 "arm_f10", "arm_f11", "arm_f12", "arm_f13", "arm_f14",
210                 "arm_f15", "arm_f16", "arm_f17", "arm_f18", "arm_f19",
211                 "arm_f20", "arm_f21", "arm_f22", "arm_f23", "arm_f24",
212                 "arm_f25", "arm_f26", "arm_f27", "arm_f28", "arm_f29",
213                 "arm_f30", "arm_f31"
214         };
215         if (reg >= 0 && reg < 32)
216                 return rnames [reg];
217         return "unknown";
218 }
219
220
221 #ifndef DISABLE_JIT
222 static guint8*
223 emit_big_add (guint8 *code, int dreg, int sreg, int imm)
224 {
225         int imm8, rot_amount;
226         if ((imm8 = mono_arm_is_rotated_imm8 (imm, &rot_amount)) >= 0) {
227                 ARM_ADD_REG_IMM (code, dreg, sreg, imm8, rot_amount);
228                 return code;
229         }
230         if (dreg == sreg) {
231                 code = mono_arm_emit_load_imm (code, ARMREG_IP, imm);
232                 ARM_ADD_REG_REG (code, dreg, sreg, ARMREG_IP);
233         } else {
234                 code = mono_arm_emit_load_imm (code, dreg, imm);
235                 ARM_ADD_REG_REG (code, dreg, dreg, sreg);
236         }
237         return code;
238 }
239
240 /* If dreg == sreg, this clobbers IP */
241 static guint8*
242 emit_sub_imm (guint8 *code, int dreg, int sreg, int imm)
243 {
244         int imm8, rot_amount;
245         if ((imm8 = mono_arm_is_rotated_imm8 (imm, &rot_amount)) >= 0) {
246                 ARM_SUB_REG_IMM (code, dreg, sreg, imm8, rot_amount);
247                 return code;
248         }
249         if (dreg == sreg) {
250                 code = mono_arm_emit_load_imm (code, ARMREG_IP, imm);
251                 ARM_SUB_REG_REG (code, dreg, sreg, ARMREG_IP);
252         } else {
253                 code = mono_arm_emit_load_imm (code, dreg, imm);
254                 ARM_SUB_REG_REG (code, dreg, dreg, sreg);
255         }
256         return code;
257 }
258
259 static guint8*
260 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
261 {
262         /* we can use r0-r3, since this is called only for incoming args on the stack */
263         if (size > sizeof (gpointer) * 4) {
264                 guint8 *start_loop;
265                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
266                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
267                 start_loop = code = mono_arm_emit_load_imm (code, ARMREG_R2, size);
268                 ARM_LDR_IMM (code, ARMREG_R3, ARMREG_R0, 0);
269                 ARM_STR_IMM (code, ARMREG_R3, ARMREG_R1, 0);
270                 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, 4);
271                 ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
272                 ARM_SUBS_REG_IMM8 (code, ARMREG_R2, ARMREG_R2, 4);
273                 ARM_B_COND (code, ARMCOND_NE, 0);
274                 arm_patch (code - 4, start_loop);
275                 return code;
276         }
277         if (arm_is_imm12 (doffset) && arm_is_imm12 (doffset + size) &&
278                         arm_is_imm12 (soffset) && arm_is_imm12 (soffset + size)) {
279                 while (size >= 4) {
280                         ARM_LDR_IMM (code, ARMREG_LR, sreg, soffset);
281                         ARM_STR_IMM (code, ARMREG_LR, dreg, doffset);
282                         doffset += 4;
283                         soffset += 4;
284                         size -= 4;
285                 }
286         } else if (size) {
287                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
288                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
289                 doffset = soffset = 0;
290                 while (size >= 4) {
291                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R0, soffset);
292                         ARM_STR_IMM (code, ARMREG_LR, ARMREG_R1, doffset);
293                         doffset += 4;
294                         soffset += 4;
295                         size -= 4;
296                 }
297         }
298         g_assert (size == 0);
299         return code;
300 }
301
302 static guint8*
303 emit_call_reg (guint8 *code, int reg)
304 {
305         if (v5_supported) {
306                 ARM_BLX_REG (code, reg);
307         } else {
308 #ifdef USE_JUMP_TABLES
309                 g_assert_not_reached ();
310 #endif
311                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
312                 if (thumb_supported)
313                         ARM_BX (code, reg);
314                 else
315                         ARM_MOV_REG_REG (code, ARMREG_PC, reg);
316         }
317         return code;
318 }
319
320 static guint8*
321 emit_call_seq (MonoCompile *cfg, guint8 *code)
322 {
323 #ifdef USE_JUMP_TABLES
324         code = mono_arm_patchable_bl (code, ARMCOND_AL);
325 #else
326         if (cfg->method->dynamic) {
327                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
328                 ARM_B (code, 0);
329                 *(gpointer*)code = NULL;
330                 code += 4;
331                 code = emit_call_reg (code, ARMREG_IP);
332         } else {
333                 ARM_BL (code, 0);
334         }
335         cfg->thunk_area += THUNK_SIZE;
336 #endif
337         return code;
338 }
339
340 guint8*
341 mono_arm_patchable_b (guint8 *code, int cond)
342 {
343 #ifdef USE_JUMP_TABLES
344         gpointer *jte;
345
346         jte = mono_jumptable_add_entry ();
347         code = mono_arm_load_jumptable_entry (code, jte, ARMREG_IP);
348         ARM_BX_COND (code, cond, ARMREG_IP);
349 #else
350         ARM_B_COND (code, cond, 0);
351 #endif
352         return code;
353 }
354
355 guint8*
356 mono_arm_patchable_bl (guint8 *code, int cond)
357 {
358 #ifdef USE_JUMP_TABLES
359         gpointer *jte;
360
361         jte = mono_jumptable_add_entry ();
362         code = mono_arm_load_jumptable_entry (code, jte,  ARMREG_IP);
363         ARM_BLX_REG_COND (code, cond, ARMREG_IP);
364 #else
365         ARM_BL_COND (code, cond, 0);
366 #endif
367         return code;
368 }
369
370 #ifdef USE_JUMP_TABLES
371 guint8*
372 mono_arm_load_jumptable_entry_addr (guint8 *code, gpointer *jte, ARMReg reg)
373 {
374         ARM_MOVW_REG_IMM (code, reg, GPOINTER_TO_UINT(jte) & 0xffff);
375         ARM_MOVT_REG_IMM (code, reg, (GPOINTER_TO_UINT(jte) >> 16) & 0xffff);
376         return code;
377 }
378
379 guint8*
380 mono_arm_load_jumptable_entry (guint8 *code, gpointer* jte, ARMReg reg)
381 {
382         code = mono_arm_load_jumptable_entry_addr (code, jte, reg);
383         ARM_LDR_IMM (code, reg, reg, 0);
384         return code;
385 }
386 #endif
387
388 /*
389  * emit_save_lmf:
390  *
391  *   Emit code to push an LMF structure on the LMF stack.
392  * On arm, this is intermixed with the initialization of other fields of the structure.
393  */
394 static guint8*
395 emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
396 {
397         gboolean get_lmf_fast = FALSE;
398         int i;
399
400 #ifdef HAVE_AEABI_READ_TP
401         gint32 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
402
403         if (lmf_addr_tls_offset != -1) {
404                 get_lmf_fast = TRUE;
405
406                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
407                                                          (gpointer)"__aeabi_read_tp");
408                 code = emit_call_seq (cfg, code);
409
410                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, lmf_addr_tls_offset);
411                 get_lmf_fast = TRUE;
412         }
413 #endif
414
415 #ifdef TARGET_IOS
416         if (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
417                 int lmf_offset;
418
419                 /* Inline mono_get_lmf_addr () */
420                 /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
421
422                 /* Load mono_jit_tls_id */
423                 /* OP_AOTCONST */
424                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_JIT_TLS_ID, NULL);
425                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
426                 ARM_B (code, 0);
427                 *(gpointer*)code = NULL;
428                 code += 4;
429                 ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
430                 /* call pthread_getspecific () */
431                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
432                                                          (gpointer)"pthread_getspecific");
433                 code = emit_call_seq (cfg, code);
434                 /* lmf_addr = &jit_tls->lmf */
435                 lmf_offset = MONO_STRUCT_OFFSET (MonoJitTlsData, lmf);
436                 g_assert (arm_is_imm8 (lmf_offset));
437                 ARM_ADD_REG_IMM (code, ARMREG_R0, ARMREG_R0, lmf_offset, 0);
438
439                 get_lmf_fast = TRUE;
440         }
441 #endif
442
443         if (!get_lmf_fast) {
444                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
445                                                          (gpointer)"mono_get_lmf_addr");
446                 code = emit_call_seq (cfg, code);
447         }
448         /* we build the MonoLMF structure on the stack - see mini-arm.h */
449         /* lmf_offset is the offset from the previous stack pointer,
450          * alloc_size is the total stack space allocated, so the offset
451          * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
452          * The pointer to the struct is put in r1 (new_lmf).
453          * ip is used as scratch
454          * The callee-saved registers are already in the MonoLMF structure
455          */
456         code = emit_big_add (code, ARMREG_R1, ARMREG_SP, lmf_offset);
457         /* r0 is the result from mono_get_lmf_addr () */
458         ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, lmf_addr));
459         /* new_lmf->previous_lmf = *lmf_addr */
460         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
461         ARM_STR_IMM (code, ARMREG_IP, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
462         /* *(lmf_addr) = r1 */
463         ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
464         /* Skip method (only needed for trampoline LMF frames) */
465         ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, sp));
466         ARM_STR_IMM (code, ARMREG_FP, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, fp));
467         /* save the current IP */
468         ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_PC);
469         ARM_STR_IMM (code, ARMREG_IP, ARMREG_R1, MONO_STRUCT_OFFSET (MonoLMF, ip));
470
471         for (i = 0; i < sizeof (MonoLMF); i += sizeof (mgreg_t))
472                 mini_gc_set_slot_type_from_fp (cfg, lmf_offset + i, SLOT_NOREF);
473
474         return code;
475 }
476
477 typedef struct {
478         gint32 vreg;
479         gint32 hreg;
480 } FloatArgData;
481
482 static guint8 *
483 emit_float_args (MonoCompile *cfg, MonoCallInst *inst, guint8 *code, int *max_len, guint *offset)
484 {
485         GSList *list;
486
487         g_assert (!cfg->r4fp);
488
489         for (list = inst->float_args; list; list = list->next) {
490                 FloatArgData *fad = list->data;
491                 MonoInst *var = get_vreg_to_inst (cfg, fad->vreg);
492                 gboolean imm = arm_is_fpimm8 (var->inst_offset);
493
494                 /* 4+1 insns for emit_big_add () and 1 for FLDS. */
495                 if (!imm)
496                         *max_len += 20 + 4;
497
498                 *max_len += 4;
499
500                 if (*offset + *max_len > cfg->code_size) {
501                         cfg->code_size += *max_len;
502                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
503
504                         code = cfg->native_code + *offset;
505                 }
506
507                 if (!imm) {
508                         code = emit_big_add (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
509                         ARM_FLDS (code, fad->hreg, ARMREG_LR, 0);
510                 } else
511                         ARM_FLDS (code, fad->hreg, var->inst_basereg, var->inst_offset);
512
513                 *offset = code - cfg->native_code;
514         }
515
516         return code;
517 }
518
519 static guint8 *
520 mono_arm_emit_vfp_scratch_save (MonoCompile *cfg, guint8 *code, int reg)
521 {
522         MonoInst *inst;
523
524         g_assert (reg == vfp_scratch1 || reg == vfp_scratch2);
525
526         inst = (MonoInst *) cfg->arch.vfp_scratch_slots [reg == vfp_scratch1 ? 0 : 1];
527
528         if (IS_HARD_FLOAT) {
529                 if (!arm_is_fpimm8 (inst->inst_offset)) {
530                         code = emit_big_add (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
531                         ARM_FSTD (code, reg, ARMREG_LR, 0);
532                 } else
533                         ARM_FSTD (code, reg, inst->inst_basereg, inst->inst_offset);
534         }
535
536         return code;
537 }
538
539 static guint8 *
540 mono_arm_emit_vfp_scratch_restore (MonoCompile *cfg, guint8 *code, int reg)
541 {
542         MonoInst *inst;
543
544         g_assert (reg == vfp_scratch1 || reg == vfp_scratch2);
545
546         inst = (MonoInst *) cfg->arch.vfp_scratch_slots [reg == vfp_scratch1 ? 0 : 1];
547
548         if (IS_HARD_FLOAT) {
549                 if (!arm_is_fpimm8 (inst->inst_offset)) {
550                         code = emit_big_add (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
551                         ARM_FLDD (code, reg, ARMREG_LR, 0);
552                 } else
553                         ARM_FLDD (code, reg, inst->inst_basereg, inst->inst_offset);
554         }
555
556         return code;
557 }
558
559 /*
560  * emit_restore_lmf:
561  *
562  *   Emit code to pop an LMF structure from the LMF stack.
563  */
564 static guint8*
565 emit_restore_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
566 {
567         int basereg, offset;
568
569         if (lmf_offset < 32) {
570                 basereg = cfg->frame_reg;
571                 offset = lmf_offset;
572         } else {
573                 basereg = ARMREG_R2;
574                 offset = 0;
575                 code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, lmf_offset);
576         }
577
578         /* ip = previous_lmf */
579         ARM_LDR_IMM (code, ARMREG_IP, basereg, offset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
580         /* lr = lmf_addr */
581         ARM_LDR_IMM (code, ARMREG_LR, basereg, offset + MONO_STRUCT_OFFSET (MonoLMF, lmf_addr));
582         /* *(lmf_addr) = previous_lmf */
583         ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
584
585         return code;
586 }
587
588 #endif /* #ifndef DISABLE_JIT */
589
590 /*
591  * mono_arch_get_argument_info:
592  * @csig:  a method signature
593  * @param_count: the number of parameters to consider
594  * @arg_info: an array to store the result infos
595  *
596  * Gathers information on parameters such as size, alignment and
597  * padding. arg_info should be large enought to hold param_count + 1 entries. 
598  *
599  * Returns the size of the activation frame.
600  */
601 int
602 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
603 {
604         int k, frame_size = 0;
605         guint32 size, align, pad;
606         int offset = 8;
607         MonoType *t;
608
609         t = mini_type_get_underlying_type (gsctx, csig->ret);
610         if (MONO_TYPE_ISSTRUCT (t)) {
611                 frame_size += sizeof (gpointer);
612                 offset += 4;
613         }
614
615         arg_info [0].offset = offset;
616
617         if (csig->hasthis) {
618                 frame_size += sizeof (gpointer);
619                 offset += 4;
620         }
621
622         arg_info [0].size = frame_size;
623
624         for (k = 0; k < param_count; k++) {
625                 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
626
627                 /* ignore alignment for now */
628                 align = 1;
629
630                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
631                 arg_info [k].pad = pad;
632                 frame_size += size;
633                 arg_info [k + 1].pad = 0;
634                 arg_info [k + 1].size = size;
635                 offset += pad;
636                 arg_info [k + 1].offset = offset;
637                 offset += size;
638         }
639
640         align = MONO_ARCH_FRAME_ALIGNMENT;
641         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
642         arg_info [k].pad = pad;
643
644         return frame_size;
645 }
646
647 #define MAX_ARCH_DELEGATE_PARAMS 3
648
649 static gpointer
650 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
651 {
652         guint8 *code, *start;
653
654         if (has_target) {
655                 start = code = mono_global_codeman_reserve (12);
656
657                 /* Replace the this argument with the target */
658                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
659                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, target));
660                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
661
662                 g_assert ((code - start) <= 12);
663
664                 mono_arch_flush_icache (start, 12);
665         } else {
666                 int size, i;
667
668                 size = 8 + param_count * 4;
669                 start = code = mono_global_codeman_reserve (size);
670
671                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
672                 /* slide down the arguments */
673                 for (i = 0; i < param_count; ++i) {
674                         ARM_MOV_REG_REG (code, (ARMREG_R0 + i), (ARMREG_R0 + i + 1));
675                 }
676                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
677
678                 g_assert ((code - start) <= size);
679
680                 mono_arch_flush_icache (start, size);
681         }
682
683         mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL);
684         if (code_size)
685                 *code_size = code - start;
686
687         return start;
688 }
689
690 /*
691  * mono_arch_get_delegate_invoke_impls:
692  *
693  *   Return a list of MonoAotTrampInfo structures for the delegate invoke impl
694  * trampolines.
695  */
696 GSList*
697 mono_arch_get_delegate_invoke_impls (void)
698 {
699         GSList *res = NULL;
700         guint8 *code;
701         guint32 code_len;
702         int i;
703         char *tramp_name;
704
705         code = get_delegate_invoke_impl (TRUE, 0, &code_len);
706         res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
707
708         for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
709                 code = get_delegate_invoke_impl (FALSE, i, &code_len);
710                 tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
711                 res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
712                 g_free (tramp_name);
713         }
714
715         return res;
716 }
717
718 gpointer
719 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
720 {
721         guint8 *code, *start;
722         MonoType *sig_ret;
723
724         /* FIXME: Support more cases */
725         sig_ret = mini_type_get_underlying_type (NULL, sig->ret);
726         if (MONO_TYPE_ISSTRUCT (sig_ret))
727                 return NULL;
728
729         if (has_target) {
730                 static guint8* cached = NULL;
731                 mono_mini_arch_lock ();
732                 if (cached) {
733                         mono_mini_arch_unlock ();
734                         return cached;
735                 }
736
737                 if (mono_aot_only)
738                         start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
739                 else
740                         start = get_delegate_invoke_impl (TRUE, 0, NULL);
741                 cached = start;
742                 mono_mini_arch_unlock ();
743                 return cached;
744         } else {
745                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
746                 int i;
747
748                 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
749                         return NULL;
750                 for (i = 0; i < sig->param_count; ++i)
751                         if (!mono_is_regsize_var (sig->params [i]))
752                                 return NULL;
753
754                 mono_mini_arch_lock ();
755                 code = cache [sig->param_count];
756                 if (code) {
757                         mono_mini_arch_unlock ();
758                         return code;
759                 }
760
761                 if (mono_aot_only) {
762                         char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
763                         start = mono_aot_get_trampoline (name);
764                         g_free (name);
765                 } else {
766                         start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
767                 }
768                 cache [sig->param_count] = start;
769                 mono_mini_arch_unlock ();
770                 return start;
771         }
772
773         return NULL;
774 }
775
776 gpointer
777 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
778 {
779         return NULL;
780 }
781
782 gpointer
783 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
784 {
785         return (gpointer)regs [ARMREG_R0];
786 }
787
788 /*
789  * Initialize the cpu to execute managed code.
790  */
791 void
792 mono_arch_cpu_init (void)
793 {
794         i8_align = MONO_ABI_ALIGNOF (gint64);
795 #ifdef MONO_CROSS_COMPILE
796         /* Need to set the alignment of i8 since it can different on the target */
797 #ifdef TARGET_ANDROID
798         /* linux gnueabi */
799         mono_type_set_alignment (MONO_TYPE_I8, i8_align);
800 #endif
801 #endif
802 }
803
804 /*
805  * Initialize architecture specific code.
806  */
807 void
808 mono_arch_init (void)
809 {
810         const char *cpu_arch;
811
812         mono_mutex_init_recursive (&mini_arch_mutex);
813         if (mini_get_debug_options ()->soft_breakpoints) {
814                 single_step_tramp = mini_get_single_step_trampoline ();
815                 breakpoint_tramp = mini_get_breakpoint_trampoline ();
816         } else {
817                 ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
818                 bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
819                 mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
820         }
821
822         mono_aot_register_jit_icall ("mono_arm_throw_exception", mono_arm_throw_exception);
823         mono_aot_register_jit_icall ("mono_arm_throw_exception_by_token", mono_arm_throw_exception_by_token);
824         mono_aot_register_jit_icall ("mono_arm_resume_unwind", mono_arm_resume_unwind);
825 #if defined(ENABLE_GSHAREDVT)
826         mono_aot_register_jit_icall ("mono_arm_start_gsharedvt_call", mono_arm_start_gsharedvt_call);
827 #endif
828
829 #if defined(__ARM_EABI__)
830         eabi_supported = TRUE;
831 #endif
832
833 #if defined(ARM_FPU_VFP_HARD)
834         arm_fpu = MONO_ARM_FPU_VFP_HARD;
835 #else
836         arm_fpu = MONO_ARM_FPU_VFP;
837
838 #if defined(ARM_FPU_NONE) && !defined(__APPLE__)
839         /*
840          * If we're compiling with a soft float fallback and it
841          * turns out that no VFP unit is available, we need to
842          * switch to soft float. We don't do this for iOS, since
843          * iOS devices always have a VFP unit.
844          */
845         if (!mono_hwcap_arm_has_vfp)
846                 arm_fpu = MONO_ARM_FPU_NONE;
847
848         /*
849          * This environment variable can be useful in testing
850          * environments to make sure the soft float fallback
851          * works. Most ARM devices have VFP units these days, so
852          * normally soft float code would not be exercised much.
853          */
854         const char *soft = g_getenv ("MONO_ARM_FORCE_SOFT_FLOAT");
855
856         if (soft && !strncmp (soft, "1", 1))
857                 arm_fpu = MONO_ARM_FPU_NONE;
858 #endif
859 #endif
860
861         v5_supported = mono_hwcap_arm_is_v5;
862         v6_supported = mono_hwcap_arm_is_v6;
863         v7_supported = mono_hwcap_arm_is_v7;
864         v7s_supported = mono_hwcap_arm_is_v7s;
865
866 #if defined(__APPLE__)
867         /* iOS is special-cased here because we don't yet
868            have a way to properly detect CPU features on it. */
869         thumb_supported = TRUE;
870         iphone_abi = TRUE;
871 #else
872         thumb_supported = mono_hwcap_arm_has_thumb;
873         thumb2_supported = mono_hwcap_arm_has_thumb2;
874 #endif
875
876         /* Format: armv(5|6|7[s])[-thumb[2]] */
877         cpu_arch = g_getenv ("MONO_CPU_ARCH");
878
879         /* Do this here so it overrides any detection. */
880         if (cpu_arch) {
881                 if (strncmp (cpu_arch, "armv", 4) == 0) {
882                         v5_supported = cpu_arch [4] >= '5';
883                         v6_supported = cpu_arch [4] >= '6';
884                         v7_supported = cpu_arch [4] >= '7';
885                         v7s_supported = strncmp (cpu_arch, "armv7s", 6) == 0;
886                 }
887
888                 thumb_supported = strstr (cpu_arch, "thumb") != NULL;
889                 thumb2_supported = strstr (cpu_arch, "thumb2") != NULL;
890         }
891 }
892
893 /*
894  * Cleanup architecture specific code.
895  */
896 void
897 mono_arch_cleanup (void)
898 {
899 }
900
901 /*
902  * This function returns the optimizations supported on this cpu.
903  */
904 guint32
905 mono_arch_cpu_optimizations (guint32 *exclude_mask)
906 {
907         /* no arm-specific optimizations yet */
908         *exclude_mask = 0;
909         return 0;
910 }
911
912 /*
913  * This function test for all SIMD functions supported.
914  *
915  * Returns a bitmask corresponding to all supported versions.
916  *
917  */
918 guint32
919 mono_arch_cpu_enumerate_simd_versions (void)
920 {
921         /* SIMD is currently unimplemented */
922         return 0;
923 }
924
925
926 #ifndef DISABLE_JIT
927
928 gboolean
929 mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode)
930 {
931         if (v7s_supported) {
932                 switch (opcode) {
933                 case OP_IDIV:
934                 case OP_IREM:
935                 case OP_IDIV_UN:
936                 case OP_IREM_UN:
937                         return FALSE;
938                 default:
939                         break;
940                 }
941         }
942         return TRUE;
943 }
944
945 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
946 gboolean
947 mono_arch_is_soft_float (void)
948 {
949         return arm_fpu == MONO_ARM_FPU_NONE;
950 }
951 #endif
952
953 gboolean
954 mono_arm_is_hard_float (void)
955 {
956         return arm_fpu == MONO_ARM_FPU_VFP_HARD;
957 }
958
959 static gboolean
960 is_regsize_var (MonoGenericSharingContext *gsctx, MonoType *t) {
961         if (t->byref)
962                 return TRUE;
963         t = mini_type_get_underlying_type (gsctx, t);
964         switch (t->type) {
965         case MONO_TYPE_I4:
966         case MONO_TYPE_U4:
967         case MONO_TYPE_I:
968         case MONO_TYPE_U:
969         case MONO_TYPE_PTR:
970         case MONO_TYPE_FNPTR:
971                 return TRUE;
972         case MONO_TYPE_OBJECT:
973         case MONO_TYPE_STRING:
974         case MONO_TYPE_CLASS:
975         case MONO_TYPE_SZARRAY:
976         case MONO_TYPE_ARRAY:
977                 return TRUE;
978         case MONO_TYPE_GENERICINST:
979                 if (!mono_type_generic_inst_is_valuetype (t))
980                         return TRUE;
981                 return FALSE;
982         case MONO_TYPE_VALUETYPE:
983                 return FALSE;
984         }
985         return FALSE;
986 }
987
988 GList *
989 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
990 {
991         GList *vars = NULL;
992         int i;
993
994         for (i = 0; i < cfg->num_varinfo; i++) {
995                 MonoInst *ins = cfg->varinfo [i];
996                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
997
998                 /* unused vars */
999                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
1000                         continue;
1001
1002                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
1003                         continue;
1004
1005                 /* we can only allocate 32 bit values */
1006                 if (is_regsize_var (cfg->generic_sharing_context, ins->inst_vtype)) {
1007                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
1008                         g_assert (i == vmv->idx);
1009                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
1010                 }
1011         }
1012
1013         return vars;
1014 }
1015
1016 GList *
1017 mono_arch_get_global_int_regs (MonoCompile *cfg)
1018 {
1019         GList *regs = NULL;
1020
1021         mono_arch_compute_omit_fp (cfg);
1022
1023         /* 
1024          * FIXME: Interface calls might go through a static rgctx trampoline which
1025          * sets V5, but it doesn't save it, so we need to save it ourselves, and
1026          * avoid using it.
1027          */
1028         if (cfg->flags & MONO_CFG_HAS_CALLS)
1029                 cfg->uses_rgctx_reg = TRUE;
1030
1031         if (cfg->arch.omit_fp)
1032                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_FP));
1033         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V1));
1034         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V2));
1035         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V3));
1036         if (iphone_abi)
1037                 /* V4=R7 is used as a frame pointer, but V7=R10 is preserved */
1038                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));
1039         else
1040                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V4));
1041         if (!(cfg->compile_aot || cfg->uses_rgctx_reg || COMPILE_LLVM (cfg)))
1042                 /* V5 is reserved for passing the vtable/rgctx/IMT method */
1043                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
1044         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V6));*/
1045         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));*/
1046
1047         return regs;
1048 }
1049
1050 /*
1051  * mono_arch_regalloc_cost:
1052  *
1053  *  Return the cost, in number of memory references, of the action of 
1054  * allocating the variable VMV into a register during global register
1055  * allocation.
1056  */
1057 guint32
1058 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1059 {
1060         /* FIXME: */
1061         return 2;
1062 }
1063
1064 #endif /* #ifndef DISABLE_JIT */
1065
1066 #ifndef __GNUC_PREREQ
1067 #define __GNUC_PREREQ(maj, min) (0)
1068 #endif
1069
1070 void
1071 mono_arch_flush_icache (guint8 *code, gint size)
1072 {
1073 #if defined(__native_client__)
1074   // For Native Client we don't have to flush i-cache here,
1075   // as it's being done by dyncode interface.
1076 #else
1077
1078 #ifdef MONO_CROSS_COMPILE
1079 #elif __APPLE__
1080         sys_icache_invalidate (code, size);
1081 #elif __GNUC_PREREQ(4, 3)
1082     __builtin___clear_cache (code, code + size);
1083 #elif __GNUC_PREREQ(4, 1)
1084         __clear_cache (code, code + size);
1085 #elif defined(PLATFORM_ANDROID)
1086         const int syscall = 0xf0002;
1087         __asm __volatile (
1088                 "mov     r0, %0\n"                      
1089                 "mov     r1, %1\n"
1090                 "mov     r7, %2\n"
1091                 "mov     r2, #0x0\n"
1092                 "svc     0x00000000\n"
1093                 :
1094                 :       "r" (code), "r" (code + size), "r" (syscall)
1095                 :       "r0", "r1", "r7", "r2"
1096                 );
1097 #else
1098         __asm __volatile ("mov r0, %0\n"
1099                         "mov r1, %1\n"
1100                         "mov r2, %2\n"
1101                         "swi 0x9f0002       @ sys_cacheflush"
1102                         : /* no outputs */
1103                         : "r" (code), "r" (code + size), "r" (0)
1104                         : "r0", "r1", "r3" );
1105 #endif
1106 #endif /* !__native_client__ */
1107 }
1108
1109 typedef enum {
1110         RegTypeNone,
1111         RegTypeGeneral,
1112         RegTypeIRegPair,
1113         RegTypeBase,
1114         RegTypeBaseGen,
1115         RegTypeFP,
1116         RegTypeStructByVal,
1117         RegTypeStructByAddr,
1118         /* gsharedvt argument passed by addr in greg */
1119         RegTypeGSharedVtInReg,
1120         /* gsharedvt argument passed by addr on stack */
1121         RegTypeGSharedVtOnStack,
1122         RegTypeHFA
1123 } ArgStorage;
1124
1125 typedef struct {
1126         gint32  offset;
1127         guint16 vtsize; /* in param area */
1128         /* RegTypeHFA */
1129         int esize;
1130         /* RegTypeHFA */
1131         int nregs;
1132         guint8  reg;
1133         ArgStorage  storage;
1134         gint32  struct_size;
1135         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
1136 } ArgInfo;
1137
1138 typedef struct {
1139         int nargs;
1140         guint32 stack_usage;
1141         /* The index of the vret arg in the argument list for RegTypeStructByAddr */
1142         int vret_arg_index;
1143         ArgInfo ret;
1144         ArgInfo sig_cookie;
1145         ArgInfo args [1];
1146 } CallInfo;
1147
1148 #define DEBUG(a)
1149
1150 static void inline
1151 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
1152 {
1153         if (simple) {
1154                 if (*gr > ARMREG_R3) {
1155                         ainfo->size = 4;
1156                         ainfo->offset = *stack_size;
1157                         ainfo->reg = ARMREG_SP; /* in the caller */
1158                         ainfo->storage = RegTypeBase;
1159                         *stack_size += 4;
1160                 } else {
1161                         ainfo->storage = RegTypeGeneral;
1162                         ainfo->reg = *gr;
1163                 }
1164         } else {
1165                 gboolean split;
1166
1167                 if (eabi_supported)
1168                         split = i8_align == 4;
1169                 else
1170                         split = TRUE;
1171
1172                 ainfo->size = 8;
1173                 if (*gr == ARMREG_R3 && split) {
1174                         /* first word in r3 and the second on the stack */
1175                         ainfo->offset = *stack_size;
1176                         ainfo->reg = ARMREG_SP; /* in the caller */
1177                         ainfo->storage = RegTypeBaseGen;
1178                         *stack_size += 4;
1179                 } else if (*gr >= ARMREG_R3) {
1180                         if (eabi_supported) {
1181                                 /* darwin aligns longs to 4 byte only */
1182                                 if (i8_align == 8) {
1183                                         *stack_size += 7;
1184                                         *stack_size &= ~7;
1185                                 }
1186                         }
1187                         ainfo->offset = *stack_size;
1188                         ainfo->reg = ARMREG_SP; /* in the caller */
1189                         ainfo->storage = RegTypeBase;
1190                         *stack_size += 8;
1191                 } else {
1192                         if (eabi_supported) {
1193                                 if (i8_align == 8 && ((*gr) & 1))
1194                                         (*gr) ++;
1195                         }
1196                         ainfo->storage = RegTypeIRegPair;
1197                         ainfo->reg = *gr;
1198                 }
1199                 (*gr) ++;
1200         }
1201         (*gr) ++;
1202 }
1203
1204 static void inline
1205 add_float (guint *fpr, guint *stack_size, ArgInfo *ainfo, gboolean is_double, gint *float_spare)
1206 {
1207         /*
1208          * If we're calling a function like this:
1209          *
1210          * void foo(float a, double b, float c)
1211          *
1212          * We pass a in s0 and b in d1. That leaves us
1213          * with s1 being unused. The armhf ABI recognizes
1214          * this and requires register assignment to then
1215          * use that for the next single-precision arg,
1216          * i.e. c in this example. So float_spare either
1217          * tells us which reg to use for the next single-
1218          * precision arg, or it's -1, meaning use *fpr.
1219          *
1220          * Note that even though most of the JIT speaks
1221          * double-precision, fpr represents single-
1222          * precision registers.
1223          *
1224          * See parts 5.5 and 6.1.2 of the AAPCS for how
1225          * this all works.
1226          */
1227
1228         if (*fpr < ARM_VFP_F16 || (!is_double && *float_spare >= 0)) {
1229                 ainfo->storage = RegTypeFP;
1230
1231                 if (is_double) {
1232                         /*
1233                          * If we're passing a double-precision value
1234                          * and *fpr is odd (e.g. it's s1, s3, ...)
1235                          * we need to use the next even register. So
1236                          * we mark the current *fpr as a spare that
1237                          * can be used for the next single-precision
1238                          * value.
1239                          */
1240                         if (*fpr % 2) {
1241                                 *float_spare = *fpr;
1242                                 (*fpr)++;
1243                         }
1244
1245                         /*
1246                          * At this point, we have an even register
1247                          * so we assign that and move along.
1248                          */
1249                         ainfo->reg = *fpr;
1250                         *fpr += 2;
1251                 } else if (*float_spare >= 0) {
1252                         /*
1253                          * We're passing a single-precision value
1254                          * and it looks like a spare single-
1255                          * precision register is available. Let's
1256                          * use it.
1257                          */
1258
1259                         ainfo->reg = *float_spare;
1260                         *float_spare = -1;
1261                 } else {
1262                         /*
1263                          * If we hit this branch, we're passing a
1264                          * single-precision value and we can simply
1265                          * use the next available register.
1266                          */
1267
1268                         ainfo->reg = *fpr;
1269                         (*fpr)++;
1270                 }
1271         } else {
1272                 /*
1273                  * We've exhausted available floating point
1274                  * regs, so pass the rest on the stack.
1275                  */
1276
1277                 if (is_double) {
1278                         *stack_size += 7;
1279                         *stack_size &= ~7;
1280                 }
1281
1282                 ainfo->offset = *stack_size;
1283                 ainfo->reg = ARMREG_SP;
1284                 ainfo->storage = RegTypeBase;
1285
1286                 *stack_size += 8;
1287         }
1288 }
1289
1290 static gboolean
1291 is_hfa (MonoType *t, int *out_nfields, int *out_esize)
1292 {
1293         MonoClass *klass;
1294         gpointer iter;
1295         MonoClassField *field;
1296         MonoType *ftype, *prev_ftype = NULL;
1297         int nfields = 0;
1298
1299         klass = mono_class_from_mono_type (t);
1300         iter = NULL;
1301         while ((field = mono_class_get_fields (klass, &iter))) {
1302                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1303                         continue;
1304                 ftype = mono_field_get_type (field);
1305                 ftype = mini_type_get_underlying_type (NULL, ftype);
1306
1307                 if (MONO_TYPE_ISSTRUCT (ftype)) {
1308                         int nested_nfields, nested_esize;
1309
1310                         if (!is_hfa (ftype, &nested_nfields, &nested_esize))
1311                                 return FALSE;
1312                         if (nested_esize == 4)
1313                                 ftype = &mono_defaults.single_class->byval_arg;
1314                         else
1315                                 ftype = &mono_defaults.double_class->byval_arg;
1316                         if (prev_ftype && prev_ftype->type != ftype->type)
1317                                 return FALSE;
1318                         prev_ftype = ftype;
1319                         nfields += nested_nfields;
1320                 } else {
1321                         if (!(!ftype->byref && (ftype->type == MONO_TYPE_R4 || ftype->type == MONO_TYPE_R8)))
1322                                 return FALSE;
1323                         if (prev_ftype && prev_ftype->type != ftype->type)
1324                                 return FALSE;
1325                         prev_ftype = ftype;
1326                         nfields ++;
1327                 }
1328         }
1329         if (nfields == 0 || nfields > 4)
1330                 return FALSE;
1331         *out_nfields = nfields;
1332         *out_esize = prev_ftype->type == MONO_TYPE_R4 ? 4 : 8;
1333         return TRUE;
1334 }
1335
1336 static CallInfo*
1337 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
1338 {
1339         guint i, gr, fpr, pstart;
1340         gint float_spare;
1341         int n = sig->hasthis + sig->param_count;
1342         int nfields, esize;
1343         guint32 align;
1344         MonoType *t;
1345         guint32 stack_size = 0;
1346         CallInfo *cinfo;
1347         gboolean is_pinvoke = sig->pinvoke;
1348         gboolean vtype_retaddr = FALSE;
1349
1350         if (mp)
1351                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1352         else
1353                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1354
1355         cinfo->nargs = n;
1356         gr = ARMREG_R0;
1357         fpr = ARM_VFP_F0;
1358         float_spare = -1;
1359
1360         t = mini_type_get_underlying_type (gsctx, sig->ret);
1361         switch (t->type) {
1362         case MONO_TYPE_I1:
1363         case MONO_TYPE_U1:
1364         case MONO_TYPE_I2:
1365         case MONO_TYPE_U2:
1366         case MONO_TYPE_I4:
1367         case MONO_TYPE_U4:
1368         case MONO_TYPE_I:
1369         case MONO_TYPE_U:
1370         case MONO_TYPE_PTR:
1371         case MONO_TYPE_FNPTR:
1372         case MONO_TYPE_CLASS:
1373         case MONO_TYPE_OBJECT:
1374         case MONO_TYPE_SZARRAY:
1375         case MONO_TYPE_ARRAY:
1376         case MONO_TYPE_STRING:
1377                 cinfo->ret.storage = RegTypeGeneral;
1378                 cinfo->ret.reg = ARMREG_R0;
1379                 break;
1380         case MONO_TYPE_U8:
1381         case MONO_TYPE_I8:
1382                 cinfo->ret.storage = RegTypeIRegPair;
1383                 cinfo->ret.reg = ARMREG_R0;
1384                 break;
1385         case MONO_TYPE_R4:
1386         case MONO_TYPE_R8:
1387                 cinfo->ret.storage = RegTypeFP;
1388
1389                 if (IS_HARD_FLOAT) {
1390                         cinfo->ret.reg = ARM_VFP_F0;
1391                 } else {
1392                         cinfo->ret.reg = ARMREG_R0;
1393                 }
1394                 break;
1395         case MONO_TYPE_GENERICINST:
1396                 if (!mono_type_generic_inst_is_valuetype (t)) {
1397                         cinfo->ret.storage = RegTypeGeneral;
1398                         cinfo->ret.reg = ARMREG_R0;
1399                         break;
1400                 }
1401                 // FIXME: Only for variable types
1402                 if (mini_is_gsharedvt_type_gsctx (gsctx, t)) {
1403                         cinfo->ret.storage = RegTypeStructByAddr;
1404                         break;
1405                 }
1406                 /* Fall through */
1407         case MONO_TYPE_VALUETYPE:
1408         case MONO_TYPE_TYPEDBYREF:
1409                 if (IS_HARD_FLOAT && sig->pinvoke && is_hfa (t, &nfields, &esize)) {
1410                         cinfo->ret.storage = RegTypeHFA;
1411                         cinfo->ret.reg = 0;
1412                         cinfo->ret.nregs = nfields;
1413                         cinfo->ret.esize = esize;
1414                 } else {
1415                         if (is_pinvoke && mono_class_native_size (mono_class_from_mono_type (t), &align) <= sizeof (gpointer))
1416                                 cinfo->ret.storage = RegTypeStructByVal;
1417                         else
1418                                 cinfo->ret.storage = RegTypeStructByAddr;
1419                 }
1420                 break;
1421         case MONO_TYPE_VAR:
1422         case MONO_TYPE_MVAR:
1423                 g_assert (mini_is_gsharedvt_type_gsctx (gsctx, t));
1424                 cinfo->ret.storage = RegTypeStructByAddr;
1425                 break;
1426         case MONO_TYPE_VOID:
1427                 break;
1428         default:
1429                 g_error ("Can't handle as return value 0x%x", sig->ret->type);
1430         }
1431
1432         vtype_retaddr = cinfo->ret.storage == RegTypeStructByAddr;
1433
1434         pstart = 0;
1435         n = 0;
1436         /*
1437          * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
1438          * the first argument, allowing 'this' to be always passed in the first arg reg.
1439          * Also do this if the first argument is a reference type, since virtual calls
1440          * are sometimes made using calli without sig->hasthis set, like in the delegate
1441          * invoke wrappers.
1442          */
1443         if (vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
1444                 if (sig->hasthis) {
1445                         add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1446                 } else {
1447                         add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0], TRUE);
1448                         pstart = 1;
1449                 }
1450                 n ++;
1451                 cinfo->ret.reg = gr;
1452                 gr ++;
1453                 cinfo->vret_arg_index = 1;
1454         } else {
1455                 /* this */
1456                 if (sig->hasthis) {
1457                         add_general (&gr, &stack_size, cinfo->args + 0, TRUE);
1458                         n ++;
1459                 }
1460                 if (vtype_retaddr) {
1461                         cinfo->ret.reg = gr;
1462                         gr ++;
1463                 }
1464         }
1465
1466         DEBUG(printf("params: %d\n", sig->param_count));
1467         for (i = pstart; i < sig->param_count; ++i) {
1468                 ArgInfo *ainfo = &cinfo->args [n];
1469
1470                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1471                         /* Prevent implicit arguments and sig_cookie from
1472                            being passed in registers */
1473                         gr = ARMREG_R3 + 1;
1474                         fpr = ARM_VFP_F16;
1475                         /* Emit the signature cookie just before the implicit arguments */
1476                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1477                 }
1478                 DEBUG(printf("param %d: ", i));
1479                 if (sig->params [i]->byref) {
1480                         DEBUG(printf("byref\n"));
1481                         add_general (&gr, &stack_size, ainfo, TRUE);
1482                         n++;
1483                         continue;
1484                 }
1485                 t = mini_type_get_underlying_type (gsctx, sig->params [i]);
1486                 switch (t->type) {
1487                 case MONO_TYPE_I1:
1488                 case MONO_TYPE_U1:
1489                         cinfo->args [n].size = 1;
1490                         add_general (&gr, &stack_size, ainfo, TRUE);
1491                         break;
1492                 case MONO_TYPE_I2:
1493                 case MONO_TYPE_U2:
1494                         cinfo->args [n].size = 2;
1495                         add_general (&gr, &stack_size, ainfo, TRUE);
1496                         break;
1497                 case MONO_TYPE_I4:
1498                 case MONO_TYPE_U4:
1499                         cinfo->args [n].size = 4;
1500                         add_general (&gr, &stack_size, ainfo, TRUE);
1501                         break;
1502                 case MONO_TYPE_I:
1503                 case MONO_TYPE_U:
1504                 case MONO_TYPE_PTR:
1505                 case MONO_TYPE_FNPTR:
1506                 case MONO_TYPE_CLASS:
1507                 case MONO_TYPE_OBJECT:
1508                 case MONO_TYPE_STRING:
1509                 case MONO_TYPE_SZARRAY:
1510                 case MONO_TYPE_ARRAY:
1511                         cinfo->args [n].size = sizeof (gpointer);
1512                         add_general (&gr, &stack_size, ainfo, TRUE);
1513                         break;
1514                 case MONO_TYPE_GENERICINST:
1515                         if (!mono_type_generic_inst_is_valuetype (t)) {
1516                                 cinfo->args [n].size = sizeof (gpointer);
1517                                 add_general (&gr, &stack_size, ainfo, TRUE);
1518                                 break;
1519                         }
1520                         if (mini_is_gsharedvt_type_gsctx (gsctx, t)) {
1521                                 /* gsharedvt arguments are passed by ref */
1522                                 g_assert (mini_is_gsharedvt_type_gsctx (gsctx, t));
1523                                 add_general (&gr, &stack_size, ainfo, TRUE);
1524                                 switch (ainfo->storage) {
1525                                 case RegTypeGeneral:
1526                                         ainfo->storage = RegTypeGSharedVtInReg;
1527                                         break;
1528                                 case RegTypeBase:
1529                                         ainfo->storage = RegTypeGSharedVtOnStack;
1530                                         break;
1531                                 default:
1532                                         g_assert_not_reached ();
1533                                 }
1534                                 break;
1535                         }
1536                         /* Fall through */
1537                 case MONO_TYPE_TYPEDBYREF:
1538                 case MONO_TYPE_VALUETYPE: {
1539                         gint size;
1540                         int align_size;
1541                         int nwords, nfields, esize;
1542                         guint32 align;
1543
1544                         if (IS_HARD_FLOAT && sig->pinvoke && is_hfa (t, &nfields, &esize)) {
1545                                 if (fpr + nfields < ARM_VFP_F16) {
1546                                         ainfo->storage = RegTypeHFA;
1547                                         ainfo->reg = fpr;
1548                                         ainfo->nregs = nfields;
1549                                         ainfo->esize = esize;
1550                                         fpr += nfields;
1551                                         break;
1552                                 } else {
1553                                         fpr = ARM_VFP_F16;
1554                                 }
1555                         }
1556
1557                         if (t->type == MONO_TYPE_TYPEDBYREF) {
1558                                 size = sizeof (MonoTypedRef);
1559                                 align = sizeof (gpointer);
1560                         } else {
1561                                 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
1562                                 if (is_pinvoke)
1563                                         size = mono_class_native_size (klass, &align);
1564                                 else
1565                                         size = mini_type_stack_size_full (gsctx, t, &align, FALSE);
1566                         }
1567                         DEBUG(printf ("load %d bytes struct\n", size));
1568                         align_size = size;
1569                         nwords = 0;
1570                         align_size += (sizeof (gpointer) - 1);
1571                         align_size &= ~(sizeof (gpointer) - 1);
1572                         nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
1573                         ainfo->storage = RegTypeStructByVal;
1574                         ainfo->struct_size = size;
1575                         /* FIXME: align stack_size if needed */
1576                         if (eabi_supported) {
1577                                 if (align >= 8 && (gr & 1))
1578                                         gr ++;
1579                         }
1580                         if (gr > ARMREG_R3) {
1581                                 ainfo->size = 0;
1582                                 ainfo->vtsize = nwords;
1583                         } else {
1584                                 int rest = ARMREG_R3 - gr + 1;
1585                                 int n_in_regs = rest >= nwords? nwords: rest;
1586
1587                                 ainfo->size = n_in_regs;
1588                                 ainfo->vtsize = nwords - n_in_regs;
1589                                 ainfo->reg = gr;
1590                                 gr += n_in_regs;
1591                                 nwords -= n_in_regs;
1592                         }
1593                         if (sig->call_convention == MONO_CALL_VARARG)
1594                                 /* This matches the alignment in mono_ArgIterator_IntGetNextArg () */
1595                                 stack_size = ALIGN_TO (stack_size, align);
1596                         ainfo->offset = stack_size;
1597                         /*g_print ("offset for arg %d at %d\n", n, stack_size);*/
1598                         stack_size += nwords * sizeof (gpointer);
1599                         break;
1600                 }
1601                 case MONO_TYPE_U8:
1602                 case MONO_TYPE_I8:
1603                         ainfo->size = 8;
1604                         add_general (&gr, &stack_size, ainfo, FALSE);
1605                         break;
1606                 case MONO_TYPE_R4:
1607                         ainfo->size = 4;
1608
1609                         if (IS_HARD_FLOAT)
1610                                 add_float (&fpr, &stack_size, ainfo, FALSE, &float_spare);
1611                         else
1612                                 add_general (&gr, &stack_size, ainfo, TRUE);
1613                         break;
1614                 case MONO_TYPE_R8:
1615                         ainfo->size = 8;
1616
1617                         if (IS_HARD_FLOAT)
1618                                 add_float (&fpr, &stack_size, ainfo, TRUE, &float_spare);
1619                         else
1620                                 add_general (&gr, &stack_size, ainfo, FALSE);
1621                         break;
1622                 case MONO_TYPE_VAR:
1623                 case MONO_TYPE_MVAR:
1624                         /* gsharedvt arguments are passed by ref */
1625                         g_assert (mini_is_gsharedvt_type_gsctx (gsctx, t));
1626                         add_general (&gr, &stack_size, ainfo, TRUE);
1627                         switch (ainfo->storage) {
1628                         case RegTypeGeneral:
1629                                 ainfo->storage = RegTypeGSharedVtInReg;
1630                                 break;
1631                         case RegTypeBase:
1632                                 ainfo->storage = RegTypeGSharedVtOnStack;
1633                                 break;
1634                         default:
1635                                 g_assert_not_reached ();
1636                         }
1637                         break;
1638                 default:
1639                         g_error ("Can't handle 0x%x", sig->params [i]->type);
1640                 }
1641                 n ++;
1642         }
1643
1644         /* Handle the case where there are no implicit arguments */
1645         if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1646                 /* Prevent implicit arguments and sig_cookie from
1647                    being passed in registers */
1648                 gr = ARMREG_R3 + 1;
1649                 fpr = ARM_VFP_F16;
1650                 /* Emit the signature cookie just before the implicit arguments */
1651                 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
1652         }
1653
1654         /* align stack size to 8 */
1655         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1656         stack_size = (stack_size + 7) & ~7;
1657
1658         cinfo->stack_usage = stack_size;
1659         return cinfo;
1660 }
1661
1662
1663 gboolean
1664 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
1665 {
1666         MonoType *callee_ret;
1667         CallInfo *c1, *c2;
1668         gboolean res;
1669
1670         c1 = get_call_info (NULL, NULL, caller_sig);
1671         c2 = get_call_info (NULL, NULL, callee_sig);
1672
1673         /*
1674          * Tail calls with more callee stack usage than the caller cannot be supported, since
1675          * the extra stack space would be left on the stack after the tail call.
1676          */
1677         res = c1->stack_usage >= c2->stack_usage;
1678         callee_ret = mini_get_underlying_type (cfg, callee_sig->ret);
1679         if (callee_ret && MONO_TYPE_ISSTRUCT (callee_ret) && c2->ret.storage != RegTypeStructByVal)
1680                 /* An address on the callee's stack is passed as the first argument */
1681                 res = FALSE;
1682
1683         if (c2->stack_usage > 16 * 4)
1684                 res = FALSE;
1685
1686         g_free (c1);
1687         g_free (c2);
1688
1689         return res;
1690 }
1691
1692 #ifndef DISABLE_JIT
1693
1694 static gboolean
1695 debug_omit_fp (void)
1696 {
1697 #if 0
1698         return mono_debug_count ();
1699 #else
1700         return TRUE;
1701 #endif
1702 }
1703
1704 /**
1705  * mono_arch_compute_omit_fp:
1706  *
1707  *   Determine whenever the frame pointer can be eliminated.
1708  */
1709 static void
1710 mono_arch_compute_omit_fp (MonoCompile *cfg)
1711 {
1712         MonoMethodSignature *sig;
1713         MonoMethodHeader *header;
1714         int i, locals_size;
1715         CallInfo *cinfo;
1716
1717         if (cfg->arch.omit_fp_computed)
1718                 return;
1719
1720         header = cfg->header;
1721
1722         sig = mono_method_signature (cfg->method);
1723
1724         if (!cfg->arch.cinfo)
1725                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1726         cinfo = cfg->arch.cinfo;
1727
1728         /*
1729          * FIXME: Remove some of the restrictions.
1730          */
1731         cfg->arch.omit_fp = TRUE;
1732         cfg->arch.omit_fp_computed = TRUE;
1733
1734         if (cfg->disable_omit_fp)
1735                 cfg->arch.omit_fp = FALSE;
1736         if (!debug_omit_fp ())
1737                 cfg->arch.omit_fp = FALSE;
1738         /*
1739         if (cfg->method->save_lmf)
1740                 cfg->arch.omit_fp = FALSE;
1741         */
1742         if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1743                 cfg->arch.omit_fp = FALSE;
1744         if (header->num_clauses)
1745                 cfg->arch.omit_fp = FALSE;
1746         if (cfg->param_area)
1747                 cfg->arch.omit_fp = FALSE;
1748         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1749                 cfg->arch.omit_fp = FALSE;
1750         if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1751                 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1752                 cfg->arch.omit_fp = FALSE;
1753         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1754                 ArgInfo *ainfo = &cinfo->args [i];
1755
1756                 if (ainfo->storage == RegTypeBase || ainfo->storage == RegTypeBaseGen || ainfo->storage == RegTypeStructByVal) {
1757                         /* 
1758                          * The stack offset can only be determined when the frame
1759                          * size is known.
1760                          */
1761                         cfg->arch.omit_fp = FALSE;
1762                 }
1763         }
1764
1765         locals_size = 0;
1766         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1767                 MonoInst *ins = cfg->varinfo [i];
1768                 int ialign;
1769
1770                 locals_size += mono_type_size (ins->inst_vtype, &ialign);
1771         }
1772 }
1773
1774 /*
1775  * Set var information according to the calling convention. arm version.
1776  * The locals var stuff should most likely be split in another method.
1777  */
1778 void
1779 mono_arch_allocate_vars (MonoCompile *cfg)
1780 {
1781         MonoMethodSignature *sig;
1782         MonoMethodHeader *header;
1783         MonoInst *ins;
1784         MonoType *sig_ret;
1785         int i, offset, size, align, curinst;
1786         CallInfo *cinfo;
1787         ArgInfo *ainfo;
1788         guint32 ualign;
1789
1790         sig = mono_method_signature (cfg->method);
1791
1792         if (!cfg->arch.cinfo)
1793                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1794         cinfo = cfg->arch.cinfo;
1795         sig_ret = mini_get_underlying_type (cfg, sig->ret);
1796
1797         mono_arch_compute_omit_fp (cfg);
1798
1799         if (cfg->arch.omit_fp)
1800                 cfg->frame_reg = ARMREG_SP;
1801         else
1802                 cfg->frame_reg = ARMREG_FP;
1803
1804         cfg->flags |= MONO_CFG_HAS_SPILLUP;
1805
1806         /* allow room for the vararg method args: void* and long/double */
1807         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1808                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1809
1810         header = cfg->header;
1811
1812         /* See mono_arch_get_global_int_regs () */
1813         if (cfg->flags & MONO_CFG_HAS_CALLS)
1814                 cfg->uses_rgctx_reg = TRUE;
1815
1816         if (cfg->frame_reg != ARMREG_SP)
1817                 cfg->used_int_regs |= 1 << cfg->frame_reg;
1818
1819         if (cfg->compile_aot || cfg->uses_rgctx_reg || COMPILE_LLVM (cfg))
1820                 /* V5 is reserved for passing the vtable/rgctx/IMT method */
1821                 cfg->used_int_regs |= (1 << MONO_ARCH_IMT_REG);
1822
1823         offset = 0;
1824         curinst = 0;
1825         if (!MONO_TYPE_ISSTRUCT (sig_ret) && cinfo->ret.storage != RegTypeStructByAddr) {
1826                 if (sig_ret->type != MONO_TYPE_VOID) {
1827                         cfg->ret->opcode = OP_REGVAR;
1828                         cfg->ret->inst_c0 = ARMREG_R0;
1829                 }
1830         }
1831         /* local vars are at a positive offset from the stack pointer */
1832         /* 
1833          * also note that if the function uses alloca, we use FP
1834          * to point at the local variables.
1835          */
1836         offset = 0; /* linkage area */
1837         /* align the offset to 16 bytes: not sure this is needed here  */
1838         //offset += 8 - 1;
1839         //offset &= ~(8 - 1);
1840
1841         /* add parameter area size for called functions */
1842         offset += cfg->param_area;
1843         offset += 8 - 1;
1844         offset &= ~(8 - 1);
1845         if (cfg->flags & MONO_CFG_HAS_FPOUT)
1846                 offset += 8;
1847
1848         /* allow room to save the return value */
1849         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1850                 offset += 8;
1851
1852         switch (cinfo->ret.storage) {
1853         case RegTypeStructByVal:
1854                 cfg->ret->opcode = OP_REGOFFSET;
1855                 cfg->ret->inst_basereg = cfg->frame_reg;
1856                 offset += sizeof (gpointer) - 1;
1857                 offset &= ~(sizeof (gpointer) - 1);
1858                 cfg->ret->inst_offset = - offset;
1859                 offset += sizeof(gpointer);
1860                 break;
1861         case RegTypeHFA:
1862                 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
1863                 offset = ALIGN_TO (offset, 8);
1864                 cfg->ret->opcode = OP_REGOFFSET;
1865                 cfg->ret->inst_basereg = cfg->frame_reg;
1866                 cfg->ret->inst_offset = offset;
1867                 // FIXME:
1868                 offset += 32;
1869                 break;
1870         case RegTypeStructByAddr:
1871                 ins = cfg->vret_addr;
1872                 offset += sizeof(gpointer) - 1;
1873                 offset &= ~(sizeof(gpointer) - 1);
1874                 ins->inst_offset = offset;
1875                 ins->opcode = OP_REGOFFSET;
1876                 ins->inst_basereg = cfg->frame_reg;
1877                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1878                         printf ("vret_addr =");
1879                         mono_print_ins (cfg->vret_addr);
1880                 }
1881                 offset += sizeof(gpointer);
1882                 break;
1883         default:
1884                 break;
1885         }
1886
1887         /* Allocate these first so they have a small offset, OP_SEQ_POINT depends on this */
1888         if (cfg->arch.seq_point_info_var) {
1889                 MonoInst *ins;
1890
1891                 ins = cfg->arch.seq_point_info_var;
1892
1893                 size = 4;
1894                 align = 4;
1895                 offset += align - 1;
1896                 offset &= ~(align - 1);
1897                 ins->opcode = OP_REGOFFSET;
1898                 ins->inst_basereg = cfg->frame_reg;
1899                 ins->inst_offset = offset;
1900                 offset += size;
1901
1902                 ins = cfg->arch.ss_trigger_page_var;
1903                 size = 4;
1904                 align = 4;
1905                 offset += align - 1;
1906                 offset &= ~(align - 1);
1907                 ins->opcode = OP_REGOFFSET;
1908                 ins->inst_basereg = cfg->frame_reg;
1909                 ins->inst_offset = offset;
1910                 offset += size;
1911         }
1912
1913         if (cfg->arch.seq_point_read_var) {
1914                 MonoInst *ins;
1915
1916                 ins = cfg->arch.seq_point_read_var;
1917
1918                 size = 4;
1919                 align = 4;
1920                 offset += align - 1;
1921                 offset &= ~(align - 1);
1922                 ins->opcode = OP_REGOFFSET;
1923                 ins->inst_basereg = cfg->frame_reg;
1924                 ins->inst_offset = offset;
1925                 offset += size;
1926
1927                 ins = cfg->arch.seq_point_ss_method_var;
1928                 size = 4;
1929                 align = 4;
1930                 offset += align - 1;
1931                 offset &= ~(align - 1);
1932                 ins->opcode = OP_REGOFFSET;
1933                 ins->inst_basereg = cfg->frame_reg;
1934                 ins->inst_offset = offset;
1935                 offset += size;
1936
1937                 ins = cfg->arch.seq_point_bp_method_var;
1938                 size = 4;
1939                 align = 4;
1940                 offset += align - 1;
1941                 offset &= ~(align - 1);
1942                 ins->opcode = OP_REGOFFSET;
1943                 ins->inst_basereg = cfg->frame_reg;
1944                 ins->inst_offset = offset;
1945                 offset += size;
1946         }
1947
1948         if (cfg->has_atomic_exchange_i4 || cfg->has_atomic_cas_i4 || cfg->has_atomic_add_i4) {
1949                 /* Allocate a temporary used by the atomic ops */
1950                 size = 4;
1951                 align = 4;
1952
1953                 /* Allocate a local slot to hold the sig cookie address */
1954                 offset += align - 1;
1955                 offset &= ~(align - 1);
1956                 cfg->arch.atomic_tmp_offset = offset;
1957                 offset += size;
1958         } else {
1959                 cfg->arch.atomic_tmp_offset = -1;
1960         }
1961
1962         cfg->locals_min_stack_offset = offset;
1963
1964         curinst = cfg->locals_start;
1965         for (i = curinst; i < cfg->num_varinfo; ++i) {
1966                 MonoType *t;
1967
1968                 ins = cfg->varinfo [i];
1969                 if ((ins->flags & MONO_INST_IS_DEAD) || ins->opcode == OP_REGVAR || ins->opcode == OP_REGOFFSET)
1970                         continue;
1971
1972                 t = ins->inst_vtype;
1973                 if (cfg->gsharedvt && mini_is_gsharedvt_variable_type (cfg, t))
1974                         continue;
1975
1976                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1977                 * pinvoke wrappers when they call functions returning structure */
1978                 if (ins->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (t) && t->type != MONO_TYPE_TYPEDBYREF) {
1979                         size = mono_class_native_size (mono_class_from_mono_type (t), &ualign);
1980                         align = ualign;
1981                 }
1982                 else
1983                         size = mono_type_size (t, &align);
1984
1985                 /* FIXME: if a structure is misaligned, our memcpy doesn't work,
1986                  * since it loads/stores misaligned words, which don't do the right thing.
1987                  */
1988                 if (align < 4 && size >= 4)
1989                         align = 4;
1990                 if (ALIGN_TO (offset, align) > ALIGN_TO (offset, 4))
1991                         mini_gc_set_slot_type_from_fp (cfg, ALIGN_TO (offset, 4), SLOT_NOREF);
1992                 offset += align - 1;
1993                 offset &= ~(align - 1);
1994                 ins->opcode = OP_REGOFFSET;
1995                 ins->inst_offset = offset;
1996                 ins->inst_basereg = cfg->frame_reg;
1997                 offset += size;
1998                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1999         }
2000
2001         cfg->locals_max_stack_offset = offset;
2002
2003         curinst = 0;
2004         if (sig->hasthis) {
2005                 ins = cfg->args [curinst];
2006                 if (ins->opcode != OP_REGVAR) {
2007                         ins->opcode = OP_REGOFFSET;
2008                         ins->inst_basereg = cfg->frame_reg;
2009                         offset += sizeof (gpointer) - 1;
2010                         offset &= ~(sizeof (gpointer) - 1);
2011                         ins->inst_offset = offset;
2012                         offset += sizeof (gpointer);
2013                 }
2014                 curinst++;
2015         }
2016
2017         if (sig->call_convention == MONO_CALL_VARARG) {
2018                 size = 4;
2019                 align = 4;
2020
2021                 /* Allocate a local slot to hold the sig cookie address */
2022                 offset += align - 1;
2023                 offset &= ~(align - 1);
2024                 cfg->sig_cookie = offset;
2025                 offset += size;
2026         }                       
2027
2028         for (i = 0; i < sig->param_count; ++i) {
2029                 ainfo = cinfo->args + i;
2030
2031                 ins = cfg->args [curinst];
2032
2033                 switch (ainfo->storage) {
2034                 case RegTypeHFA:
2035                         offset = ALIGN_TO (offset, 8);
2036                         ins->opcode = OP_REGOFFSET;
2037                         ins->inst_basereg = cfg->frame_reg;
2038                         /* These arguments are saved to the stack in the prolog */
2039                         ins->inst_offset = offset;
2040                         if (cfg->verbose_level >= 2)
2041                                 printf ("arg %d allocated to %s+0x%0x.\n", i, mono_arch_regname (ins->inst_basereg), (int)ins->inst_offset);
2042                         // FIXME:
2043                         offset += 32;
2044                         break;
2045                 default:
2046                         break;
2047                 }
2048
2049                 if (ins->opcode != OP_REGVAR) {
2050                         ins->opcode = OP_REGOFFSET;
2051                         ins->inst_basereg = cfg->frame_reg;
2052                         size = mini_type_stack_size_full (cfg->generic_sharing_context, sig->params [i], &ualign, sig->pinvoke);
2053                         align = ualign;
2054                         /* FIXME: if a structure is misaligned, our memcpy doesn't work,
2055                          * since it loads/stores misaligned words, which don't do the right thing.
2056                          */
2057                         if (align < 4 && size >= 4)
2058                                 align = 4;
2059                         /* The code in the prolog () stores words when storing vtypes received in a register */
2060                         if (MONO_TYPE_ISSTRUCT (sig->params [i]))
2061                                 align = 4;
2062                         if (ALIGN_TO (offset, align) > ALIGN_TO (offset, 4))
2063                                 mini_gc_set_slot_type_from_fp (cfg, ALIGN_TO (offset, 4), SLOT_NOREF);
2064                         offset += align - 1;
2065                         offset &= ~(align - 1);
2066                         ins->inst_offset = offset;
2067                         offset += size;
2068                 }
2069                 curinst++;
2070         }
2071
2072         /* align the offset to 8 bytes */
2073         if (ALIGN_TO (offset, 8) > ALIGN_TO (offset, 4))
2074                 mini_gc_set_slot_type_from_fp (cfg, ALIGN_TO (offset, 4), SLOT_NOREF);
2075         offset += 8 - 1;
2076         offset &= ~(8 - 1);
2077
2078         /* change sign? */
2079         cfg->stack_offset = offset;
2080 }
2081
2082 void
2083 mono_arch_create_vars (MonoCompile *cfg)
2084 {
2085         MonoMethodSignature *sig;
2086         CallInfo *cinfo;
2087         int i;
2088
2089         sig = mono_method_signature (cfg->method);
2090
2091         if (!cfg->arch.cinfo)
2092                 cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
2093         cinfo = cfg->arch.cinfo;
2094
2095         if (IS_HARD_FLOAT) {
2096                 for (i = 0; i < 2; i++) {
2097                         MonoInst *inst = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
2098                         inst->flags |= MONO_INST_VOLATILE;
2099
2100                         cfg->arch.vfp_scratch_slots [i] = (gpointer) inst;
2101                 }
2102         }
2103
2104         if (cinfo->ret.storage == RegTypeStructByVal)
2105                 cfg->ret_var_is_local = TRUE;
2106
2107         if (cinfo->ret.storage == RegTypeStructByAddr) {
2108                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
2109                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
2110                         printf ("vret_addr = ");
2111                         mono_print_ins (cfg->vret_addr);
2112                 }
2113         }
2114
2115         if (cfg->gen_sdb_seq_points) {
2116                 if (cfg->soft_breakpoints) {
2117                         MonoInst *ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2118                         ins->flags |= MONO_INST_VOLATILE;
2119                         cfg->arch.seq_point_read_var = ins;
2120
2121                         ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2122                         ins->flags |= MONO_INST_VOLATILE;
2123                         cfg->arch.seq_point_ss_method_var = ins;
2124
2125                         ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2126                         ins->flags |= MONO_INST_VOLATILE;
2127                         cfg->arch.seq_point_bp_method_var = ins;
2128
2129                         g_assert (!cfg->compile_aot);
2130                 } else if (cfg->compile_aot) {
2131                         MonoInst *ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2132                         ins->flags |= MONO_INST_VOLATILE;
2133                         cfg->arch.seq_point_info_var = ins;
2134
2135                         /* Allocate a separate variable for this to save 1 load per seq point */
2136                         ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2137                         ins->flags |= MONO_INST_VOLATILE;
2138                         cfg->arch.ss_trigger_page_var = ins;
2139                 }
2140         }
2141 }
2142
2143 static void
2144 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
2145 {
2146         MonoMethodSignature *tmp_sig;
2147         int sig_reg;
2148
2149         if (call->tail_call)
2150                 NOT_IMPLEMENTED;
2151
2152         g_assert (cinfo->sig_cookie.storage == RegTypeBase);
2153                         
2154         /*
2155          * mono_ArgIterator_Setup assumes the signature cookie is 
2156          * passed first and all the arguments which were before it are
2157          * passed on the stack after the signature. So compensate by 
2158          * passing a different signature.
2159          */
2160         tmp_sig = mono_metadata_signature_dup (call->signature);
2161         tmp_sig->param_count -= call->signature->sentinelpos;
2162         tmp_sig->sentinelpos = 0;
2163         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
2164
2165         sig_reg = mono_alloc_ireg (cfg);
2166         MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig);
2167
2168         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, cinfo->sig_cookie.offset, sig_reg);
2169 }
2170
2171 #ifdef ENABLE_LLVM
2172 LLVMCallInfo*
2173 mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
2174 {
2175         int i, n;
2176         CallInfo *cinfo;
2177         ArgInfo *ainfo;
2178         LLVMCallInfo *linfo;
2179
2180         n = sig->param_count + sig->hasthis;
2181
2182         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
2183
2184         linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
2185
2186         /*
2187          * LLVM always uses the native ABI while we use our own ABI, the
2188          * only difference is the handling of vtypes:
2189          * - we only pass/receive them in registers in some cases, and only 
2190          *   in 1 or 2 integer registers.
2191          */
2192         if (cinfo->ret.storage == RegTypeStructByAddr) {
2193                 /* Vtype returned using a hidden argument */
2194                 linfo->ret.storage = LLVMArgVtypeRetAddr;
2195                 linfo->vret_arg_index = cinfo->vret_arg_index;
2196         } else if (cinfo->ret.storage != RegTypeGeneral && cinfo->ret.storage != RegTypeNone && cinfo->ret.storage != RegTypeFP && cinfo->ret.storage != RegTypeIRegPair) {
2197                 cfg->exception_message = g_strdup ("unknown ret conv");
2198                 cfg->disable_llvm = TRUE;
2199                 return linfo;
2200         }
2201
2202         for (i = 0; i < n; ++i) {
2203                 ainfo = cinfo->args + i;
2204
2205                 linfo->args [i].storage = LLVMArgNone;
2206
2207                 switch (ainfo->storage) {
2208                 case RegTypeGeneral:
2209                 case RegTypeIRegPair:
2210                 case RegTypeBase:
2211                         linfo->args [i].storage = LLVMArgInIReg;
2212                         break;
2213                 case RegTypeStructByVal:
2214                         linfo->args [i].storage = LLVMArgAsIArgs;
2215                         linfo->args [i].nslots = ainfo->struct_size / sizeof (gpointer);
2216                         break;
2217                 default:
2218                         cfg->exception_message = g_strdup_printf ("ainfo->storage (%d)", ainfo->storage);
2219                         cfg->disable_llvm = TRUE;
2220                         break;
2221                 }
2222         }
2223
2224         return linfo;
2225 }
2226 #endif
2227
2228 void
2229 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
2230 {
2231         MonoInst *in, *ins;
2232         MonoMethodSignature *sig;
2233         int i, n;
2234         CallInfo *cinfo;
2235
2236         sig = call->signature;
2237         n = sig->param_count + sig->hasthis;
2238         
2239         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
2240
2241         switch (cinfo->ret.storage) {
2242         case RegTypeStructByVal:
2243                 /* The JIT will transform this into a normal call */
2244                 call->vret_in_reg = TRUE;
2245                 break;
2246         case RegTypeHFA:
2247                 /*
2248                  * The vtype is returned in registers, save the return area address in a local, and save the vtype into
2249                  * the location pointed to by it after call in emit_move_return_value ().
2250                  */
2251                 if (!cfg->arch.vret_addr_loc) {
2252                         cfg->arch.vret_addr_loc = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2253                         /* Prevent it from being register allocated or optimized away */
2254                         ((MonoInst*)cfg->arch.vret_addr_loc)->flags |= MONO_INST_VOLATILE;
2255                 }
2256
2257                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ((MonoInst*)cfg->arch.vret_addr_loc)->dreg, call->vret_var->dreg);
2258                 break;
2259         case RegTypeStructByAddr: {
2260                 MonoInst *vtarg;
2261                 MONO_INST_NEW (cfg, vtarg, OP_MOVE);
2262                 vtarg->sreg1 = call->vret_var->dreg;
2263                 vtarg->dreg = mono_alloc_preg (cfg);
2264                 MONO_ADD_INS (cfg->cbb, vtarg);
2265
2266                 mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
2267                 break;
2268         }
2269         default:
2270                 break;
2271         }
2272
2273         for (i = 0; i < n; ++i) {
2274                 ArgInfo *ainfo = cinfo->args + i;
2275                 MonoType *t;
2276
2277                 if (i >= sig->hasthis)
2278                         t = sig->params [i - sig->hasthis];
2279                 else
2280                         t = &mono_defaults.int_class->byval_arg;
2281                 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
2282
2283                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
2284                         /* Emit the signature cookie just before the implicit arguments */
2285                         emit_sig_cookie (cfg, call, cinfo);
2286                 }
2287
2288                 in = call->args [i];
2289
2290                 switch (ainfo->storage) {
2291                 case RegTypeGeneral:
2292                 case RegTypeIRegPair:
2293                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
2294                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2295                                 ins->dreg = mono_alloc_ireg (cfg);
2296                                 ins->sreg1 = in->dreg + 1;
2297                                 MONO_ADD_INS (cfg->cbb, ins);
2298                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
2299
2300                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2301                                 ins->dreg = mono_alloc_ireg (cfg);
2302                                 ins->sreg1 = in->dreg + 2;
2303                                 MONO_ADD_INS (cfg->cbb, ins);
2304                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
2305                         } else if (!t->byref && ((t->type == MONO_TYPE_R8) || (t->type == MONO_TYPE_R4))) {
2306                                 if (ainfo->size == 4) {
2307                                         if (IS_SOFT_FLOAT) {
2308                                                 /* mono_emit_call_args () have already done the r8->r4 conversion */
2309                                                 /* The converted value is in an int vreg */
2310                                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2311                                                 ins->dreg = mono_alloc_ireg (cfg);
2312                                                 ins->sreg1 = in->dreg;
2313                                                 MONO_ADD_INS (cfg->cbb, ins);
2314                                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
2315                                         } else {
2316                                                 int creg;
2317
2318                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
2319                                                 creg = mono_alloc_ireg (cfg);
2320                                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
2321                                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg, FALSE);
2322                                         }
2323                                 } else {
2324                                         if (IS_SOFT_FLOAT) {
2325                                                 MONO_INST_NEW (cfg, ins, OP_FGETLOW32);
2326                                                 ins->dreg = mono_alloc_ireg (cfg);
2327                                                 ins->sreg1 = in->dreg;
2328                                                 MONO_ADD_INS (cfg->cbb, ins);
2329                                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
2330
2331                                                 MONO_INST_NEW (cfg, ins, OP_FGETHIGH32);
2332                                                 ins->dreg = mono_alloc_ireg (cfg);
2333                                                 ins->sreg1 = in->dreg;
2334                                                 MONO_ADD_INS (cfg->cbb, ins);
2335                                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
2336                                         } else {
2337                                                 int creg;
2338
2339                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
2340                                                 creg = mono_alloc_ireg (cfg);
2341                                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
2342                                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg, FALSE);
2343                                                 creg = mono_alloc_ireg (cfg);
2344                                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8 + 4));
2345                                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg + 1, FALSE);
2346                                         }
2347                                 }
2348                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
2349                         } else {
2350                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2351                                 ins->dreg = mono_alloc_ireg (cfg);
2352                                 ins->sreg1 = in->dreg;
2353                                 MONO_ADD_INS (cfg->cbb, ins);
2354
2355                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
2356                         }
2357                         break;
2358                 case RegTypeStructByAddr:
2359                         NOT_IMPLEMENTED;
2360 #if 0
2361                         /* FIXME: where si the data allocated? */
2362                         arg->backend.reg3 = ainfo->reg;
2363                         call->used_iregs |= 1 << ainfo->reg;
2364                         g_assert_not_reached ();
2365 #endif
2366                         break;
2367                 case RegTypeStructByVal:
2368                 case RegTypeGSharedVtInReg:
2369                 case RegTypeGSharedVtOnStack:
2370                 case RegTypeHFA:
2371                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
2372                         ins->opcode = OP_OUTARG_VT;
2373                         ins->sreg1 = in->dreg;
2374                         ins->klass = in->klass;
2375                         ins->inst_p0 = call;
2376                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
2377                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
2378                         mono_call_inst_add_outarg_vt (cfg, call, ins);
2379                         MONO_ADD_INS (cfg->cbb, ins);
2380                         break;
2381                 case RegTypeBase:
2382                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
2383                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2384                         } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
2385                                 if (t->type == MONO_TYPE_R8) {
2386                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2387                                 } else {
2388                                         if (IS_SOFT_FLOAT)
2389                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2390                                         else
2391                                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2392                                 }
2393                         } else {
2394                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
2395                         }
2396                         break;
2397                 case RegTypeBaseGen:
2398                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
2399                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, (G_BYTE_ORDER == G_BIG_ENDIAN) ? in->dreg + 1 : in->dreg + 2);
2400                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
2401                                 ins->dreg = mono_alloc_ireg (cfg);
2402                                 ins->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN ? in->dreg + 2 : in->dreg + 1;
2403                                 MONO_ADD_INS (cfg->cbb, ins);
2404                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ARMREG_R3, FALSE);
2405                         } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
2406                                 int creg;
2407
2408                                 /* This should work for soft-float as well */
2409
2410                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
2411                                 creg = mono_alloc_ireg (cfg);
2412                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ARMREG_R3, FALSE);
2413                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
2414                                 creg = mono_alloc_ireg (cfg);
2415                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 4));
2416                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, creg);
2417                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
2418                         } else {
2419                                 g_assert_not_reached ();
2420                         }
2421                         break;
2422                 case RegTypeFP: {
2423                         int fdreg = mono_alloc_freg (cfg);
2424
2425                         if (ainfo->size == 8) {
2426                                 MONO_INST_NEW (cfg, ins, OP_FMOVE);
2427                                 ins->sreg1 = in->dreg;
2428                                 ins->dreg = fdreg;
2429                                 MONO_ADD_INS (cfg->cbb, ins);
2430
2431                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, TRUE);
2432                         } else {
2433                                 FloatArgData *fad;
2434
2435                                 /*
2436                                  * Mono's register allocator doesn't speak single-precision registers that
2437                                  * overlap double-precision registers (i.e. armhf). So we have to work around
2438                                  * the register allocator and load the value from memory manually.
2439                                  *
2440                                  * So we create a variable for the float argument and an instruction to store
2441                                  * the argument into the variable. We then store the list of these arguments
2442                                  * in cfg->float_args. This list is then used by emit_float_args later to
2443                                  * pass the arguments in the various call opcodes.
2444                                  *
2445                                  * This is not very nice, and we should really try to fix the allocator.
2446                                  */
2447
2448                                 MonoInst *float_arg = mono_compile_create_var (cfg, &mono_defaults.single_class->byval_arg, OP_LOCAL);
2449
2450                                 /* Make sure the instruction isn't seen as pointless and removed.
2451                                  */
2452                                 float_arg->flags |= MONO_INST_VOLATILE;
2453
2454                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, float_arg->dreg, in->dreg);
2455
2456                                 /* We use the dreg to look up the instruction later. The hreg is used to
2457                                  * emit the instruction that loads the value into the FP reg.
2458                                  */
2459                                 fad = mono_mempool_alloc0 (cfg->mempool, sizeof (FloatArgData));
2460                                 fad->vreg = float_arg->dreg;
2461                                 fad->hreg = ainfo->reg;
2462
2463                                 call->float_args = g_slist_append_mempool (cfg->mempool, call->float_args, fad);
2464                         }
2465
2466                         call->used_iregs |= 1 << ainfo->reg;
2467                         cfg->flags |= MONO_CFG_HAS_FPOUT;
2468                         break;
2469                 }
2470                 default:
2471                         g_assert_not_reached ();
2472                 }
2473         }
2474
2475         /* Handle the case where there are no implicit arguments */
2476         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
2477                 emit_sig_cookie (cfg, call, cinfo);
2478
2479         call->call_info = cinfo;
2480         call->stack_usage = cinfo->stack_usage;
2481 }
2482
2483 static void
2484 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *arg)
2485 {
2486         MonoInst *ins;
2487
2488         switch (storage) {
2489         case RegTypeFP:
2490                 MONO_INST_NEW (cfg, ins, OP_FMOVE);
2491                 ins->dreg = mono_alloc_freg (cfg);
2492                 ins->sreg1 = arg->dreg;
2493                 MONO_ADD_INS (cfg->cbb, ins);
2494                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
2495                 break;
2496         default:
2497                 g_assert_not_reached ();
2498                 break;
2499         }
2500 }
2501
2502 void
2503 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
2504 {
2505         MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
2506         MonoInst *load;
2507         ArgInfo *ainfo = ins->inst_p1;
2508         int ovf_size = ainfo->vtsize;
2509         int doffset = ainfo->offset;
2510         int struct_size = ainfo->struct_size;
2511         int i, soffset, dreg, tmpreg;
2512
2513         switch (ainfo->storage) {
2514         case RegTypeGSharedVtInReg:
2515                 /* Pass by addr */
2516                 mono_call_inst_add_outarg_reg (cfg, call, src->dreg, ainfo->reg, FALSE);
2517                 break;
2518         case RegTypeGSharedVtOnStack:
2519                 /* Pass by addr on stack */
2520                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, src->dreg);
2521                 break;
2522         case RegTypeHFA:
2523                 for (i = 0; i < ainfo->nregs; ++i) {
2524                         if (ainfo->esize == 4)
2525                                 MONO_INST_NEW (cfg, load, OP_LOADR4_MEMBASE);
2526                         else
2527                                 MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
2528                         load->dreg = mono_alloc_freg (cfg);
2529                         load->inst_basereg = src->dreg;
2530                         load->inst_offset = i * ainfo->esize;
2531                         MONO_ADD_INS (cfg->cbb, load);
2532
2533                         if (ainfo->esize == 4) {
2534                                 FloatArgData *fad;
2535
2536                                 /* See RegTypeFP in mono_arch_emit_call () */
2537                                 MonoInst *float_arg = mono_compile_create_var (cfg, &mono_defaults.single_class->byval_arg, OP_LOCAL);
2538                                 float_arg->flags |= MONO_INST_VOLATILE;
2539                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, float_arg->dreg, load->dreg);
2540
2541                                 fad = mono_mempool_alloc0 (cfg->mempool, sizeof (FloatArgData));
2542                                 fad->vreg = float_arg->dreg;
2543                                 fad->hreg = ainfo->reg + i;
2544
2545                                 call->float_args = g_slist_append_mempool (cfg->mempool, call->float_args, fad);
2546                         } else {
2547                                 add_outarg_reg (cfg, call, RegTypeFP, ainfo->reg + i, load);
2548                         }
2549                 }
2550                 break;
2551         default:
2552                 soffset = 0;
2553                 for (i = 0; i < ainfo->size; ++i) {
2554                         dreg = mono_alloc_ireg (cfg);
2555                         switch (struct_size) {
2556                         case 1:
2557                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, src->dreg, soffset);
2558                                 break;
2559                         case 2:
2560                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, dreg, src->dreg, soffset);
2561                                 break;
2562                         case 3:
2563                                 tmpreg = mono_alloc_ireg (cfg);
2564                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, src->dreg, soffset);
2565                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, tmpreg, src->dreg, soffset + 1);
2566                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, tmpreg, tmpreg, 8);
2567                                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, dreg, dreg, tmpreg);
2568                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, tmpreg, src->dreg, soffset + 2);
2569                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, tmpreg, tmpreg, 16);
2570                                 MONO_EMIT_NEW_BIALU (cfg, OP_IOR, dreg, dreg, tmpreg);
2571                                 break;
2572                         default:
2573                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
2574                                 break;
2575                         }
2576                         mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
2577                         soffset += sizeof (gpointer);
2578                         struct_size -= sizeof (gpointer);
2579                 }
2580                 //g_print ("vt size: %d at R%d + %d\n", doffset, vt->inst_basereg, vt->inst_offset);
2581                 if (ovf_size != 0)
2582                         mini_emit_memcpy (cfg, ARMREG_SP, doffset, src->dreg, soffset, MIN (ovf_size * sizeof (gpointer), struct_size), struct_size < 4 ? 1 : 4);
2583                 break;
2584         }
2585 }
2586
2587 void
2588 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
2589 {
2590         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
2591
2592         if (!ret->byref) {
2593                 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
2594                         MonoInst *ins;
2595
2596                         if (COMPILE_LLVM (cfg)) {
2597                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2598                         } else {
2599                                 MONO_INST_NEW (cfg, ins, OP_SETLRET);
2600                                 ins->sreg1 = val->dreg + 1;
2601                                 ins->sreg2 = val->dreg + 2;
2602                                 MONO_ADD_INS (cfg->cbb, ins);
2603                         }
2604                         return;
2605                 }
2606                 switch (arm_fpu) {
2607                 case MONO_ARM_FPU_NONE:
2608                         if (ret->type == MONO_TYPE_R8) {
2609                                 MonoInst *ins;
2610
2611                                 MONO_INST_NEW (cfg, ins, OP_SETFRET);
2612                                 ins->dreg = cfg->ret->dreg;
2613                                 ins->sreg1 = val->dreg;
2614                                 MONO_ADD_INS (cfg->cbb, ins);
2615                                 return;
2616                         }
2617                         if (ret->type == MONO_TYPE_R4) {
2618                                 /* Already converted to an int in method_to_ir () */
2619                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2620                                 return;
2621                         }
2622                         break;
2623                 case MONO_ARM_FPU_VFP:
2624                 case MONO_ARM_FPU_VFP_HARD:
2625                         if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
2626                                 MonoInst *ins;
2627
2628                                 MONO_INST_NEW (cfg, ins, OP_SETFRET);
2629                                 ins->dreg = cfg->ret->dreg;
2630                                 ins->sreg1 = val->dreg;
2631                                 MONO_ADD_INS (cfg->cbb, ins);
2632                                 return;
2633                         }
2634                         break;
2635                 default:
2636                         g_assert_not_reached ();
2637                 }
2638         }
2639
2640         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2641 }
2642
2643 #endif /* #ifndef DISABLE_JIT */
2644
2645 gboolean 
2646 mono_arch_is_inst_imm (gint64 imm)
2647 {
2648         return TRUE;
2649 }
2650
2651 typedef struct {
2652         MonoMethodSignature *sig;
2653         CallInfo *cinfo;
2654         MonoType *rtype;
2655         MonoType **param_types;
2656 } ArchDynCallInfo;
2657
2658 static gboolean
2659 dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
2660 {
2661         int i;
2662
2663         if (sig->hasthis + sig->param_count > PARAM_REGS + DYN_CALL_STACK_ARGS)
2664                 return FALSE;
2665
2666         switch (cinfo->ret.storage) {
2667         case RegTypeNone:
2668         case RegTypeGeneral:
2669         case RegTypeIRegPair:
2670         case RegTypeStructByAddr:
2671                 break;
2672         case RegTypeFP:
2673                 if (IS_VFP)
2674                         break;
2675                 else
2676                         return FALSE;
2677         default:
2678                 return FALSE;
2679         }
2680
2681         for (i = 0; i < cinfo->nargs; ++i) {
2682                 ArgInfo *ainfo = &cinfo->args [i];
2683                 int last_slot;
2684
2685                 switch (ainfo->storage) {
2686                 case RegTypeGeneral:
2687                         break;
2688                 case RegTypeIRegPair:
2689                         break;
2690                 case RegTypeBase:
2691                         if (ainfo->offset >= (DYN_CALL_STACK_ARGS * sizeof (gpointer)))
2692                                 return FALSE;
2693                         break;
2694                 case RegTypeStructByVal:
2695                         if (ainfo->size == 0)
2696                                 last_slot = PARAM_REGS + (ainfo->offset / 4) + ainfo->vtsize;
2697                         else
2698                                 last_slot = ainfo->reg + ainfo->size + ainfo->vtsize;
2699                         if (last_slot >= PARAM_REGS + DYN_CALL_STACK_ARGS)
2700                                 return FALSE;
2701                         break;
2702                 default:
2703                         return FALSE;
2704                 }
2705         }
2706
2707         // FIXME: Can't use cinfo only as it doesn't contain info about I8/float */
2708         for (i = 0; i < sig->param_count; ++i) {
2709                 MonoType *t = sig->params [i];
2710
2711                 if (t->byref)
2712                         continue;
2713
2714                 t = mini_replace_type (t);
2715
2716                 switch (t->type) {
2717                 case MONO_TYPE_R4:
2718                 case MONO_TYPE_R8:
2719                         if (IS_SOFT_FLOAT)
2720                                 return FALSE;
2721                         else
2722                                 break;
2723                         /*
2724                 case MONO_TYPE_I8:
2725                 case MONO_TYPE_U8:
2726                         return FALSE;
2727                         */
2728                 default:
2729                         break;
2730                 }
2731         }
2732
2733         return TRUE;
2734 }
2735
2736 MonoDynCallInfo*
2737 mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
2738 {
2739         ArchDynCallInfo *info;
2740         CallInfo *cinfo;
2741         int i;
2742
2743         cinfo = get_call_info (NULL, NULL, sig);
2744
2745         if (!dyn_call_supported (cinfo, sig)) {
2746                 g_free (cinfo);
2747                 return NULL;
2748         }
2749
2750         info = g_new0 (ArchDynCallInfo, 1);
2751         // FIXME: Preprocess the info to speed up start_dyn_call ()
2752         info->sig = sig;
2753         info->cinfo = cinfo;
2754         info->rtype = mini_type_get_underlying_type (NULL, sig->ret);
2755         info->param_types = g_new0 (MonoType*, sig->param_count);
2756         for (i = 0; i < sig->param_count; ++i)
2757                 info->param_types [i] = mini_type_get_underlying_type (NULL, sig->params [i]);
2758         
2759         return (MonoDynCallInfo*)info;
2760 }
2761
2762 void
2763 mono_arch_dyn_call_free (MonoDynCallInfo *info)
2764 {
2765         ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
2766
2767         g_free (ainfo->cinfo);
2768         g_free (ainfo);
2769 }
2770
2771 void
2772 mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len)
2773 {
2774         ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
2775         DynCallArgs *p = (DynCallArgs*)buf;
2776         int arg_index, greg, i, j, pindex;
2777         MonoMethodSignature *sig = dinfo->sig;
2778
2779         g_assert (buf_len >= sizeof (DynCallArgs));
2780
2781         p->res = 0;
2782         p->ret = ret;
2783
2784         arg_index = 0;
2785         greg = 0;
2786         pindex = 0;
2787
2788         if (sig->hasthis || dinfo->cinfo->vret_arg_index == 1) {
2789                 p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);
2790                 if (!sig->hasthis)
2791                         pindex = 1;
2792         }
2793
2794         if (dinfo->cinfo->ret.storage == RegTypeStructByAddr)
2795                 p->regs [greg ++] = (mgreg_t)ret;
2796
2797         for (i = pindex; i < sig->param_count; i++) {
2798                 MonoType *t = dinfo->param_types [i];
2799                 gpointer *arg = args [arg_index ++];
2800                 ArgInfo *ainfo = &dinfo->cinfo->args [i + sig->hasthis];
2801                 int slot = -1;
2802
2803                 if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeStructByVal)
2804                         slot = ainfo->reg;
2805                 else if (ainfo->storage == RegTypeBase)
2806                         slot = PARAM_REGS + (ainfo->offset / 4);
2807                 else
2808                         g_assert_not_reached ();
2809
2810                 if (t->byref) {
2811                         p->regs [slot] = (mgreg_t)*arg;
2812                         continue;
2813                 }
2814
2815                 switch (t->type) {
2816                 case MONO_TYPE_STRING:
2817                 case MONO_TYPE_CLASS:  
2818                 case MONO_TYPE_ARRAY:
2819                 case MONO_TYPE_SZARRAY:
2820                 case MONO_TYPE_OBJECT:
2821                 case MONO_TYPE_PTR:
2822                 case MONO_TYPE_I:
2823                 case MONO_TYPE_U:
2824                         p->regs [slot] = (mgreg_t)*arg;
2825                         break;
2826                 case MONO_TYPE_U1:
2827                         p->regs [slot] = *(guint8*)arg;
2828                         break;
2829                 case MONO_TYPE_I1:
2830                         p->regs [slot] = *(gint8*)arg;
2831                         break;
2832                 case MONO_TYPE_I2:
2833                         p->regs [slot] = *(gint16*)arg;
2834                         break;
2835                 case MONO_TYPE_U2:
2836                         p->regs [slot] = *(guint16*)arg;
2837                         break;
2838                 case MONO_TYPE_I4:
2839                         p->regs [slot] = *(gint32*)arg;
2840                         break;
2841                 case MONO_TYPE_U4:
2842                         p->regs [slot] = *(guint32*)arg;
2843                         break;
2844                 case MONO_TYPE_I8:
2845                 case MONO_TYPE_U8:
2846                         p->regs [slot ++] = (mgreg_t)arg [0];
2847                         p->regs [slot] = (mgreg_t)arg [1];
2848                         break;
2849                 case MONO_TYPE_R4:
2850                         p->regs [slot] = *(mgreg_t*)arg;
2851                         break;
2852                 case MONO_TYPE_R8:
2853                         p->regs [slot ++] = (mgreg_t)arg [0];
2854                         p->regs [slot] = (mgreg_t)arg [1];
2855                         break;
2856                 case MONO_TYPE_GENERICINST:
2857                         if (MONO_TYPE_IS_REFERENCE (t)) {
2858                                 p->regs [slot] = (mgreg_t)*arg;
2859                                 break;
2860                         } else {
2861                                 /* Fall though */
2862                         }
2863                 case MONO_TYPE_VALUETYPE:
2864                         g_assert (ainfo->storage == RegTypeStructByVal);
2865
2866                         if (ainfo->size == 0)
2867                                 slot = PARAM_REGS + (ainfo->offset / 4);
2868                         else
2869                                 slot = ainfo->reg;
2870
2871                         for (j = 0; j < ainfo->size + ainfo->vtsize; ++j)
2872                                 p->regs [slot ++] = ((mgreg_t*)arg) [j];
2873                         break;
2874                 default:
2875                         g_assert_not_reached ();
2876                 }
2877         }
2878 }
2879
2880 void
2881 mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
2882 {
2883         ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
2884         MonoType *ptype = ainfo->rtype;
2885         guint8 *ret = ((DynCallArgs*)buf)->ret;
2886         mgreg_t res = ((DynCallArgs*)buf)->res;
2887         mgreg_t res2 = ((DynCallArgs*)buf)->res2;
2888
2889         switch (ptype->type) {
2890         case MONO_TYPE_VOID:
2891                 *(gpointer*)ret = NULL;
2892                 break;
2893         case MONO_TYPE_STRING:
2894         case MONO_TYPE_CLASS:  
2895         case MONO_TYPE_ARRAY:
2896         case MONO_TYPE_SZARRAY:
2897         case MONO_TYPE_OBJECT:
2898         case MONO_TYPE_I:
2899         case MONO_TYPE_U:
2900         case MONO_TYPE_PTR:
2901                 *(gpointer*)ret = (gpointer)res;
2902                 break;
2903         case MONO_TYPE_I1:
2904                 *(gint8*)ret = res;
2905                 break;
2906         case MONO_TYPE_U1:
2907                 *(guint8*)ret = res;
2908                 break;
2909         case MONO_TYPE_I2:
2910                 *(gint16*)ret = res;
2911                 break;
2912         case MONO_TYPE_U2:
2913                 *(guint16*)ret = res;
2914                 break;
2915         case MONO_TYPE_I4:
2916                 *(gint32*)ret = res;
2917                 break;
2918         case MONO_TYPE_U4:
2919                 *(guint32*)ret = res;
2920                 break;
2921         case MONO_TYPE_I8:
2922         case MONO_TYPE_U8:
2923                 /* This handles endianness as well */
2924                 ((gint32*)ret) [0] = res;
2925                 ((gint32*)ret) [1] = res2;
2926                 break;
2927         case MONO_TYPE_GENERICINST:
2928                 if (MONO_TYPE_IS_REFERENCE (ptype)) {
2929                         *(gpointer*)ret = (gpointer)res;
2930                         break;
2931                 } else {
2932                         /* Fall though */
2933                 }
2934         case MONO_TYPE_VALUETYPE:
2935                 g_assert (ainfo->cinfo->ret.storage == RegTypeStructByAddr);
2936                 /* Nothing to do */
2937                 break;
2938         case MONO_TYPE_R4:
2939                 g_assert (IS_VFP);
2940                 *(float*)ret = *(float*)&res;
2941                 break;
2942         case MONO_TYPE_R8: {
2943                 mgreg_t regs [2];
2944
2945                 g_assert (IS_VFP);
2946                 regs [0] = res;
2947                 regs [1] = res2;
2948
2949                 *(double*)ret = *(double*)&regs;
2950                 break;
2951         }
2952         default:
2953                 g_assert_not_reached ();
2954         }
2955 }
2956
2957 #ifndef DISABLE_JIT
2958
2959 /*
2960  * Allow tracing to work with this interface (with an optional argument)
2961  */
2962
2963 void*
2964 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
2965 {
2966         guchar *code = p;
2967
2968         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
2969         ARM_MOV_REG_IMM8 (code, ARMREG_R1, 0); /* NULL ebp for now */
2970         code = mono_arm_emit_load_imm (code, ARMREG_R2, (guint32)func);
2971         code = emit_call_reg (code, ARMREG_R2);
2972         return code;
2973 }
2974
2975 enum {
2976         SAVE_NONE,
2977         SAVE_STRUCT,
2978         SAVE_ONE,
2979         SAVE_TWO,
2980         SAVE_ONE_FP,
2981         SAVE_TWO_FP
2982 };
2983
2984 void*
2985 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
2986 {
2987         guchar *code = p;
2988         int save_mode = SAVE_NONE;
2989         int offset;
2990         MonoMethod *method = cfg->method;
2991         MonoType *ret_type = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
2992         int rtype = ret_type->type;
2993         int save_offset = cfg->param_area;
2994         save_offset += 7;
2995         save_offset &= ~7;
2996         
2997         offset = code - cfg->native_code;
2998         /* we need about 16 instructions */
2999         if (offset > (cfg->code_size - 16 * 4)) {
3000                 cfg->code_size *= 2;
3001                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3002                 code = cfg->native_code + offset;
3003         }
3004         switch (rtype) {
3005         case MONO_TYPE_VOID:
3006                 /* special case string .ctor icall */
3007                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
3008                         save_mode = SAVE_ONE;
3009                 else
3010                         save_mode = SAVE_NONE;
3011                 break;
3012         case MONO_TYPE_I8:
3013         case MONO_TYPE_U8:
3014                 save_mode = SAVE_TWO;
3015                 break;
3016         case MONO_TYPE_R4:
3017                 if (IS_HARD_FLOAT)
3018                         save_mode = SAVE_ONE_FP;
3019                 else
3020                         save_mode = SAVE_ONE;
3021                 break;
3022         case MONO_TYPE_R8:
3023                 if (IS_HARD_FLOAT)
3024                         save_mode = SAVE_TWO_FP;
3025                 else
3026                         save_mode = SAVE_TWO;
3027                 break;
3028         case MONO_TYPE_GENERICINST:
3029                 if (!mono_type_generic_inst_is_valuetype (ret_type)) {
3030                         save_mode = SAVE_ONE;
3031                         break;
3032                 }
3033                 /* Fall through */
3034         case MONO_TYPE_VALUETYPE:
3035                 save_mode = SAVE_STRUCT;
3036                 break;
3037         default:
3038                 save_mode = SAVE_ONE;
3039                 break;
3040         }
3041
3042         switch (save_mode) {
3043         case SAVE_TWO:
3044                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
3045                 ARM_STR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
3046                 if (enable_arguments) {
3047                         ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_R1);
3048                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
3049                 }
3050                 break;
3051         case SAVE_ONE:
3052                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
3053                 if (enable_arguments) {
3054                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
3055                 }
3056                 break;
3057         case SAVE_ONE_FP:
3058                 ARM_FSTS (code, ARM_VFP_F0, cfg->frame_reg, save_offset);
3059                 if (enable_arguments) {
3060                         ARM_FMRS (code, ARMREG_R1, ARM_VFP_F0);
3061                 }
3062                 break;
3063         case SAVE_TWO_FP:
3064                 ARM_FSTD (code, ARM_VFP_D0, cfg->frame_reg, save_offset);
3065                 if (enable_arguments) {
3066                         ARM_FMDRR (code, ARMREG_R1, ARMREG_R2, ARM_VFP_D0);
3067                 }
3068                 break;
3069         case SAVE_STRUCT:
3070                 if (enable_arguments) {
3071                         /* FIXME: get the actual address  */
3072                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
3073                 }
3074                 break;
3075         case SAVE_NONE:
3076         default:
3077                 break;
3078         }
3079
3080         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
3081         code = mono_arm_emit_load_imm (code, ARMREG_IP, (guint32)func);
3082         code = emit_call_reg (code, ARMREG_IP);
3083
3084         switch (save_mode) {
3085         case SAVE_TWO:
3086                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
3087                 ARM_LDR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
3088                 break;
3089         case SAVE_ONE:
3090                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
3091                 break;
3092         case SAVE_ONE_FP:
3093                 ARM_FLDS (code, ARM_VFP_F0, cfg->frame_reg, save_offset);
3094                 break;
3095         case SAVE_TWO_FP:
3096                 ARM_FLDD (code, ARM_VFP_D0, cfg->frame_reg, save_offset);
3097                 break;
3098         case SAVE_NONE:
3099         default:
3100                 break;
3101         }
3102
3103         return code;
3104 }
3105
3106 /*
3107  * The immediate field for cond branches is big enough for all reasonable methods
3108  */
3109 #define EMIT_COND_BRANCH_FLAGS(ins,condcode) \
3110 if (0 && ins->inst_true_bb->native_offset) { \
3111         ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffffff); \
3112 } else { \
3113         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
3114         ARM_B_COND (code, (condcode), 0); \
3115 }
3116
3117 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_cc_table [(cond)])
3118
3119 /* emit an exception if condition is fail
3120  *
3121  * We assign the extra code used to throw the implicit exceptions
3122  * to cfg->bb_exit as far as the big branch handling is concerned
3123  */
3124 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(condcode,exc_name)            \
3125         do {                                                        \
3126                 mono_add_patch_info (cfg, code - cfg->native_code,   \
3127                                     MONO_PATCH_INFO_EXC, exc_name); \
3128                 ARM_BL_COND (code, (condcode), 0); \
3129         } while (0); 
3130
3131 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_cc_table [(cond)], (exc_name))
3132
3133 void
3134 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
3135 {
3136 }
3137
3138 void
3139 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
3140 {
3141         MonoInst *ins, *n;
3142
3143         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
3144                 MonoInst *last_ins = mono_inst_prev (ins, FILTER_IL_SEQ_POINT);
3145
3146                 switch (ins->opcode) {
3147                 case OP_MUL_IMM: 
3148                 case OP_IMUL_IMM: 
3149                         /* Already done by an arch-independent pass */
3150                         break;
3151                 case OP_LOAD_MEMBASE:
3152                 case OP_LOADI4_MEMBASE:
3153                         /* 
3154                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
3155                          * OP_LOAD_MEMBASE offset(basereg), reg
3156                          */
3157                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
3158                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
3159                             ins->inst_basereg == last_ins->inst_destbasereg &&
3160                             ins->inst_offset == last_ins->inst_offset) {
3161                                 if (ins->dreg == last_ins->sreg1) {
3162                                         MONO_DELETE_INS (bb, ins);
3163                                         continue;
3164                                 } else {
3165                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
3166                                         ins->opcode = OP_MOVE;
3167                                         ins->sreg1 = last_ins->sreg1;
3168                                 }
3169
3170                         /* 
3171                          * Note: reg1 must be different from the basereg in the second load
3172                          * OP_LOAD_MEMBASE offset(basereg), reg1
3173                          * OP_LOAD_MEMBASE offset(basereg), reg2
3174                          * -->
3175                          * OP_LOAD_MEMBASE offset(basereg), reg1
3176                          * OP_MOVE reg1, reg2
3177                          */
3178                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
3179                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
3180                               ins->inst_basereg != last_ins->dreg &&
3181                               ins->inst_basereg == last_ins->inst_basereg &&
3182                               ins->inst_offset == last_ins->inst_offset) {
3183
3184                                 if (ins->dreg == last_ins->dreg) {
3185                                         MONO_DELETE_INS (bb, ins);
3186                                         continue;
3187                                 } else {
3188                                         ins->opcode = OP_MOVE;
3189                                         ins->sreg1 = last_ins->dreg;
3190                                 }
3191
3192                                 //g_assert_not_reached ();
3193
3194 #if 0
3195                         /* 
3196                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
3197                          * OP_LOAD_MEMBASE offset(basereg), reg
3198                          * -->
3199                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
3200                          * OP_ICONST reg, imm
3201                          */
3202                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
3203                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
3204                                    ins->inst_basereg == last_ins->inst_destbasereg &&
3205                                    ins->inst_offset == last_ins->inst_offset) {
3206                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
3207                                 ins->opcode = OP_ICONST;
3208                                 ins->inst_c0 = last_ins->inst_imm;
3209                                 g_assert_not_reached (); // check this rule
3210 #endif
3211                         }
3212                         break;
3213                 case OP_LOADU1_MEMBASE:
3214                 case OP_LOADI1_MEMBASE:
3215                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
3216                                         ins->inst_basereg == last_ins->inst_destbasereg &&
3217                                         ins->inst_offset == last_ins->inst_offset) {
3218                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
3219                                 ins->sreg1 = last_ins->sreg1;                           
3220                         }
3221                         break;
3222                 case OP_LOADU2_MEMBASE:
3223                 case OP_LOADI2_MEMBASE:
3224                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
3225                                         ins->inst_basereg == last_ins->inst_destbasereg &&
3226                                         ins->inst_offset == last_ins->inst_offset) {
3227                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
3228                                 ins->sreg1 = last_ins->sreg1;                           
3229                         }
3230                         break;
3231                 case OP_MOVE:
3232                         ins->opcode = OP_MOVE;
3233                         /* 
3234                          * OP_MOVE reg, reg 
3235                          */
3236                         if (ins->dreg == ins->sreg1) {
3237                                 MONO_DELETE_INS (bb, ins);
3238                                 continue;
3239                         }
3240                         /* 
3241                          * OP_MOVE sreg, dreg 
3242                          * OP_MOVE dreg, sreg
3243                          */
3244                         if (last_ins && last_ins->opcode == OP_MOVE &&
3245                             ins->sreg1 == last_ins->dreg &&
3246                             ins->dreg == last_ins->sreg1) {
3247                                 MONO_DELETE_INS (bb, ins);
3248                                 continue;
3249                         }
3250                         break;
3251                 }
3252         }
3253 }
3254
3255 /* 
3256  * the branch_cc_table should maintain the order of these
3257  * opcodes.
3258 case CEE_BEQ:
3259 case CEE_BGE:
3260 case CEE_BGT:
3261 case CEE_BLE:
3262 case CEE_BLT:
3263 case CEE_BNE_UN:
3264 case CEE_BGE_UN:
3265 case CEE_BGT_UN:
3266 case CEE_BLE_UN:
3267 case CEE_BLT_UN:
3268  */
3269 static const guchar 
3270 branch_cc_table [] = {
3271         ARMCOND_EQ, 
3272         ARMCOND_GE, 
3273         ARMCOND_GT, 
3274         ARMCOND_LE,
3275         ARMCOND_LT, 
3276         
3277         ARMCOND_NE, 
3278         ARMCOND_HS, 
3279         ARMCOND_HI, 
3280         ARMCOND_LS,
3281         ARMCOND_LO
3282 };
3283
3284 #define ADD_NEW_INS(cfg,dest,op) do {       \
3285                 MONO_INST_NEW ((cfg), (dest), (op)); \
3286         mono_bblock_insert_before_ins (bb, ins, (dest)); \
3287         } while (0)
3288
3289 static int
3290 map_to_reg_reg_op (int op)
3291 {
3292         switch (op) {
3293         case OP_ADD_IMM:
3294                 return OP_IADD;
3295         case OP_SUB_IMM:
3296                 return OP_ISUB;
3297         case OP_AND_IMM:
3298                 return OP_IAND;
3299         case OP_COMPARE_IMM:
3300                 return OP_COMPARE;
3301         case OP_ICOMPARE_IMM:
3302                 return OP_ICOMPARE;
3303         case OP_ADDCC_IMM:
3304                 return OP_ADDCC;
3305         case OP_ADC_IMM:
3306                 return OP_ADC;
3307         case OP_SUBCC_IMM:
3308                 return OP_SUBCC;
3309         case OP_SBB_IMM:
3310                 return OP_SBB;
3311         case OP_OR_IMM:
3312                 return OP_IOR;
3313         case OP_XOR_IMM:
3314                 return OP_IXOR;
3315         case OP_LOAD_MEMBASE:
3316                 return OP_LOAD_MEMINDEX;
3317         case OP_LOADI4_MEMBASE:
3318                 return OP_LOADI4_MEMINDEX;
3319         case OP_LOADU4_MEMBASE:
3320                 return OP_LOADU4_MEMINDEX;
3321         case OP_LOADU1_MEMBASE:
3322                 return OP_LOADU1_MEMINDEX;
3323         case OP_LOADI2_MEMBASE:
3324                 return OP_LOADI2_MEMINDEX;
3325         case OP_LOADU2_MEMBASE:
3326                 return OP_LOADU2_MEMINDEX;
3327         case OP_LOADI1_MEMBASE:
3328                 return OP_LOADI1_MEMINDEX;
3329         case OP_STOREI1_MEMBASE_REG:
3330                 return OP_STOREI1_MEMINDEX;
3331         case OP_STOREI2_MEMBASE_REG:
3332                 return OP_STOREI2_MEMINDEX;
3333         case OP_STOREI4_MEMBASE_REG:
3334                 return OP_STOREI4_MEMINDEX;
3335         case OP_STORE_MEMBASE_REG:
3336                 return OP_STORE_MEMINDEX;
3337         case OP_STORER4_MEMBASE_REG:
3338                 return OP_STORER4_MEMINDEX;
3339         case OP_STORER8_MEMBASE_REG:
3340                 return OP_STORER8_MEMINDEX;
3341         case OP_STORE_MEMBASE_IMM:
3342                 return OP_STORE_MEMBASE_REG;
3343         case OP_STOREI1_MEMBASE_IMM:
3344                 return OP_STOREI1_MEMBASE_REG;
3345         case OP_STOREI2_MEMBASE_IMM:
3346                 return OP_STOREI2_MEMBASE_REG;
3347         case OP_STOREI4_MEMBASE_IMM:
3348                 return OP_STOREI4_MEMBASE_REG;
3349         }
3350         g_assert_not_reached ();
3351 }
3352
3353 /*
3354  * Remove from the instruction list the instructions that can't be
3355  * represented with very simple instructions with no register
3356  * requirements.
3357  */
3358 void
3359 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
3360 {
3361         MonoInst *ins, *temp, *last_ins = NULL;
3362         int rot_amount, imm8, low_imm;
3363
3364         MONO_BB_FOR_EACH_INS (bb, ins) {
3365 loop_start:
3366                 switch (ins->opcode) {
3367                 case OP_ADD_IMM:
3368                 case OP_SUB_IMM:
3369                 case OP_AND_IMM:
3370                 case OP_COMPARE_IMM:
3371                 case OP_ICOMPARE_IMM:
3372                 case OP_ADDCC_IMM:
3373                 case OP_ADC_IMM:
3374                 case OP_SUBCC_IMM:
3375                 case OP_SBB_IMM:
3376                 case OP_OR_IMM:
3377                 case OP_XOR_IMM:
3378                 case OP_IADD_IMM:
3379                 case OP_ISUB_IMM:
3380                 case OP_IAND_IMM:
3381                 case OP_IADC_IMM:
3382                 case OP_ISBB_IMM:
3383                 case OP_IOR_IMM:
3384                 case OP_IXOR_IMM:
3385                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
3386                                 ADD_NEW_INS (cfg, temp, OP_ICONST);
3387                                 temp->inst_c0 = ins->inst_imm;
3388                                 temp->dreg = mono_alloc_ireg (cfg);
3389                                 ins->sreg2 = temp->dreg;
3390                                 ins->opcode = mono_op_imm_to_op (ins->opcode);
3391                         }
3392                         if (ins->opcode == OP_SBB || ins->opcode == OP_ISBB || ins->opcode == OP_SUBCC)
3393                                 goto loop_start;
3394                         else
3395                                 break;
3396                 case OP_MUL_IMM:
3397                 case OP_IMUL_IMM:
3398                         if (ins->inst_imm == 1) {
3399                                 ins->opcode = OP_MOVE;
3400                                 break;
3401                         }
3402                         if (ins->inst_imm == 0) {
3403                                 ins->opcode = OP_ICONST;
3404                                 ins->inst_c0 = 0;
3405                                 break;
3406                         }
3407                         imm8 = mono_is_power_of_two (ins->inst_imm);
3408                         if (imm8 > 0) {
3409                                 ins->opcode = OP_SHL_IMM;
3410                                 ins->inst_imm = imm8;
3411                                 break;
3412                         }
3413                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3414                         temp->inst_c0 = ins->inst_imm;
3415                         temp->dreg = mono_alloc_ireg (cfg);
3416                         ins->sreg2 = temp->dreg;
3417                         ins->opcode = OP_IMUL;
3418                         break;
3419                 case OP_SBB:
3420                 case OP_ISBB:
3421                 case OP_SUBCC:
3422                 case OP_ISUBCC:
3423                         if (ins->next  && (ins->next->opcode == OP_COND_EXC_C || ins->next->opcode == OP_COND_EXC_IC))
3424                                 /* ARM sets the C flag to 1 if there was _no_ overflow */
3425                                 ins->next->opcode = OP_COND_EXC_NC;
3426                         break;
3427                 case OP_IDIV_IMM:
3428                 case OP_IDIV_UN_IMM:
3429                 case OP_IREM_IMM:
3430                 case OP_IREM_UN_IMM:
3431                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3432                         temp->inst_c0 = ins->inst_imm;
3433                         temp->dreg = mono_alloc_ireg (cfg);
3434                         ins->sreg2 = temp->dreg;
3435                         ins->opcode = mono_op_imm_to_op (ins->opcode);
3436                         break;
3437                 case OP_LOCALLOC_IMM:
3438                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3439                         temp->inst_c0 = ins->inst_imm;
3440                         temp->dreg = mono_alloc_ireg (cfg);
3441                         ins->sreg1 = temp->dreg;
3442                         ins->opcode = OP_LOCALLOC;
3443                         break;
3444                 case OP_LOAD_MEMBASE:
3445                 case OP_LOADI4_MEMBASE:
3446                 case OP_LOADU4_MEMBASE:
3447                 case OP_LOADU1_MEMBASE:
3448                         /* we can do two things: load the immed in a register
3449                          * and use an indexed load, or see if the immed can be
3450                          * represented as an ad_imm + a load with a smaller offset
3451                          * that fits. We just do the first for now, optimize later.
3452                          */
3453                         if (arm_is_imm12 (ins->inst_offset))
3454                                 break;
3455                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3456                         temp->inst_c0 = ins->inst_offset;
3457                         temp->dreg = mono_alloc_ireg (cfg);
3458                         ins->sreg2 = temp->dreg;
3459                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3460                         break;
3461                 case OP_LOADI2_MEMBASE:
3462                 case OP_LOADU2_MEMBASE:
3463                 case OP_LOADI1_MEMBASE:
3464                         if (arm_is_imm8 (ins->inst_offset))
3465                                 break;
3466                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3467                         temp->inst_c0 = ins->inst_offset;
3468                         temp->dreg = mono_alloc_ireg (cfg);
3469                         ins->sreg2 = temp->dreg;
3470                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3471                         break;
3472                 case OP_LOADR4_MEMBASE:
3473                 case OP_LOADR8_MEMBASE:
3474                         if (arm_is_fpimm8 (ins->inst_offset))
3475                                 break;
3476                         low_imm = ins->inst_offset & 0x1ff;
3477                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~0x1ff, &rot_amount)) >= 0) {
3478                                 ADD_NEW_INS (cfg, temp, OP_ADD_IMM);
3479                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
3480                                 temp->sreg1 = ins->inst_basereg;
3481                                 temp->dreg = mono_alloc_ireg (cfg);
3482                                 ins->inst_basereg = temp->dreg;
3483                                 ins->inst_offset = low_imm;
3484                         } else {
3485                                 MonoInst *add_ins;
3486
3487                                 ADD_NEW_INS (cfg, temp, OP_ICONST);
3488                                 temp->inst_c0 = ins->inst_offset;
3489                                 temp->dreg = mono_alloc_ireg (cfg);
3490
3491                                 ADD_NEW_INS (cfg, add_ins, OP_IADD);
3492                                 add_ins->sreg1 = ins->inst_basereg;
3493                                 add_ins->sreg2 = temp->dreg;
3494                                 add_ins->dreg = mono_alloc_ireg (cfg);
3495
3496                                 ins->inst_basereg = add_ins->dreg;
3497                                 ins->inst_offset = 0;
3498                         }
3499                         break;
3500                 case OP_STORE_MEMBASE_REG:
3501                 case OP_STOREI4_MEMBASE_REG:
3502                 case OP_STOREI1_MEMBASE_REG:
3503                         if (arm_is_imm12 (ins->inst_offset))
3504                                 break;
3505                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3506                         temp->inst_c0 = ins->inst_offset;
3507                         temp->dreg = mono_alloc_ireg (cfg);
3508                         ins->sreg2 = temp->dreg;
3509                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3510                         break;
3511                 case OP_STOREI2_MEMBASE_REG:
3512                         if (arm_is_imm8 (ins->inst_offset))
3513                                 break;
3514                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3515                         temp->inst_c0 = ins->inst_offset;
3516                         temp->dreg = mono_alloc_ireg (cfg);
3517                         ins->sreg2 = temp->dreg;
3518                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3519                         break;
3520                 case OP_STORER4_MEMBASE_REG:
3521                 case OP_STORER8_MEMBASE_REG:
3522                         if (arm_is_fpimm8 (ins->inst_offset))
3523                                 break;
3524                         low_imm = ins->inst_offset & 0x1ff;
3525                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~ 0x1ff, &rot_amount)) >= 0 && arm_is_fpimm8 (low_imm)) {
3526                                 ADD_NEW_INS (cfg, temp, OP_ADD_IMM);
3527                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
3528                                 temp->sreg1 = ins->inst_destbasereg;
3529                                 temp->dreg = mono_alloc_ireg (cfg);
3530                                 ins->inst_destbasereg = temp->dreg;
3531                                 ins->inst_offset = low_imm;
3532                         } else {
3533                                 MonoInst *add_ins;
3534
3535                                 ADD_NEW_INS (cfg, temp, OP_ICONST);
3536                                 temp->inst_c0 = ins->inst_offset;
3537                                 temp->dreg = mono_alloc_ireg (cfg);
3538
3539                                 ADD_NEW_INS (cfg, add_ins, OP_IADD);
3540                                 add_ins->sreg1 = ins->inst_destbasereg;
3541                                 add_ins->sreg2 = temp->dreg;
3542                                 add_ins->dreg = mono_alloc_ireg (cfg);
3543
3544                                 ins->inst_destbasereg = add_ins->dreg;
3545                                 ins->inst_offset = 0;
3546                         }
3547                         break;
3548                 case OP_STORE_MEMBASE_IMM:
3549                 case OP_STOREI1_MEMBASE_IMM:
3550                 case OP_STOREI2_MEMBASE_IMM:
3551                 case OP_STOREI4_MEMBASE_IMM:
3552                         ADD_NEW_INS (cfg, temp, OP_ICONST);
3553                         temp->inst_c0 = ins->inst_imm;
3554                         temp->dreg = mono_alloc_ireg (cfg);
3555                         ins->sreg1 = temp->dreg;
3556                         ins->opcode = map_to_reg_reg_op (ins->opcode);
3557                         last_ins = temp;
3558                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
3559                 case OP_FCOMPARE:
3560                 case OP_RCOMPARE: {
3561                         gboolean swap = FALSE;
3562                         int reg;
3563
3564                         if (!ins->next) {
3565                                 /* Optimized away */
3566                                 NULLIFY_INS (ins);
3567                                 break;
3568                         }
3569
3570                         /* Some fp compares require swapped operands */
3571                         switch (ins->next->opcode) {
3572                         case OP_FBGT:
3573                                 ins->next->opcode = OP_FBLT;
3574                                 swap = TRUE;
3575                                 break;
3576                         case OP_FBGT_UN:
3577                                 ins->next->opcode = OP_FBLT_UN;
3578                                 swap = TRUE;
3579                                 break;
3580                         case OP_FBLE:
3581                                 ins->next->opcode = OP_FBGE;
3582                                 swap = TRUE;
3583                                 break;
3584                         case OP_FBLE_UN:
3585                                 ins->next->opcode = OP_FBGE_UN;
3586                                 swap = TRUE;
3587                                 break;
3588                         default:
3589                                 break;
3590                         }
3591                         if (swap) {
3592                                 reg = ins->sreg1;
3593                                 ins->sreg1 = ins->sreg2;
3594                                 ins->sreg2 = reg;
3595                         }
3596                         break;
3597                 }
3598                 }
3599
3600                 last_ins = ins;
3601         }
3602         bb->last_ins = last_ins;
3603         bb->max_vreg = cfg->next_vreg;
3604 }
3605
3606 void
3607 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
3608 {
3609         MonoInst *ins;
3610
3611         if (long_ins->opcode == OP_LNEG) {
3612                 ins = long_ins;
3613                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, ins->dreg + 1, ins->sreg1 + 1, 0);
3614                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
3615                 NULLIFY_INS (ins);
3616         }
3617 }
3618
3619 static guchar*
3620 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3621 {
3622         /* sreg is a float, dreg is an integer reg  */
3623         if (IS_VFP) {
3624                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
3625                 if (is_signed)
3626                         ARM_TOSIZD (code, vfp_scratch1, sreg);
3627                 else
3628                         ARM_TOUIZD (code, vfp_scratch1, sreg);
3629                 ARM_FMRS (code, dreg, vfp_scratch1);
3630                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
3631         }
3632         if (!is_signed) {
3633                 if (size == 1)
3634                         ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff);
3635                 else if (size == 2) {
3636                         ARM_SHL_IMM (code, dreg, dreg, 16);
3637                         ARM_SHR_IMM (code, dreg, dreg, 16);
3638                 }
3639         } else {
3640                 if (size == 1) {
3641                         ARM_SHL_IMM (code, dreg, dreg, 24);
3642                         ARM_SAR_IMM (code, dreg, dreg, 24);
3643                 } else if (size == 2) {
3644                         ARM_SHL_IMM (code, dreg, dreg, 16);
3645                         ARM_SAR_IMM (code, dreg, dreg, 16);
3646                 }
3647         }
3648         return code;
3649 }
3650
3651 static guchar*
3652 emit_r4_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
3653 {
3654         /* sreg is a float, dreg is an integer reg  */
3655         g_assert (IS_VFP);
3656         code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
3657         if (is_signed)
3658                 ARM_TOSIZS (code, vfp_scratch1, sreg);
3659         else
3660                 ARM_TOUIZS (code, vfp_scratch1, sreg);
3661         ARM_FMRS (code, dreg, vfp_scratch1);
3662         code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
3663
3664         if (!is_signed) {
3665                 if (size == 1)
3666                         ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff);
3667                 else if (size == 2) {
3668                         ARM_SHL_IMM (code, dreg, dreg, 16);
3669                         ARM_SHR_IMM (code, dreg, dreg, 16);
3670                 }
3671         } else {
3672                 if (size == 1) {
3673                         ARM_SHL_IMM (code, dreg, dreg, 24);
3674                         ARM_SAR_IMM (code, dreg, dreg, 24);
3675                 } else if (size == 2) {
3676                         ARM_SHL_IMM (code, dreg, dreg, 16);
3677                         ARM_SAR_IMM (code, dreg, dreg, 16);
3678                 }
3679         }
3680         return code;
3681 }
3682
3683 #endif /* #ifndef DISABLE_JIT */
3684
3685 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
3686
3687 static void
3688 emit_thunk (guint8 *code, gconstpointer target)
3689 {
3690         guint8 *p = code;
3691
3692         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
3693         if (thumb_supported)
3694                 ARM_BX (code, ARMREG_IP);
3695         else
3696                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
3697         *(guint32*)code = (guint32)target;
3698         code += 4;
3699         mono_arch_flush_icache (p, code - p);
3700 }
3701
3702 static void
3703 handle_thunk (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target)
3704 {
3705         MonoJitInfo *ji = NULL;
3706         MonoThunkJitInfo *info;
3707         guint8 *thunks, *p;
3708         int thunks_size;
3709         guint8 *orig_target;
3710         guint8 *target_thunk;
3711
3712         if (!domain)
3713                 domain = mono_domain_get ();
3714
3715         if (cfg) {
3716                 /*
3717                  * This can be called multiple times during JITting,
3718                  * save the current position in cfg->arch to avoid
3719                  * doing a O(n^2) search.
3720                  */
3721                 if (!cfg->arch.thunks) {
3722                         cfg->arch.thunks = cfg->thunks;
3723                         cfg->arch.thunks_size = cfg->thunk_area;
3724                 }
3725                 thunks = cfg->arch.thunks;
3726                 thunks_size = cfg->arch.thunks_size;
3727                 if (!thunks_size) {
3728                         g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, mono_method_full_name (cfg->method, TRUE));
3729                         g_assert_not_reached ();
3730                 }
3731
3732                 g_assert (*(guint32*)thunks == 0);
3733                 emit_thunk (thunks, target);
3734                 arm_patch (code, thunks);
3735
3736                 cfg->arch.thunks += THUNK_SIZE;
3737                 cfg->arch.thunks_size -= THUNK_SIZE;
3738         } else {
3739                 ji = mini_jit_info_table_find (domain, (char*)code, NULL);
3740                 g_assert (ji);
3741                 info = mono_jit_info_get_thunk_info (ji);
3742                 g_assert (info);
3743
3744                 thunks = (guint8*)ji->code_start + info->thunks_offset;
3745                 thunks_size = info->thunks_size;
3746
3747                 orig_target = mono_arch_get_call_target (code + 4);
3748
3749                 mono_mini_arch_lock ();
3750
3751                 target_thunk = NULL;
3752                 if (orig_target >= thunks && orig_target < thunks + thunks_size) {
3753                         /* The call already points to a thunk, because of trampolines etc. */
3754                         target_thunk = orig_target;
3755                 } else {
3756                         for (p = thunks; p < thunks + thunks_size; p += THUNK_SIZE) {
3757                                 if (((guint32*)p) [0] == 0) {
3758                                         /* Free entry */
3759                                         target_thunk = p;
3760                                         break;
3761                                 }
3762                         }
3763                 }
3764
3765                 //printf ("THUNK: %p %p %p\n", code, target, target_thunk);
3766
3767                 if (!target_thunk) {
3768                         mono_mini_arch_unlock ();
3769                         g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, cfg ? mono_method_full_name (cfg->method, TRUE) : mono_method_full_name (jinfo_get_method (ji), TRUE));
3770                         g_assert_not_reached ();
3771                 }
3772
3773                 emit_thunk (target_thunk, target);
3774                 arm_patch (code, target_thunk);
3775                 mono_arch_flush_icache (code, 4);
3776
3777                 mono_mini_arch_unlock ();
3778         }
3779 }
3780
3781 static void
3782 arm_patch_general (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target)
3783 {
3784         guint32 *code32 = (void*)code;
3785         guint32 ins = *code32;
3786         guint32 prim = (ins >> 25) & 7;
3787         guint32 tval = GPOINTER_TO_UINT (target);
3788
3789         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
3790         if (prim == 5) { /* 101b */
3791                 /* the diff starts 8 bytes from the branch opcode */
3792                 gint diff = target - code - 8;
3793                 gint tbits;
3794                 gint tmask = 0xffffffff;
3795                 if (tval & 1) { /* entering thumb mode */
3796                         diff = target - 1 - code - 8;
3797                         g_assert (thumb_supported);
3798                         tbits = 0xf << 28; /* bl->blx bit pattern */
3799                         g_assert ((ins & (1 << 24))); /* it must be a bl, not b instruction */
3800                         /* this low bit of the displacement is moved to bit 24 in the instruction encoding */
3801                         if (diff & 2) {
3802                                 tbits |= 1 << 24;
3803                         }
3804                         tmask = ~(1 << 24); /* clear the link bit */
3805                         /*g_print ("blx to thumb: target: %p, code: %p, diff: %d, mask: %x\n", target, code, diff, tmask);*/
3806                 } else {
3807                         tbits = 0;
3808                 }
3809                 if (diff >= 0) {
3810                         if (diff <= 33554431) {
3811                                 diff >>= 2;
3812                                 ins = (ins & 0xff000000) | diff;
3813                                 ins &= tmask;
3814                                 *code32 = ins | tbits;
3815                                 return;
3816                         }
3817                 } else {
3818                         /* diff between 0 and -33554432 */
3819                         if (diff >= -33554432) {
3820                                 diff >>= 2;
3821                                 ins = (ins & 0xff000000) | (diff & ~0xff000000);
3822                                 ins &= tmask;
3823                                 *code32 = ins | tbits;
3824                                 return;
3825                         }
3826                 }
3827                 
3828                 handle_thunk (cfg, domain, code, target);
3829                 return;
3830         }
3831
3832 #ifdef USE_JUMP_TABLES
3833         {
3834                 gpointer *jte = mono_jumptable_get_entry (code);
3835                 g_assert (jte);
3836                 jte [0] = (gpointer) target;
3837         }
3838 #else
3839         /*
3840          * The alternative call sequences looks like this:
3841          *
3842          *      ldr ip, [pc] // loads the address constant
3843          *      b 1f         // jumps around the constant
3844          *      address constant embedded in the code
3845          *   1f:
3846          *      mov lr, pc
3847          *      mov pc, ip
3848          *
3849          * There are two cases for patching:
3850          * a) at the end of method emission: in this case code points to the start
3851          *    of the call sequence
3852          * b) during runtime patching of the call site: in this case code points
3853          *    to the mov pc, ip instruction
3854          *
3855          * We have to handle also the thunk jump code sequence:
3856          *
3857          *      ldr ip, [pc]
3858          *      mov pc, ip
3859          *      address constant // execution never reaches here
3860          */
3861         if ((ins & 0x0ffffff0) == 0x12fff10) {
3862                 /* Branch and exchange: the address is constructed in a reg 
3863                  * We can patch BX when the code sequence is the following:
3864                  *  ldr     ip, [pc, #0]    ; 0x8
3865                  *  b       0xc
3866                  *  .word code_ptr
3867                  *  mov     lr, pc
3868                  *  bx      ips
3869                  * */
3870                 guint32 ccode [4];
3871                 guint8 *emit = (guint8*)ccode;
3872                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
3873                 ARM_B (emit, 0);
3874                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
3875                 ARM_BX (emit, ARMREG_IP);
3876
3877                 /*patching from magic trampoline*/
3878                 if (ins == ccode [3]) {
3879                         g_assert (code32 [-4] == ccode [0]);
3880                         g_assert (code32 [-3] == ccode [1]);
3881                         g_assert (code32 [-1] == ccode [2]);
3882                         code32 [-2] = (guint32)target;
3883                         return;
3884                 }
3885                 /*patching from JIT*/
3886                 if (ins == ccode [0]) {
3887                         g_assert (code32 [1] == ccode [1]);
3888                         g_assert (code32 [3] == ccode [2]);
3889                         g_assert (code32 [4] == ccode [3]);
3890                         code32 [2] = (guint32)target;
3891                         return;
3892                 }
3893                 g_assert_not_reached ();
3894         } else if ((ins & 0x0ffffff0) == 0x12fff30) {
3895                 /*
3896                  * ldr ip, [pc, #0]
3897                  * b 0xc
3898                  * .word code_ptr
3899                  * blx ip
3900                  */
3901                 guint32 ccode [4];
3902                 guint8 *emit = (guint8*)ccode;
3903                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
3904                 ARM_B (emit, 0);
3905                 ARM_BLX_REG (emit, ARMREG_IP);
3906
3907                 g_assert (code32 [-3] == ccode [0]);
3908                 g_assert (code32 [-2] == ccode [1]);
3909                 g_assert (code32 [0] == ccode [2]);
3910
3911                 code32 [-1] = (guint32)target;
3912         } else {
3913                 guint32 ccode [4];
3914                 guint32 *tmp = ccode;
3915                 guint8 *emit = (guint8*)tmp;
3916                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
3917                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
3918                 ARM_MOV_REG_REG (emit, ARMREG_PC, ARMREG_IP);
3919                 ARM_BX (emit, ARMREG_IP);
3920                 if (ins == ccode [2]) {
3921                         g_assert_not_reached (); // should be -2 ...
3922                         code32 [-1] = (guint32)target;
3923                         return;
3924                 }
3925                 if (ins == ccode [0]) {
3926                         /* handles both thunk jump code and the far call sequence */
3927                         code32 [2] = (guint32)target;
3928                         return;
3929                 }
3930                 g_assert_not_reached ();
3931         }
3932 //      g_print ("patched with 0x%08x\n", ins);
3933 #endif
3934 }
3935
3936 void
3937 arm_patch (guchar *code, const guchar *target)
3938 {
3939         arm_patch_general (NULL, NULL, code, target);
3940 }
3941
3942 /* 
3943  * Return the >= 0 uimm8 value if val can be represented with a byte + rotation
3944  * (with the rotation amount in *rot_amount. rot_amount is already adjusted
3945  * to be used with the emit macros.
3946  * Return -1 otherwise.
3947  */
3948 int
3949 mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount)
3950 {
3951         guint32 res, i;
3952         for (i = 0; i < 31; i+= 2) {
3953                 res = (val << (32 - i)) | (val >> i);
3954                 if (res & ~0xff)
3955                         continue;
3956                 *rot_amount = i? 32 - i: 0;
3957                 return res;
3958         }
3959         return -1;
3960 }
3961
3962 /*
3963  * Emits in code a sequence of instructions that load the value 'val'
3964  * into the dreg register. Uses at most 4 instructions.
3965  */
3966 guint8*
3967 mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
3968 {
3969         int imm8, rot_amount;
3970 #if 0
3971         ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
3972         /* skip the constant pool */
3973         ARM_B (code, 0);
3974         *(int*)code = val;
3975         code += 4;
3976         return code;
3977 #endif
3978         if ((imm8 = mono_arm_is_rotated_imm8 (val, &rot_amount)) >= 0) {
3979                 ARM_MOV_REG_IMM (code, dreg, imm8, rot_amount);
3980         } else if ((imm8 = mono_arm_is_rotated_imm8 (~val, &rot_amount)) >= 0) {
3981                 ARM_MVN_REG_IMM (code, dreg, imm8, rot_amount);
3982         } else {
3983                 if (v7_supported) {
3984                         ARM_MOVW_REG_IMM (code, dreg, val & 0xffff);
3985                         if (val >> 16)
3986                                 ARM_MOVT_REG_IMM (code, dreg, (val >> 16) & 0xffff);
3987                         return code;
3988                 }
3989                 if (val & 0xFF) {
3990                         ARM_MOV_REG_IMM8 (code, dreg, (val & 0xFF));
3991                         if (val & 0xFF00) {
3992                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
3993                         }
3994                         if (val & 0xFF0000) {
3995                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
3996                         }
3997                         if (val & 0xFF000000) {
3998                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
3999                         }
4000                 } else if (val & 0xFF00) {
4001                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF00) >> 8, 24);
4002                         if (val & 0xFF0000) {
4003                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
4004                         }
4005                         if (val & 0xFF000000) {
4006                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
4007                         }
4008                 } else if (val & 0xFF0000) {
4009                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF0000) >> 16, 16);
4010                         if (val & 0xFF000000) {
4011                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
4012                         }
4013                 }
4014                 //g_assert_not_reached ();
4015         }
4016         return code;
4017 }
4018
4019 gboolean
4020 mono_arm_thumb_supported (void)
4021 {
4022         return thumb_supported;
4023 }
4024
4025 #ifndef DISABLE_JIT
4026
4027 static guint8*
4028 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
4029 {
4030         CallInfo *cinfo;
4031         MonoCallInst *call;
4032
4033         call = (MonoCallInst*)ins;
4034         cinfo = call->call_info;
4035
4036         switch (cinfo->ret.storage) {
4037         case RegTypeHFA: {
4038                 MonoInst *loc = cfg->arch.vret_addr_loc;
4039                 int i;
4040
4041                 /* Load the destination address */
4042                 g_assert (loc && loc->opcode == OP_REGOFFSET);
4043
4044                 if (arm_is_imm12 (loc->inst_offset)) {
4045                         ARM_LDR_IMM (code, ARMREG_LR, loc->inst_basereg, loc->inst_offset);
4046                 } else {
4047                         code = mono_arm_emit_load_imm (code, ARMREG_LR, loc->inst_offset);
4048                         ARM_LDR_REG_REG (code, ARMREG_LR, loc->inst_basereg, ARMREG_LR);
4049                 }
4050                 for (i = 0; i < cinfo->ret.nregs; ++i) {
4051                         if (cinfo->ret.esize == 4)
4052                                 ARM_FSTS (code, cinfo->ret.reg + i, ARMREG_LR, i * 4);
4053                         else
4054                                 ARM_FSTD (code, cinfo->ret.reg + (i * 2), ARMREG_LR, i * 8);
4055                 }
4056                 return code;
4057         }
4058         default:
4059                 break;
4060         }
4061
4062         switch (ins->opcode) {
4063         case OP_FCALL:
4064         case OP_FCALL_REG:
4065         case OP_FCALL_MEMBASE:
4066                 if (IS_VFP) {
4067                         MonoType *sig_ret = mini_type_get_underlying_type (NULL, ((MonoCallInst*)ins)->signature->ret);
4068                         if (sig_ret->type == MONO_TYPE_R4) {
4069                                 if (IS_HARD_FLOAT) {
4070                                         ARM_CVTS (code, ins->dreg, ARM_VFP_F0);
4071                                 } else {
4072                                         ARM_FMSR (code, ins->dreg, ARMREG_R0);
4073                                         ARM_CVTS (code, ins->dreg, ins->dreg);
4074                                 }
4075                         } else {
4076                                 if (IS_HARD_FLOAT) {
4077                                         ARM_CPYD (code, ins->dreg, ARM_VFP_D0);
4078                                 } else {
4079                                         ARM_FMDRR (code, ARMREG_R0, ARMREG_R1, ins->dreg);
4080                                 }
4081                         }
4082                 }
4083                 break;
4084         case OP_RCALL:
4085         case OP_RCALL_REG:
4086         case OP_RCALL_MEMBASE: {
4087                 MonoType *sig_ret;
4088
4089                 g_assert (IS_VFP);
4090
4091                 sig_ret = mini_type_get_underlying_type (NULL, ((MonoCallInst*)ins)->signature->ret);
4092                 g_assert (sig_ret->type == MONO_TYPE_R4);
4093                 if (IS_HARD_FLOAT) {
4094                         ARM_CPYS (code, ins->dreg, ARM_VFP_F0);
4095                 } else {
4096                         ARM_FMSR (code, ins->dreg, ARMREG_R0);
4097                         ARM_CPYS (code, ins->dreg, ins->dreg);
4098                 }
4099                 break;
4100         }
4101         default:
4102                 break;
4103         }
4104
4105         return code;
4106 }
4107
4108 void
4109 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
4110 {
4111         MonoInst *ins;
4112         MonoCallInst *call;
4113         guint offset;
4114         guint8 *code = cfg->native_code + cfg->code_len;
4115         MonoInst *last_ins = NULL;
4116         guint last_offset = 0;
4117         int max_len, cpos;
4118         int imm8, rot_amount;
4119
4120         /* we don't align basic blocks of loops on arm */
4121
4122         if (cfg->verbose_level > 2)
4123                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
4124
4125         cpos = bb->max_offset;
4126
4127         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
4128                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
4129                 //g_assert (!mono_compile_aot);
4130                 //cpos += 6;
4131                 //if (bb->cil_code)
4132                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
4133                 /* this is not thread save, but good enough */
4134                 /* fixme: howto handle overflows? */
4135                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
4136         }
4137
4138     if (mono_break_at_bb_method && mono_method_desc_full_match (mono_break_at_bb_method, cfg->method) && bb->block_num == mono_break_at_bb_bb_num) {
4139                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4140                                                          (gpointer)"mono_break");
4141                 code = emit_call_seq (cfg, code);
4142         }
4143
4144         MONO_BB_FOR_EACH_INS (bb, ins) {
4145                 offset = code - cfg->native_code;
4146
4147                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4148
4149                 if (offset > (cfg->code_size - max_len - 16)) {
4150                         cfg->code_size *= 2;
4151                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4152                         code = cfg->native_code + offset;
4153                 }
4154         //      if (ins->cil_code)
4155         //              g_print ("cil code\n");
4156                 mono_debug_record_line_number (cfg, ins, offset);
4157
4158                 switch (ins->opcode) {
4159                 case OP_MEMORY_BARRIER:
4160                         if (v6_supported) {
4161                                 ARM_MOV_REG_IMM8 (code, ARMREG_R0, 0);
4162                                 ARM_MCR (code, 15, 0, ARMREG_R0, 7, 10, 5);
4163                         }
4164                         break;
4165                 case OP_TLS_GET:
4166 #ifdef HAVE_AEABI_READ_TP
4167                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4168                                                                  (gpointer)"__aeabi_read_tp");
4169                         code = emit_call_seq (cfg, code);
4170
4171                         ARM_LDR_IMM (code, ins->dreg, ARMREG_R0, ins->inst_offset);
4172 #else
4173                         g_assert_not_reached ();
4174 #endif
4175                         break;
4176                 case OP_ATOMIC_EXCHANGE_I4:
4177                 case OP_ATOMIC_CAS_I4:
4178                 case OP_ATOMIC_ADD_I4: {
4179                         int tmpreg;
4180                         guint8 *buf [16];
4181
4182                         g_assert (v7_supported);
4183
4184                         /* Free up a reg */
4185                         if (ins->sreg1 != ARMREG_IP && ins->sreg2 != ARMREG_IP && ins->sreg3 != ARMREG_IP)
4186                                 tmpreg = ARMREG_IP;
4187                         else if (ins->sreg1 != ARMREG_R0 && ins->sreg2 != ARMREG_R0 && ins->sreg3 != ARMREG_R0)
4188                                 tmpreg = ARMREG_R0;
4189                         else if (ins->sreg1 != ARMREG_R1 && ins->sreg2 != ARMREG_R1 && ins->sreg3 != ARMREG_R1)
4190                                 tmpreg = ARMREG_R1;
4191                         else
4192                                 tmpreg = ARMREG_R2;
4193                         g_assert (cfg->arch.atomic_tmp_offset != -1);
4194                         ARM_STR_IMM (code, tmpreg, cfg->frame_reg, cfg->arch.atomic_tmp_offset);
4195
4196                         switch (ins->opcode) {
4197                         case OP_ATOMIC_EXCHANGE_I4:
4198                                 buf [0] = code;
4199                                 ARM_DMB (code, ARM_DMB_SY);
4200                                 ARM_LDREX_REG (code, ARMREG_LR, ins->sreg1);
4201                                 ARM_STREX_REG (code, tmpreg, ins->sreg2, ins->sreg1);
4202                                 ARM_CMP_REG_IMM (code, tmpreg, 0, 0);
4203                                 buf [1] = code;
4204                                 ARM_B_COND (code, ARMCOND_NE, 0);
4205                                 arm_patch (buf [1], buf [0]);
4206                                 break;
4207                         case OP_ATOMIC_CAS_I4:
4208                                 ARM_DMB (code, ARM_DMB_SY);
4209                                 buf [0] = code;
4210                                 ARM_LDREX_REG (code, ARMREG_LR, ins->sreg1);
4211                                 ARM_CMP_REG_REG (code, ARMREG_LR, ins->sreg3);
4212                                 buf [1] = code;
4213                                 ARM_B_COND (code, ARMCOND_NE, 0);
4214                                 ARM_STREX_REG (code, tmpreg, ins->sreg2, ins->sreg1);
4215                                 ARM_CMP_REG_IMM (code, tmpreg, 0, 0);
4216                                 buf [2] = code;
4217                                 ARM_B_COND (code, ARMCOND_NE, 0);
4218                                 arm_patch (buf [2], buf [0]);
4219                                 arm_patch (buf [1], code);
4220                                 break;
4221                         case OP_ATOMIC_ADD_I4:
4222                                 buf [0] = code;
4223                                 ARM_DMB (code, ARM_DMB_SY);
4224                                 ARM_LDREX_REG (code, ARMREG_LR, ins->sreg1);
4225                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->sreg2);
4226                                 ARM_STREX_REG (code, tmpreg, ARMREG_LR, ins->sreg1);
4227                                 ARM_CMP_REG_IMM (code, tmpreg, 0, 0);
4228                                 buf [1] = code;
4229                                 ARM_B_COND (code, ARMCOND_NE, 0);
4230                                 arm_patch (buf [1], buf [0]);
4231                                 break;
4232                         default:
4233                                 g_assert_not_reached ();
4234                         }
4235
4236                         ARM_DMB (code, ARM_DMB_SY);
4237                         if (tmpreg != ins->dreg)
4238                                 ARM_LDR_IMM (code, tmpreg, cfg->frame_reg, cfg->arch.atomic_tmp_offset);
4239                         ARM_MOV_REG_REG (code, ins->dreg, ARMREG_LR);
4240                         break;
4241                 }
4242                 case OP_ATOMIC_LOAD_I1:
4243                 case OP_ATOMIC_LOAD_U1:
4244                 case OP_ATOMIC_LOAD_I2:
4245                 case OP_ATOMIC_LOAD_U2:
4246                 case OP_ATOMIC_LOAD_I4:
4247                 case OP_ATOMIC_LOAD_U4:
4248                 case OP_ATOMIC_LOAD_R4:
4249                 case OP_ATOMIC_LOAD_R8: {
4250                         if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
4251                                 ARM_DMB (code, ARM_DMB_SY);
4252
4253                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4254
4255                         switch (ins->opcode) {
4256                         case OP_ATOMIC_LOAD_I1:
4257                                 ARM_LDRSB_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
4258                                 break;
4259                         case OP_ATOMIC_LOAD_U1:
4260                                 ARM_LDRB_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
4261                                 break;
4262                         case OP_ATOMIC_LOAD_I2:
4263                                 ARM_LDRSH_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
4264                                 break;
4265                         case OP_ATOMIC_LOAD_U2:
4266                                 ARM_LDRH_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
4267                                 break;
4268                         case OP_ATOMIC_LOAD_I4:
4269                         case OP_ATOMIC_LOAD_U4:
4270                                 ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
4271                                 break;
4272                         case OP_ATOMIC_LOAD_R4:
4273                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
4274                                 ARM_ADD_REG_REG (code, ARMREG_LR, ins->inst_basereg, ARMREG_LR);
4275                                 ARM_FLDS (code, vfp_scratch1, ARMREG_LR, 0);
4276                                 ARM_CVTS (code, ins->dreg, vfp_scratch1);
4277                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
4278                                 break;
4279                         case OP_ATOMIC_LOAD_R8:
4280                                 ARM_ADD_REG_REG (code, ARMREG_LR, ins->inst_basereg, ARMREG_LR);
4281                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
4282                                 break;
4283                         }
4284
4285                         ARM_DMB (code, ARM_DMB_SY);
4286                         break;
4287                 }
4288                 case OP_ATOMIC_STORE_I1:
4289                 case OP_ATOMIC_STORE_U1:
4290                 case OP_ATOMIC_STORE_I2:
4291                 case OP_ATOMIC_STORE_U2:
4292                 case OP_ATOMIC_STORE_I4:
4293                 case OP_ATOMIC_STORE_U4:
4294                 case OP_ATOMIC_STORE_R4:
4295                 case OP_ATOMIC_STORE_R8: {
4296                         ARM_DMB (code, ARM_DMB_SY);
4297
4298                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4299
4300                         switch (ins->opcode) {
4301                         case OP_ATOMIC_STORE_I1:
4302                         case OP_ATOMIC_STORE_U1:
4303                                 ARM_STRB_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
4304                                 break;
4305                         case OP_ATOMIC_STORE_I2:
4306                         case OP_ATOMIC_STORE_U2:
4307                                 ARM_STRH_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
4308                                 break;
4309                         case OP_ATOMIC_STORE_I4:
4310                         case OP_ATOMIC_STORE_U4:
4311                                 ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
4312                                 break;
4313                         case OP_ATOMIC_STORE_R4:
4314                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
4315                                 ARM_ADD_REG_REG (code, ARMREG_LR, ins->inst_destbasereg, ARMREG_LR);
4316                                 ARM_CVTD (code, vfp_scratch1, ins->sreg1);
4317                                 ARM_FSTS (code, vfp_scratch1, ARMREG_LR, 0);
4318                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
4319                                 break;
4320                         case OP_ATOMIC_STORE_R8:
4321                                 ARM_ADD_REG_REG (code, ARMREG_LR, ins->inst_destbasereg, ARMREG_LR);
4322                                 ARM_FSTD (code, ins->sreg1, ARMREG_LR, 0);
4323                                 break;
4324                         }
4325
4326                         if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
4327                                 ARM_DMB (code, ARM_DMB_SY);
4328                         break;
4329                 }
4330                 /*case OP_BIGMUL:
4331                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
4332                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
4333                         break;
4334                 case OP_BIGMUL_UN:
4335                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
4336                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
4337                         break;*/
4338                 case OP_STOREI1_MEMBASE_IMM:
4339                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFF);
4340                         g_assert (arm_is_imm12 (ins->inst_offset));
4341                         ARM_STRB_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
4342                         break;
4343                 case OP_STOREI2_MEMBASE_IMM:
4344                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFFFF);
4345                         g_assert (arm_is_imm8 (ins->inst_offset));
4346                         ARM_STRH_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
4347                         break;
4348                 case OP_STORE_MEMBASE_IMM:
4349                 case OP_STOREI4_MEMBASE_IMM:
4350                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm);
4351                         g_assert (arm_is_imm12 (ins->inst_offset));
4352                         ARM_STR_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
4353                         break;
4354                 case OP_STOREI1_MEMBASE_REG:
4355                         g_assert (arm_is_imm12 (ins->inst_offset));
4356                         ARM_STRB_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4357                         break;
4358                 case OP_STOREI2_MEMBASE_REG:
4359                         g_assert (arm_is_imm8 (ins->inst_offset));
4360                         ARM_STRH_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4361                         break;
4362                 case OP_STORE_MEMBASE_REG:
4363                 case OP_STOREI4_MEMBASE_REG:
4364                         /* this case is special, since it happens for spill code after lowering has been called */
4365                         if (arm_is_imm12 (ins->inst_offset)) {
4366                                 ARM_STR_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4367                         } else {
4368                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4369                                 ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
4370                         }
4371                         break;
4372                 case OP_STOREI1_MEMINDEX:
4373                         ARM_STRB_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4374                         break;
4375                 case OP_STOREI2_MEMINDEX:
4376                         ARM_STRH_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4377                         break;
4378                 case OP_STORE_MEMINDEX:
4379                 case OP_STOREI4_MEMINDEX:
4380                         ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
4381                         break;
4382                 case OP_LOADU4_MEM:
4383                         g_assert_not_reached ();
4384                         break;
4385                 case OP_LOAD_MEMINDEX:
4386                 case OP_LOADI4_MEMINDEX:
4387                 case OP_LOADU4_MEMINDEX:
4388                         ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4389                         break;
4390                 case OP_LOADI1_MEMINDEX:
4391                         ARM_LDRSB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4392                         break;
4393                 case OP_LOADU1_MEMINDEX:
4394                         ARM_LDRB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4395                         break;
4396                 case OP_LOADI2_MEMINDEX:
4397                         ARM_LDRSH_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4398                         break;
4399                 case OP_LOADU2_MEMINDEX:
4400                         ARM_LDRH_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
4401                         break;
4402                 case OP_LOAD_MEMBASE:
4403                 case OP_LOADI4_MEMBASE:
4404                 case OP_LOADU4_MEMBASE:
4405                         /* this case is special, since it happens for spill code after lowering has been called */
4406                         if (arm_is_imm12 (ins->inst_offset)) {
4407                                 ARM_LDR_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4408                         } else {
4409                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4410                                 ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
4411                         }
4412                         break;
4413                 case OP_LOADI1_MEMBASE:
4414                         g_assert (arm_is_imm8 (ins->inst_offset));
4415                         ARM_LDRSB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4416                         break;
4417                 case OP_LOADU1_MEMBASE:
4418                         g_assert (arm_is_imm12 (ins->inst_offset));
4419                         ARM_LDRB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4420                         break;
4421                 case OP_LOADU2_MEMBASE:
4422                         g_assert (arm_is_imm8 (ins->inst_offset));
4423                         ARM_LDRH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4424                         break;
4425                 case OP_LOADI2_MEMBASE:
4426                         g_assert (arm_is_imm8 (ins->inst_offset));
4427                         ARM_LDRSH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4428                         break;
4429                 case OP_ICONV_TO_I1:
4430                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 24);
4431                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 24);
4432                         break;
4433                 case OP_ICONV_TO_I2:
4434                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
4435                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 16);
4436                         break;
4437                 case OP_ICONV_TO_U1:
4438                         ARM_AND_REG_IMM8 (code, ins->dreg, ins->sreg1, 0xff);
4439                         break;
4440                 case OP_ICONV_TO_U2:
4441                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
4442                         ARM_SHR_IMM (code, ins->dreg, ins->dreg, 16);
4443                         break;
4444                 case OP_COMPARE:
4445                 case OP_ICOMPARE:
4446                         ARM_CMP_REG_REG (code, ins->sreg1, ins->sreg2);
4447                         break;
4448                 case OP_COMPARE_IMM:
4449                 case OP_ICOMPARE_IMM:
4450                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4451                         g_assert (imm8 >= 0);
4452                         ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount);
4453                         break;
4454                 case OP_BREAK:
4455                         /*
4456                          * gdb does not like encountering the hw breakpoint ins in the debugged code. 
4457                          * So instead of emitting a trap, we emit a call a C function and place a 
4458                          * breakpoint there.
4459                          */
4460                         //*(int*)code = 0xef9f0001;
4461                         //code += 4;
4462                         //ARM_DBRK (code);
4463                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4464                                                                  (gpointer)"mono_break");
4465                         code = emit_call_seq (cfg, code);
4466                         break;
4467                 case OP_RELAXED_NOP:
4468                         ARM_NOP (code);
4469                         break;
4470                 case OP_NOP:
4471                 case OP_DUMMY_USE:
4472                 case OP_DUMMY_STORE:
4473                 case OP_DUMMY_ICONST:
4474                 case OP_DUMMY_R8CONST:
4475                 case OP_NOT_REACHED:
4476                 case OP_NOT_NULL:
4477                         break;
4478                 case OP_IL_SEQ_POINT:
4479                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
4480                         break;
4481                 case OP_SEQ_POINT: {
4482                         int i;
4483                         MonoInst *info_var = cfg->arch.seq_point_info_var;
4484                         MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
4485                         MonoInst *ss_read_var = cfg->arch.seq_point_read_var;
4486                         MonoInst *ss_method_var = cfg->arch.seq_point_ss_method_var;
4487                         MonoInst *bp_method_var = cfg->arch.seq_point_bp_method_var;
4488                         MonoInst *var;
4489                         int dreg = ARMREG_LR;
4490
4491                         if (cfg->soft_breakpoints) {
4492                                 g_assert (!cfg->compile_aot);
4493                         }
4494
4495                         /*
4496                          * For AOT, we use one got slot per method, which will point to a
4497                          * SeqPointInfo structure, containing all the information required
4498                          * by the code below.
4499                          */
4500                         if (cfg->compile_aot) {
4501                                 g_assert (info_var);
4502                                 g_assert (info_var->opcode == OP_REGOFFSET);
4503                                 g_assert (arm_is_imm12 (info_var->inst_offset));
4504                         }
4505
4506                         if (!cfg->soft_breakpoints) {
4507                                 /*
4508                                  * Read from the single stepping trigger page. This will cause a
4509                                  * SIGSEGV when single stepping is enabled.
4510                                  * We do this _before_ the breakpoint, so single stepping after
4511                                  * a breakpoint is hit will step to the next IL offset.
4512                                  */
4513                                 g_assert (((guint64)(gsize)ss_trigger_page >> 32) == 0);
4514                         }
4515
4516                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
4517                                 if (cfg->soft_breakpoints) {
4518                                         /* Load the address of the sequence point trigger variable. */
4519                                         var = ss_read_var;
4520                                         g_assert (var);
4521                                         g_assert (var->opcode == OP_REGOFFSET);
4522                                         g_assert (arm_is_imm12 (var->inst_offset));
4523                                         ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
4524
4525                                         /* Read the value and check whether it is non-zero. */
4526                                         ARM_LDR_IMM (code, dreg, dreg, 0);
4527                                         ARM_CMP_REG_IMM (code, dreg, 0, 0);
4528
4529                                         /* Load the address of the sequence point method. */
4530                                         var = ss_method_var;
4531                                         g_assert (var);
4532                                         g_assert (var->opcode == OP_REGOFFSET);
4533                                         g_assert (arm_is_imm12 (var->inst_offset));
4534                                         ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
4535
4536                                         /* Call it conditionally. */
4537                                         ARM_BLX_REG_COND (code, ARMCOND_NE, dreg);
4538                                 } else {
4539                                         if (cfg->compile_aot) {
4540                                                 /* Load the trigger page addr from the variable initialized in the prolog */
4541                                                 var = ss_trigger_page_var;
4542                                                 g_assert (var);
4543                                                 g_assert (var->opcode == OP_REGOFFSET);
4544                                                 g_assert (arm_is_imm12 (var->inst_offset));
4545                                                 ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
4546                                         } else {
4547 #ifdef USE_JUMP_TABLES
4548                                                 gpointer *jte = mono_jumptable_add_entry ();
4549                                                 code = mono_arm_load_jumptable_entry (code, jte, dreg);
4550                                                 jte [0] = ss_trigger_page;
4551 #else
4552                                                 ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
4553                                                 ARM_B (code, 0);
4554                                                 *(int*)code = (int)ss_trigger_page;
4555                                                 code += 4;
4556 #endif
4557                                         }
4558                                         ARM_LDR_IMM (code, dreg, dreg, 0);
4559                                 }
4560                         }
4561
4562                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
4563
4564                         if (cfg->soft_breakpoints) {
4565                                 /* Load the address of the breakpoint method into ip. */
4566                                 var = bp_method_var;
4567                                 g_assert (var);
4568                                 g_assert (var->opcode == OP_REGOFFSET);
4569                                 g_assert (arm_is_imm12 (var->inst_offset));
4570                                 ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
4571
4572                                 /*
4573                                  * A placeholder for a possible breakpoint inserted by
4574                                  * mono_arch_set_breakpoint ().
4575                                  */
4576                                 ARM_NOP (code);
4577                         } else if (cfg->compile_aot) {
4578                                 guint32 offset = code - cfg->native_code;
4579                                 guint32 val;
4580
4581                                 ARM_LDR_IMM (code, dreg, info_var->inst_basereg, info_var->inst_offset);
4582                                 /* Add the offset */
4583                                 val = ((offset / 4) * sizeof (guint8*)) + MONO_STRUCT_OFFSET (SeqPointInfo, bp_addrs);
4584                                 /* Load the info->bp_addrs [offset], which is either 0 or the address of a trigger page */
4585                                 if (arm_is_imm12 ((int)val)) {
4586                                         ARM_LDR_IMM (code, dreg, dreg, val);
4587                                 } else {
4588                                         ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF), 0);
4589                                         if (val & 0xFF00)
4590                                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
4591                                         if (val & 0xFF0000)
4592                                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
4593                                         g_assert (!(val & 0xFF000000));
4594
4595                                         ARM_LDR_IMM (code, dreg, dreg, 0);
4596                                 }
4597                                 /* What is faster, a branch or a load ? */
4598                                 ARM_CMP_REG_IMM (code, dreg, 0, 0);
4599                                 /* The breakpoint instruction */
4600                                 ARM_LDR_IMM_COND (code, dreg, dreg, 0, ARMCOND_NE);
4601                         } else {
4602                                 /* 
4603                                  * A placeholder for a possible breakpoint inserted by
4604                                  * mono_arch_set_breakpoint ().
4605                                  */
4606                                 for (i = 0; i < 4; ++i)
4607                                         ARM_NOP (code);
4608                         }
4609                         break;
4610                 }
4611                 case OP_ADDCC:
4612                 case OP_IADDCC:
4613                         ARM_ADDS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4614                         break;
4615                 case OP_IADD:
4616                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4617                         break;
4618                 case OP_ADC:
4619                 case OP_IADC:
4620                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4621                         break;
4622                 case OP_ADDCC_IMM:
4623                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4624                         g_assert (imm8 >= 0);
4625                         ARM_ADDS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4626                         break;
4627                 case OP_ADD_IMM:
4628                 case OP_IADD_IMM:
4629                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4630                         g_assert (imm8 >= 0);
4631                         ARM_ADD_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4632                         break;
4633                 case OP_ADC_IMM:
4634                 case OP_IADC_IMM:
4635                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4636                         g_assert (imm8 >= 0);
4637                         ARM_ADCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4638                         break;
4639                 case OP_IADD_OVF:
4640                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4641                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4642                         break;
4643                 case OP_IADD_OVF_UN:
4644                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4645                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4646                         break;
4647                 case OP_ISUB_OVF:
4648                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4649                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4650                         break;
4651                 case OP_ISUB_OVF_UN:
4652                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4653                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
4654                         break;
4655                 case OP_ADD_OVF_CARRY:
4656                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4657                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4658                         break;
4659                 case OP_ADD_OVF_UN_CARRY:
4660                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4661                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4662                         break;
4663                 case OP_SUB_OVF_CARRY:
4664                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4665                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
4666                         break;
4667                 case OP_SUB_OVF_UN_CARRY:
4668                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4669                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
4670                         break;
4671                 case OP_SUBCC:
4672                 case OP_ISUBCC:
4673                         ARM_SUBS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4674                         break;
4675                 case OP_SUBCC_IMM:
4676                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4677                         g_assert (imm8 >= 0);
4678                         ARM_SUBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4679                         break;
4680                 case OP_ISUB:
4681                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4682                         break;
4683                 case OP_SBB:
4684                 case OP_ISBB:
4685                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4686                         break;
4687                 case OP_SUB_IMM:
4688                 case OP_ISUB_IMM:
4689                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4690                         g_assert (imm8 >= 0);
4691                         ARM_SUB_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4692                         break;
4693                 case OP_SBB_IMM:
4694                 case OP_ISBB_IMM:
4695                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4696                         g_assert (imm8 >= 0);
4697                         ARM_SBCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4698                         break;
4699                 case OP_ARM_RSBS_IMM:
4700                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4701                         g_assert (imm8 >= 0);
4702                         ARM_RSBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4703                         break;
4704                 case OP_ARM_RSC_IMM:
4705                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4706                         g_assert (imm8 >= 0);
4707                         ARM_RSC_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4708                         break;
4709                 case OP_IAND:
4710                         ARM_AND_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4711                         break;
4712                 case OP_AND_IMM:
4713                 case OP_IAND_IMM:
4714                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4715                         g_assert (imm8 >= 0);
4716                         ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4717                         break;
4718                 case OP_IDIV:
4719                         g_assert (v7s_supported);
4720                         ARM_SDIV (code, ins->dreg, ins->sreg1, ins->sreg2);
4721                         break;
4722                 case OP_IDIV_UN:
4723                         g_assert (v7s_supported);
4724                         ARM_UDIV (code, ins->dreg, ins->sreg1, ins->sreg2);
4725                         break;
4726                 case OP_IREM:
4727                         g_assert (v7s_supported);
4728                         ARM_SDIV (code, ARMREG_LR, ins->sreg1, ins->sreg2);
4729                         ARM_MLS (code, ins->dreg, ARMREG_LR, ins->sreg2, ins->sreg1);
4730                         break;
4731                 case OP_IREM_UN:
4732                         g_assert (v7s_supported);
4733                         ARM_UDIV (code, ARMREG_LR, ins->sreg1, ins->sreg2);
4734                         ARM_MLS (code, ins->dreg, ARMREG_LR, ins->sreg2, ins->sreg1);
4735                         break;
4736                 case OP_DIV_IMM:
4737                 case OP_REM_IMM:
4738                         g_assert_not_reached ();
4739                 case OP_IOR:
4740                         ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4741                         break;
4742                 case OP_OR_IMM:
4743                 case OP_IOR_IMM:
4744                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4745                         g_assert (imm8 >= 0);
4746                         ARM_ORR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4747                         break;
4748                 case OP_IXOR:
4749                         ARM_EOR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4750                         break;
4751                 case OP_XOR_IMM:
4752                 case OP_IXOR_IMM:
4753                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
4754                         g_assert (imm8 >= 0);
4755                         ARM_EOR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
4756                         break;
4757                 case OP_ISHL:
4758                         ARM_SHL_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4759                         break;
4760                 case OP_SHL_IMM:
4761                 case OP_ISHL_IMM:
4762                         if (ins->inst_imm)
4763                                 ARM_SHL_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4764                         else if (ins->dreg != ins->sreg1)
4765                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4766                         break;
4767                 case OP_ISHR:
4768                         ARM_SAR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4769                         break;
4770                 case OP_SHR_IMM:
4771                 case OP_ISHR_IMM:
4772                         if (ins->inst_imm)
4773                                 ARM_SAR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4774                         else if (ins->dreg != ins->sreg1)
4775                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4776                         break;
4777                 case OP_SHR_UN_IMM:
4778                 case OP_ISHR_UN_IMM:
4779                         if (ins->inst_imm)
4780                                 ARM_SHR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
4781                         else if (ins->dreg != ins->sreg1)
4782                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4783                         break;
4784                 case OP_ISHR_UN:
4785                         ARM_SHR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4786                         break;
4787                 case OP_INOT:
4788                         ARM_MVN_REG_REG (code, ins->dreg, ins->sreg1);
4789                         break;
4790                 case OP_INEG:
4791                         ARM_RSB_REG_IMM8 (code, ins->dreg, ins->sreg1, 0);
4792                         break;
4793                 case OP_IMUL:
4794                         if (ins->dreg == ins->sreg2)
4795                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4796                         else
4797                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg2, ins->sreg1);
4798                         break;
4799                 case OP_MUL_IMM:
4800                         g_assert_not_reached ();
4801                         break;
4802                 case OP_IMUL_OVF:
4803                         /* FIXME: handle ovf/ sreg2 != dreg */
4804                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4805                         /* FIXME: MUL doesn't set the C/O flags on ARM */
4806                         break;
4807                 case OP_IMUL_OVF_UN:
4808                         /* FIXME: handle ovf/ sreg2 != dreg */
4809                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
4810                         /* FIXME: MUL doesn't set the C/O flags on ARM */
4811                         break;
4812                 case OP_ICONST:
4813                         code = mono_arm_emit_load_imm (code, ins->dreg, ins->inst_c0);
4814                         break;
4815                 case OP_AOTCONST:
4816                         /* Load the GOT offset */
4817                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
4818                         ARM_LDR_IMM (code, ins->dreg, ARMREG_PC, 0);
4819                         ARM_B (code, 0);
4820                         *(gpointer*)code = NULL;
4821                         code += 4;
4822                         /* Load the value from the GOT */
4823                         ARM_LDR_REG_REG (code, ins->dreg, ARMREG_PC, ins->dreg);
4824                         break;
4825                 case OP_OBJC_GET_SELECTOR:
4826                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_OBJC_SELECTOR_REF, ins->inst_p0);
4827                         ARM_LDR_IMM (code, ins->dreg, ARMREG_PC, 0);
4828                         ARM_B (code, 0);
4829                         *(gpointer*)code = NULL;
4830                         code += 4;
4831                         ARM_LDR_REG_REG (code, ins->dreg, ARMREG_PC, ins->dreg);
4832                         break;
4833                 case OP_ICONV_TO_I4:
4834                 case OP_ICONV_TO_U4:
4835                 case OP_MOVE:
4836                         if (ins->dreg != ins->sreg1)
4837                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4838                         break;
4839                 case OP_SETLRET: {
4840                         int saved = ins->sreg2;
4841                         if (ins->sreg2 == ARM_LSW_REG) {
4842                                 ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg2);
4843                                 saved = ARMREG_LR;
4844                         }
4845                         if (ins->sreg1 != ARM_LSW_REG)
4846                                 ARM_MOV_REG_REG (code, ARM_LSW_REG, ins->sreg1);
4847                         if (saved != ARM_MSW_REG)
4848                                 ARM_MOV_REG_REG (code, ARM_MSW_REG, saved);
4849                         break;
4850                 }
4851                 case OP_FMOVE:
4852                         if (IS_VFP && ins->dreg != ins->sreg1)
4853                                 ARM_CPYD (code, ins->dreg, ins->sreg1);
4854                         break;
4855                 case OP_MOVE_F_TO_I4:
4856                         code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
4857                         ARM_CVTD (code, vfp_scratch1, ins->sreg1);
4858                         ARM_FMRS (code, ins->dreg, vfp_scratch1);
4859                         code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
4860                         break;
4861                 case OP_MOVE_I4_TO_F:
4862                         ARM_FMSR (code, ins->dreg, ins->sreg1);
4863                         ARM_CVTS (code, ins->dreg, ins->dreg);
4864                         break;
4865                 case OP_FCONV_TO_R4:
4866                         if (IS_VFP) {
4867                                 if (cfg->r4fp) {
4868                                         ARM_CVTD (code, ins->dreg, ins->sreg1);
4869                                 } else {
4870                                         ARM_CVTD (code, ins->dreg, ins->sreg1);
4871                                         ARM_CVTS (code, ins->dreg, ins->dreg);
4872                                 }
4873                         }
4874                         break;
4875                 case OP_TAILCALL: {
4876                         MonoCallInst *call = (MonoCallInst*)ins;
4877
4878                         /*
4879                          * The stack looks like the following:
4880                          * <caller argument area>
4881                          * <saved regs etc>
4882                          * <rest of frame>
4883                          * <callee argument area>
4884                          * Need to copy the arguments from the callee argument area to
4885                          * the caller argument area, and pop the frame.
4886                          */
4887                         if (call->stack_usage) {
4888                                 int i, prev_sp_offset = 0;
4889
4890                                 /* Compute size of saved registers restored below */
4891                                 if (iphone_abi)
4892                                         prev_sp_offset = 2 * 4;
4893                                 else
4894                                         prev_sp_offset = 1 * 4;
4895                                 for (i = 0; i < 16; ++i) {
4896                                         if (cfg->used_int_regs & (1 << i))
4897                                                 prev_sp_offset += 4;
4898                                 }
4899
4900                                 code = emit_big_add (code, ARMREG_IP, cfg->frame_reg, cfg->stack_usage + prev_sp_offset);
4901
4902                                 /* Copy arguments on the stack to our argument area */
4903                                 for (i = 0; i < call->stack_usage; i += sizeof (mgreg_t)) {
4904                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, i);
4905                                         ARM_STR_IMM (code, ARMREG_LR, ARMREG_IP, i);
4906                                 }
4907                         }
4908
4909                         /*
4910                          * Keep in sync with mono_arch_emit_epilog
4911                          */
4912                         g_assert (!cfg->method->save_lmf);
4913
4914                         code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
4915                         if (iphone_abi) {
4916                                 if (cfg->used_int_regs)
4917                                         ARM_POP (code, cfg->used_int_regs);
4918                                 ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_LR));
4919                         } else {
4920                                 ARM_POP (code, cfg->used_int_regs | (1 << ARMREG_LR));
4921                         }
4922
4923                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method);
4924                         if (cfg->compile_aot) {
4925                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
4926                                 ARM_B (code, 0);
4927                                 *(gpointer*)code = NULL;
4928                                 code += 4;
4929                                 ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
4930                         } else {
4931                                 code = mono_arm_patchable_b (code, ARMCOND_AL);
4932                         }
4933                         break;
4934                 }
4935                 case OP_CHECK_THIS:
4936                         /* ensure ins->sreg1 is not NULL */
4937                         ARM_LDRB_IMM (code, ARMREG_LR, ins->sreg1, 0);
4938                         break;
4939                 case OP_ARGLIST: {
4940                         g_assert (cfg->sig_cookie < 128);
4941                         ARM_LDR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie);
4942                         ARM_STR_IMM (code, ARMREG_IP, ins->sreg1, 0);
4943                         break;
4944                 }
4945                 case OP_FCALL:
4946                 case OP_RCALL:
4947                 case OP_LCALL:
4948                 case OP_VCALL:
4949                 case OP_VCALL2:
4950                 case OP_VOIDCALL:
4951                 case OP_CALL:
4952                         call = (MonoCallInst*)ins;
4953
4954                         if (IS_HARD_FLOAT)
4955                                 code = emit_float_args (cfg, call, code, &max_len, &offset);
4956
4957                         if (ins->flags & MONO_INST_HAS_METHOD)
4958                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
4959                         else
4960                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
4961                         code = emit_call_seq (cfg, code);
4962                         ins->flags |= MONO_INST_GC_CALLSITE;
4963                         ins->backend.pc_offset = code - cfg->native_code;
4964                         code = emit_move_return_value (cfg, ins, code);
4965                         break;
4966                 case OP_FCALL_REG:
4967                 case OP_RCALL_REG:
4968                 case OP_LCALL_REG:
4969                 case OP_VCALL_REG:
4970                 case OP_VCALL2_REG:
4971                 case OP_VOIDCALL_REG:
4972                 case OP_CALL_REG:
4973                         if (IS_HARD_FLOAT)
4974                                 code = emit_float_args (cfg, (MonoCallInst *)ins, code, &max_len, &offset);
4975
4976                         code = emit_call_reg (code, ins->sreg1);
4977                         ins->flags |= MONO_INST_GC_CALLSITE;
4978                         ins->backend.pc_offset = code - cfg->native_code;
4979                         code = emit_move_return_value (cfg, ins, code);
4980                         break;
4981                 case OP_FCALL_MEMBASE:
4982                 case OP_RCALL_MEMBASE:
4983                 case OP_LCALL_MEMBASE:
4984                 case OP_VCALL_MEMBASE:
4985                 case OP_VCALL2_MEMBASE:
4986                 case OP_VOIDCALL_MEMBASE:
4987                 case OP_CALL_MEMBASE: {
4988                         g_assert (ins->sreg1 != ARMREG_LR);
4989                         call = (MonoCallInst*)ins;
4990
4991                         if (IS_HARD_FLOAT)
4992                                 code = emit_float_args (cfg, call, code, &max_len, &offset);
4993                         if (!arm_is_imm12 (ins->inst_offset))
4994                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_offset);
4995                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
4996                         if (!arm_is_imm12 (ins->inst_offset))
4997                                 ARM_LDR_REG_REG (code, ARMREG_PC, ins->sreg1, ARMREG_IP);
4998                         else
4999                                 ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
5000                         ins->flags |= MONO_INST_GC_CALLSITE;
5001                         ins->backend.pc_offset = code - cfg->native_code;
5002                         code = emit_move_return_value (cfg, ins, code);
5003                         break;
5004                 }
5005                 case OP_LOCALLOC: {
5006                         /* round the size to 8 bytes */
5007                         ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
5008                         ARM_BIC_REG_IMM8 (code, ins->dreg, ins->dreg, 7);
5009                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ins->dreg);
5010                         /* memzero the area: dreg holds the size, sp is the pointer */
5011                         if (ins->flags & MONO_INST_INIT) {
5012                                 guint8 *start_loop, *branch_to_cond;
5013                                 ARM_MOV_REG_IMM8 (code, ARMREG_LR, 0);
5014                                 branch_to_cond = code;
5015                                 ARM_B (code, 0);
5016                                 start_loop = code;
5017                                 ARM_STR_REG_REG (code, ARMREG_LR, ARMREG_SP, ins->dreg);
5018                                 arm_patch (branch_to_cond, code);
5019                                 /* decrement by 4 and set flags */
5020                                 ARM_SUBS_REG_IMM8 (code, ins->dreg, ins->dreg, sizeof (mgreg_t));
5021                                 ARM_B_COND (code, ARMCOND_GE, 0);
5022                                 arm_patch (code - 4, start_loop);
5023                         }
5024                         ARM_MOV_REG_REG (code, ins->dreg, ARMREG_SP);
5025                         if (cfg->param_area)
5026                                 code = emit_sub_imm (code, ARMREG_SP, ARMREG_SP, ALIGN_TO (cfg->param_area, MONO_ARCH_FRAME_ALIGNMENT));
5027                         break;
5028                 }
5029                 case OP_DYN_CALL: {
5030                         int i;
5031                         MonoInst *var = cfg->dyn_call_var;
5032
5033                         g_assert (var->opcode == OP_REGOFFSET);
5034                         g_assert (arm_is_imm12 (var->inst_offset));
5035
5036                         /* lr = args buffer filled by mono_arch_get_dyn_call_args () */
5037                         ARM_MOV_REG_REG( code, ARMREG_LR, ins->sreg1);
5038                         /* ip = ftn */
5039                         ARM_MOV_REG_REG( code, ARMREG_IP, ins->sreg2);
5040
5041                         /* Save args buffer */
5042                         ARM_STR_IMM (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
5043
5044                         /* Set stack slots using R0 as scratch reg */
5045                         /* MONO_ARCH_DYN_CALL_PARAM_AREA gives the size of stack space available */
5046                         for (i = 0; i < DYN_CALL_STACK_ARGS; ++i) {
5047                                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, (PARAM_REGS + i) * sizeof (mgreg_t));
5048                                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, i * sizeof (mgreg_t));
5049                         }
5050
5051                         /* Set argument registers */
5052                         for (i = 0; i < PARAM_REGS; ++i)
5053                                 ARM_LDR_IMM (code, i, ARMREG_LR, i * sizeof (mgreg_t));
5054
5055                         /* Make the call */
5056                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
5057                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
5058
5059                         /* Save result */
5060                         ARM_LDR_IMM (code, ARMREG_IP, var->inst_basereg, var->inst_offset);
5061                         ARM_STR_IMM (code, ARMREG_R0, ARMREG_IP, MONO_STRUCT_OFFSET (DynCallArgs, res)); 
5062                         ARM_STR_IMM (code, ARMREG_R1, ARMREG_IP, MONO_STRUCT_OFFSET (DynCallArgs, res2)); 
5063                         break;
5064                 }
5065                 case OP_THROW: {
5066                         if (ins->sreg1 != ARMREG_R0)
5067                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
5068                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
5069                                              (gpointer)"mono_arch_throw_exception");
5070                         code = emit_call_seq (cfg, code);
5071                         break;
5072                 }
5073                 case OP_RETHROW: {
5074                         if (ins->sreg1 != ARMREG_R0)
5075                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
5076                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
5077                                              (gpointer)"mono_arch_rethrow_exception");
5078                         code = emit_call_seq (cfg, code);
5079                         break;
5080                 }
5081                 case OP_START_HANDLER: {
5082                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
5083                         int i, rot_amount;
5084
5085                         /* Reserve a param area, see filter-stack.exe */
5086                         if (cfg->param_area) {
5087                                 if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
5088                                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
5089                                 } else {
5090                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
5091                                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
5092                                 }
5093                         }
5094
5095                         if (arm_is_imm12 (spvar->inst_offset)) {
5096                                 ARM_STR_IMM (code, ARMREG_LR, spvar->inst_basereg, spvar->inst_offset);
5097                         } else {
5098                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
5099                                 ARM_STR_REG_REG (code, ARMREG_LR, spvar->inst_basereg, ARMREG_IP);
5100                         }
5101                         break;
5102                 }
5103                 case OP_ENDFILTER: {
5104                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
5105                         int i, rot_amount;
5106
5107                         /* Free the param area */
5108                         if (cfg->param_area) {
5109                                 if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
5110                                         ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
5111                                 } else {
5112                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
5113                                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
5114                                 }
5115                         }
5116
5117                         if (ins->sreg1 != ARMREG_R0)
5118                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
5119                         if (arm_is_imm12 (spvar->inst_offset)) {
5120                                 ARM_LDR_IMM (code, ARMREG_IP, spvar->inst_basereg, spvar->inst_offset);
5121                         } else {
5122                                 g_assert (ARMREG_IP != spvar->inst_basereg);
5123                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
5124                                 ARM_LDR_REG_REG (code, ARMREG_IP, spvar->inst_basereg, ARMREG_IP);
5125                         }
5126                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
5127                         break;
5128                 }
5129                 case OP_ENDFINALLY: {
5130                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
5131                         int i, rot_amount;
5132
5133                         /* Free the param area */
5134                         if (cfg->param_area) {
5135                                 if ((i = mono_arm_is_rotated_imm8 (cfg->param_area, &rot_amount)) >= 0) {
5136                                         ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
5137                                 } else {
5138                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->param_area);
5139                                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
5140                                 }
5141                         }
5142
5143                         if (arm_is_imm12 (spvar->inst_offset)) {
5144                                 ARM_LDR_IMM (code, ARMREG_IP, spvar->inst_basereg, spvar->inst_offset);
5145                         } else {
5146                                 g_assert (ARMREG_IP != spvar->inst_basereg);
5147                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
5148                                 ARM_LDR_REG_REG (code, ARMREG_IP, spvar->inst_basereg, ARMREG_IP);
5149                         }
5150                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
5151                         break;
5152                 }
5153                 case OP_CALL_HANDLER: 
5154                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
5155                         code = mono_arm_patchable_bl (code, ARMCOND_AL);
5156                         cfg->thunk_area += THUNK_SIZE;
5157                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
5158                         break;
5159                 case OP_GET_EX_OBJ:
5160                         if (ins->dreg != ARMREG_R0)
5161                                 ARM_MOV_REG_REG (code, ins->dreg, ARMREG_R0);
5162                         break;
5163
5164                 case OP_LABEL:
5165                         ins->inst_c0 = code - cfg->native_code;
5166                         break;
5167                 case OP_BR:
5168                         /*if (ins->inst_target_bb->native_offset) {
5169                                 ARM_B (code, 0);
5170                                 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
5171                         } else*/ {
5172                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
5173                                 code = mono_arm_patchable_b (code, ARMCOND_AL);
5174                         } 
5175                         break;
5176                 case OP_BR_REG:
5177                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
5178                         break;
5179                 case OP_SWITCH:
5180                         /* 
5181                          * In the normal case we have:
5182                          *      ldr pc, [pc, ins->sreg1 << 2]
5183                          *      nop
5184                          * If aot, we have:
5185                          *      ldr lr, [pc, ins->sreg1 << 2]
5186                          *      add pc, pc, lr
5187                          * After follows the data.
5188                          * FIXME: add aot support.
5189                          */
5190                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_SWITCH, ins->inst_p0);
5191 #ifdef USE_JUMP_TABLES
5192                         {
5193                                 gpointer *jte = mono_jumptable_add_entries (GPOINTER_TO_INT (ins->klass));
5194                                 code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_IP);
5195                                 ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_IP, ins->sreg1, ARMSHIFT_LSL, 2);
5196                         }
5197 #else
5198
5199                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
5200                         if (offset + max_len > (cfg->code_size - 16)) {
5201                                 cfg->code_size += max_len;
5202                                 cfg->code_size *= 2;
5203                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
5204                                 code = cfg->native_code + offset;
5205                         }
5206                         ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_PC, ins->sreg1, ARMSHIFT_LSL, 2);
5207                         ARM_NOP (code);
5208                         code += 4 * GPOINTER_TO_INT (ins->klass);
5209 #endif
5210                         break;
5211                 case OP_CEQ:
5212                 case OP_ICEQ:
5213                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
5214                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
5215                         break;
5216                 case OP_CLT:
5217                 case OP_ICLT:
5218                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5219                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LT);
5220                         break;
5221                 case OP_CLT_UN:
5222                 case OP_ICLT_UN:
5223                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5224                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LO);
5225                         break;
5226                 case OP_CGT:
5227                 case OP_ICGT:
5228                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5229                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_GT);
5230                         break;
5231                 case OP_CGT_UN:
5232                 case OP_ICGT_UN:
5233                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5234                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_HI);
5235                         break;
5236                 case OP_ICNEQ:
5237                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_NE);
5238                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_EQ);
5239                         break;
5240                 case OP_ICGE:
5241                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5242                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_LT);
5243                         break;
5244                 case OP_ICLE:
5245                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5246                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_GT);
5247                         break;
5248                 case OP_ICGE_UN:
5249                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5250                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_LO);
5251                         break;
5252                 case OP_ICLE_UN:
5253                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5254                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_HI);
5255                         break;
5256                 case OP_COND_EXC_EQ:
5257                 case OP_COND_EXC_NE_UN:
5258                 case OP_COND_EXC_LT:
5259                 case OP_COND_EXC_LT_UN:
5260                 case OP_COND_EXC_GT:
5261                 case OP_COND_EXC_GT_UN:
5262                 case OP_COND_EXC_GE:
5263                 case OP_COND_EXC_GE_UN:
5264                 case OP_COND_EXC_LE:
5265                 case OP_COND_EXC_LE_UN:
5266                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
5267                         break;
5268                 case OP_COND_EXC_IEQ:
5269                 case OP_COND_EXC_INE_UN:
5270                 case OP_COND_EXC_ILT:
5271                 case OP_COND_EXC_ILT_UN:
5272                 case OP_COND_EXC_IGT:
5273                 case OP_COND_EXC_IGT_UN:
5274                 case OP_COND_EXC_IGE:
5275                 case OP_COND_EXC_IGE_UN:
5276                 case OP_COND_EXC_ILE:
5277                 case OP_COND_EXC_ILE_UN:
5278                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
5279                         break;
5280                 case OP_COND_EXC_C:
5281                 case OP_COND_EXC_IC:
5282                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_CS, ins->inst_p1);
5283                         break;
5284                 case OP_COND_EXC_OV:
5285                 case OP_COND_EXC_IOV:
5286                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, ins->inst_p1);
5287                         break;
5288                 case OP_COND_EXC_NC:
5289                 case OP_COND_EXC_INC:
5290                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_CC, ins->inst_p1);
5291                         break;
5292                 case OP_COND_EXC_NO:
5293                 case OP_COND_EXC_INO:
5294                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VC, ins->inst_p1);
5295                         break;
5296                 case OP_IBEQ:
5297                 case OP_IBNE_UN:
5298                 case OP_IBLT:
5299                 case OP_IBLT_UN:
5300                 case OP_IBGT:
5301                 case OP_IBGT_UN:
5302                 case OP_IBGE:
5303                 case OP_IBGE_UN:
5304                 case OP_IBLE:
5305                 case OP_IBLE_UN:
5306                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
5307                         break;
5308
5309                 /* floating point opcodes */
5310                 case OP_R8CONST:
5311                         if (cfg->compile_aot) {
5312                                 ARM_FLDD (code, ins->dreg, ARMREG_PC, 0);
5313                                 ARM_B (code, 1);
5314                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
5315                                 code += 4;
5316                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[1];
5317                                 code += 4;
5318                         } else {
5319                                 /* FIXME: we can optimize the imm load by dealing with part of 
5320                                  * the displacement in LDFD (aligning to 512).
5321                                  */
5322                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
5323                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
5324                         }
5325                         break;
5326                 case OP_R4CONST:
5327                         if (cfg->compile_aot) {
5328                                 ARM_FLDS (code, ins->dreg, ARMREG_PC, 0);
5329                                 ARM_B (code, 0);
5330                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
5331                                 code += 4;
5332                                 if (!cfg->r4fp)
5333                                         ARM_CVTS (code, ins->dreg, ins->dreg);
5334                         } else {
5335                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
5336                                 ARM_FLDS (code, ins->dreg, ARMREG_LR, 0);
5337                                 if (!cfg->r4fp)
5338                                         ARM_CVTS (code, ins->dreg, ins->dreg);
5339                         }
5340                         break;
5341                 case OP_STORER8_MEMBASE_REG:
5342                         /* This is generated by the local regalloc pass which runs after the lowering pass */
5343                         if (!arm_is_fpimm8 (ins->inst_offset)) {
5344                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
5345                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_destbasereg);
5346                                 ARM_FSTD (code, ins->sreg1, ARMREG_LR, 0);
5347                         } else {
5348                                 ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
5349                         }
5350                         break;
5351                 case OP_LOADR8_MEMBASE:
5352                         /* This is generated by the local regalloc pass which runs after the lowering pass */
5353                         if (!arm_is_fpimm8 (ins->inst_offset)) {
5354                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
5355                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_basereg);
5356                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
5357                         } else {
5358                                 ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
5359                         }
5360                         break;
5361                 case OP_STORER4_MEMBASE_REG:
5362                         g_assert (arm_is_fpimm8 (ins->inst_offset));
5363                         if (cfg->r4fp) {
5364                                 ARM_FSTS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
5365                         } else {
5366                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5367                                 ARM_CVTD (code, vfp_scratch1, ins->sreg1);
5368                                 ARM_FSTS (code, vfp_scratch1, ins->inst_destbasereg, ins->inst_offset);
5369                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5370                         }
5371                         break;
5372                 case OP_LOADR4_MEMBASE:
5373                         if (cfg->r4fp) {
5374                                 ARM_FLDS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
5375                         } else {
5376                                 g_assert (arm_is_fpimm8 (ins->inst_offset));
5377                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5378                                 ARM_FLDS (code, vfp_scratch1, ins->inst_basereg, ins->inst_offset);
5379                                 ARM_CVTS (code, ins->dreg, vfp_scratch1);
5380                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5381                         }
5382                         break;
5383                 case OP_ICONV_TO_R_UN: {
5384                         g_assert_not_reached ();
5385                         break;
5386                 }
5387                 case OP_ICONV_TO_R4:
5388                         if (cfg->r4fp) {
5389                                 ARM_FMSR (code, ins->dreg, ins->sreg1);
5390                                 ARM_FSITOS (code, ins->dreg, ins->dreg);
5391                         } else {
5392                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5393                                 ARM_FMSR (code, vfp_scratch1, ins->sreg1);
5394                                 ARM_FSITOS (code, vfp_scratch1, vfp_scratch1);
5395                                 ARM_CVTS (code, ins->dreg, vfp_scratch1);
5396                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5397                         }
5398                         break;
5399                 case OP_ICONV_TO_R8:
5400                         code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5401                         ARM_FMSR (code, vfp_scratch1, ins->sreg1);
5402                         ARM_FSITOD (code, ins->dreg, vfp_scratch1);
5403                         code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5404                         break;
5405
5406                 case OP_SETFRET: {
5407                         MonoType *sig_ret = mini_type_get_underlying_type (NULL, mono_method_signature (cfg->method)->ret);
5408                         if (sig_ret->type == MONO_TYPE_R4) {
5409                                 if (cfg->r4fp) {
5410                                         g_assert (!IS_HARD_FLOAT);
5411                                         ARM_FMRS (code, ARMREG_R0, ins->sreg1);
5412                                 } else {
5413                                         ARM_CVTD (code, ARM_VFP_F0, ins->sreg1);
5414
5415                                         if (!IS_HARD_FLOAT)
5416                                                 ARM_FMRS (code, ARMREG_R0, ARM_VFP_F0);
5417                                 }
5418                         } else {
5419                                 if (IS_HARD_FLOAT)
5420                                         ARM_CPYD (code, ARM_VFP_D0, ins->sreg1);
5421                                 else
5422                                         ARM_FMRRD (code, ARMREG_R0, ARMREG_R1, ins->sreg1);
5423                         }
5424                         break;
5425                 }
5426                 case OP_FCONV_TO_I1:
5427                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
5428                         break;
5429                 case OP_FCONV_TO_U1:
5430                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
5431                         break;
5432                 case OP_FCONV_TO_I2:
5433                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
5434                         break;
5435                 case OP_FCONV_TO_U2:
5436                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
5437                         break;
5438                 case OP_FCONV_TO_I4:
5439                 case OP_FCONV_TO_I:
5440                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
5441                         break;
5442                 case OP_FCONV_TO_U4:
5443                 case OP_FCONV_TO_U:
5444                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
5445                         break;
5446                 case OP_FCONV_TO_I8:
5447                 case OP_FCONV_TO_U8:
5448                         g_assert_not_reached ();
5449                         /* Implemented as helper calls */
5450                         break;
5451                 case OP_LCONV_TO_R_UN:
5452                         g_assert_not_reached ();
5453                         /* Implemented as helper calls */
5454                         break;
5455                 case OP_LCONV_TO_OVF_I4_2: {
5456                         guint8 *high_bit_not_set, *valid_negative, *invalid_negative, *valid_positive;
5457                         /* 
5458                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
5459                          */
5460
5461                         ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
5462                         high_bit_not_set = code;
5463                         ARM_B_COND (code, ARMCOND_GE, 0); /*branch if bit 31 of the lower part is not set*/
5464
5465                         ARM_CMN_REG_IMM8 (code, ins->sreg2, 1); /*This have the same effect as CMP reg, 0xFFFFFFFF */
5466                         valid_negative = code;
5467                         ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0xFFFFFFFF (lower part has bit 31 set) */
5468                         invalid_negative = code;
5469                         ARM_B_COND (code, ARMCOND_AL, 0);
5470                         
5471                         arm_patch (high_bit_not_set, code);
5472
5473                         ARM_CMP_REG_IMM8 (code, ins->sreg2, 0);
5474                         valid_positive = code;
5475                         ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0 (lower part has bit 31 clear)*/
5476
5477                         arm_patch (invalid_negative, code);
5478                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_AL, "OverflowException");
5479
5480                         arm_patch (valid_negative, code);
5481                         arm_patch (valid_positive, code);
5482
5483                         if (ins->dreg != ins->sreg1)
5484                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
5485                         break;
5486                 }
5487                 case OP_FADD:
5488                         ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2);
5489                         break;
5490                 case OP_FSUB:
5491                         ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2);
5492                         break;          
5493                 case OP_FMUL:
5494                         ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2);
5495                         break;          
5496                 case OP_FDIV:
5497                         ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2);
5498                         break;          
5499                 case OP_FNEG:
5500                         ARM_NEGD (code, ins->dreg, ins->sreg1);
5501                         break;
5502                 case OP_FREM:
5503                         /* emulated */
5504                         g_assert_not_reached ();
5505                         break;
5506                 case OP_FCOMPARE:
5507                         if (IS_VFP) {
5508                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5509                                 ARM_FMSTAT (code);
5510                         }
5511                         break;
5512                 case OP_RCOMPARE:
5513                         g_assert (IS_VFP);
5514                         ARM_CMPS (code, ins->sreg1, ins->sreg2);
5515                         ARM_FMSTAT (code);
5516                         break;
5517                 case OP_FCEQ:
5518                         if (IS_VFP) {
5519                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5520                                 ARM_FMSTAT (code);
5521                         }
5522                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
5523                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
5524                         break;
5525                 case OP_FCLT:
5526                         if (IS_VFP) {
5527                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5528                                 ARM_FMSTAT (code);
5529                         }
5530                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5531                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5532                         break;
5533                 case OP_FCLT_UN:
5534                         if (IS_VFP) {
5535                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5536                                 ARM_FMSTAT (code);
5537                         }
5538                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5539                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5540                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
5541                         break;
5542                 case OP_FCGT:
5543                         if (IS_VFP) {
5544                                 ARM_CMPD (code, ins->sreg2, ins->sreg1);
5545                                 ARM_FMSTAT (code);
5546                         }
5547                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5548                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5549                         break;
5550                 case OP_FCGT_UN:
5551                         if (IS_VFP) {
5552                                 ARM_CMPD (code, ins->sreg2, ins->sreg1);
5553                                 ARM_FMSTAT (code);
5554                         }
5555                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5556                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5557                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
5558                         break;
5559                 case OP_FCNEQ:
5560                         if (IS_VFP) {
5561                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5562                                 ARM_FMSTAT (code);
5563                         }
5564                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_NE);
5565                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_EQ);
5566                         break;
5567                 case OP_FCGE:
5568                         if (IS_VFP) {
5569                                 ARM_CMPD (code, ins->sreg1, ins->sreg2);
5570                                 ARM_FMSTAT (code);
5571                         }
5572                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5573                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_MI);
5574                         break;
5575                 case OP_FCLE:
5576                         if (IS_VFP) {
5577                                 ARM_CMPD (code, ins->sreg2, ins->sreg1);
5578                                 ARM_FMSTAT (code);
5579                         }
5580                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5581                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_MI);
5582                         break;
5583
5584                 /* ARM FPA flags table:
5585                  * N        Less than               ARMCOND_MI
5586                  * Z        Equal                   ARMCOND_EQ
5587                  * C        Greater Than or Equal   ARMCOND_CS
5588                  * V        Unordered               ARMCOND_VS
5589                  */
5590                 case OP_FBEQ:
5591                         EMIT_COND_BRANCH (ins, OP_IBEQ - OP_IBEQ);
5592                         break;
5593                 case OP_FBNE_UN:
5594                         EMIT_COND_BRANCH (ins, OP_IBNE_UN - OP_IBEQ);
5595                         break;
5596                 case OP_FBLT:
5597                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
5598                         break;
5599                 case OP_FBLT_UN:
5600                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
5601                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
5602                         break;
5603                 case OP_FBGT:
5604                 case OP_FBGT_UN:
5605                 case OP_FBLE:
5606                 case OP_FBLE_UN:
5607                         g_assert_not_reached ();
5608                         break;
5609                 case OP_FBGE:
5610                         if (IS_VFP) {
5611                                 EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
5612                         } else {
5613                                 /* FPA requires EQ even thou the docs suggests that just CS is enough */
5614                                 EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_EQ);
5615                                 EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
5616                         }
5617                         break;
5618                 case OP_FBGE_UN:
5619                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
5620                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
5621                         break;
5622
5623                 case OP_CKFINITE: {
5624                         if (IS_VFP) {
5625                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch1);
5626                                 code = mono_arm_emit_vfp_scratch_save (cfg, code, vfp_scratch2);
5627
5628 #ifdef USE_JUMP_TABLES
5629                                 {
5630                                         gpointer *jte = mono_jumptable_add_entries (2);
5631                                         jte [0] = GUINT_TO_POINTER (0xffffffff);
5632                                         jte [1] = GUINT_TO_POINTER (0x7fefffff);
5633                                         code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_IP);
5634                                         ARM_FLDD (code, vfp_scratch1, ARMREG_IP, 0);
5635                                 }
5636 #else
5637                                 ARM_ABSD (code, vfp_scratch2, ins->sreg1);
5638                                 ARM_FLDD (code, vfp_scratch1, ARMREG_PC, 0);
5639                                 ARM_B (code, 1);
5640                                 *(guint32*)code = 0xffffffff;
5641                                 code += 4;
5642                                 *(guint32*)code = 0x7fefffff;
5643                                 code += 4;
5644 #endif
5645                                 ARM_CMPD (code, vfp_scratch2, vfp_scratch1);
5646                                 ARM_FMSTAT (code);
5647                                 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_GT, "ArithmeticException");
5648                                 ARM_CMPD (code, ins->sreg1, ins->sreg1);
5649                                 ARM_FMSTAT (code);
5650                                 EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, "ArithmeticException");
5651                                 ARM_CPYD (code, ins->dreg, ins->sreg1);
5652
5653                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch1);
5654                                 code = mono_arm_emit_vfp_scratch_restore (cfg, code, vfp_scratch2);
5655                         }
5656                         break;
5657                 }
5658
5659                 case OP_RCONV_TO_I1:
5660                         code = emit_r4_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
5661                         break;
5662                 case OP_RCONV_TO_U1:
5663                         code = emit_r4_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
5664                         break;
5665                 case OP_RCONV_TO_I2:
5666                         code = emit_r4_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
5667                         break;
5668                 case OP_RCONV_TO_U2:
5669                         code = emit_r4_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
5670                         break;
5671                 case OP_RCONV_TO_I4:
5672                         code = emit_r4_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
5673                         break;
5674                 case OP_RCONV_TO_U4:
5675                         code = emit_r4_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
5676                         break;
5677                 case OP_RCONV_TO_R4:
5678                         g_assert (IS_VFP);
5679                         if (ins->dreg != ins->sreg1)
5680                                 ARM_CPYS (code, ins->dreg, ins->sreg1);
5681                         break;
5682                 case OP_RCONV_TO_R8:
5683                         g_assert (IS_VFP);
5684                         ARM_CVTS (code, ins->dreg, ins->sreg1);
5685                         break;
5686                 case OP_RADD:
5687                         ARM_VFP_ADDS (code, ins->dreg, ins->sreg1, ins->sreg2);
5688                         break;
5689                 case OP_RSUB:
5690                         ARM_VFP_SUBS (code, ins->dreg, ins->sreg1, ins->sreg2);
5691                         break;          
5692                 case OP_RMUL:
5693                         ARM_VFP_MULS (code, ins->dreg, ins->sreg1, ins->sreg2);
5694                         break;          
5695                 case OP_RDIV:
5696                         ARM_VFP_DIVS (code, ins->dreg, ins->sreg1, ins->sreg2);
5697                         break;          
5698                 case OP_RNEG:
5699                         ARM_NEGS (code, ins->dreg, ins->sreg1);
5700                         break;
5701                 case OP_RCEQ:
5702                         if (IS_VFP) {
5703                                 ARM_CMPS (code, ins->sreg1, ins->sreg2);
5704                                 ARM_FMSTAT (code);
5705                         }
5706                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
5707                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
5708                         break;
5709                 case OP_RCLT:
5710                         if (IS_VFP) {
5711                                 ARM_CMPS (code, ins->sreg1, ins->sreg2);
5712                                 ARM_FMSTAT (code);
5713                         }
5714                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5715                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5716                         break;
5717                 case OP_RCLT_UN:
5718                         if (IS_VFP) {
5719                                 ARM_CMPS (code, ins->sreg1, ins->sreg2);
5720                                 ARM_FMSTAT (code);
5721                         }
5722                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5723                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5724                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
5725                         break;
5726                 case OP_RCGT:
5727                         if (IS_VFP) {
5728                                 ARM_CMPS (code, ins->sreg2, ins->sreg1);
5729                                 ARM_FMSTAT (code);
5730                         }
5731                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5732                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5733                         break;
5734                 case OP_RCGT_UN:
5735                         if (IS_VFP) {
5736                                 ARM_CMPS (code, ins->sreg2, ins->sreg1);
5737                                 ARM_FMSTAT (code);
5738                         }
5739                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
5740                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
5741                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
5742                         break;
5743                 case OP_RCNEQ:
5744                         if (IS_VFP) {
5745                                 ARM_CMPS (code, ins->sreg1, ins->sreg2);
5746                                 ARM_FMSTAT (code);
5747                         }
5748                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_NE);
5749                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_EQ);
5750                         break;
5751                 case OP_RCGE:
5752                         if (IS_VFP) {
5753                                 ARM_CMPS (code, ins->sreg1, ins->sreg2);
5754                                 ARM_FMSTAT (code);
5755                         }
5756                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5757                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_MI);
5758                         break;
5759                 case OP_RCLE:
5760                         if (IS_VFP) {
5761                                 ARM_CMPS (code, ins->sreg2, ins->sreg1);
5762                                 ARM_FMSTAT (code);
5763                         }
5764                         ARM_MOV_REG_IMM8 (code, ins->dreg, 1);
5765                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_MI);
5766                         break;
5767
5768                 case OP_GC_LIVENESS_DEF:
5769                 case OP_GC_LIVENESS_USE:
5770                 case OP_GC_PARAM_SLOT_LIVENESS_DEF:
5771                         ins->backend.pc_offset = code - cfg->native_code;
5772                         break;
5773                 case OP_GC_SPILL_SLOT_LIVENESS_DEF:
5774                         ins->backend.pc_offset = code - cfg->native_code;
5775                         bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
5776                         break;
5777
5778                 default:
5779                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
5780                         g_assert_not_reached ();
5781                 }
5782
5783                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
5784                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
5785                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
5786                         g_assert_not_reached ();
5787                 }
5788                
5789                 cpos += max_len;
5790
5791                 last_ins = ins;
5792                 last_offset = offset;
5793         }
5794
5795         cfg->code_len = code - cfg->native_code;
5796 }
5797
5798 #endif /* DISABLE_JIT */
5799
5800 #ifdef HAVE_AEABI_READ_TP
5801 void __aeabi_read_tp (void);
5802 #endif
5803
5804 void
5805 mono_arch_register_lowlevel_calls (void)
5806 {
5807         /* The signature doesn't matter */
5808         mono_register_jit_icall (mono_arm_throw_exception, "mono_arm_throw_exception", mono_create_icall_signature ("void"), TRUE);
5809         mono_register_jit_icall (mono_arm_throw_exception_by_token, "mono_arm_throw_exception_by_token", mono_create_icall_signature ("void"), TRUE);
5810
5811 #ifndef MONO_CROSS_COMPILE
5812 #ifdef HAVE_AEABI_READ_TP
5813         mono_register_jit_icall (__aeabi_read_tp, "__aeabi_read_tp", mono_create_icall_signature ("void"), TRUE);
5814 #endif
5815 #endif
5816 }
5817
5818 #define patch_lis_ori(ip,val) do {\
5819                 guint16 *__lis_ori = (guint16*)(ip);    \
5820                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
5821                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
5822         } while (0)
5823
5824 void
5825 mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target)
5826 {
5827         unsigned char *ip = ji->ip.i + code;
5828
5829         if (ji->type == MONO_PATCH_INFO_SWITCH) {
5830         }
5831
5832         switch (ji->type) {
5833         case MONO_PATCH_INFO_SWITCH: {
5834 #ifdef USE_JUMP_TABLES
5835                 gpointer *jt = mono_jumptable_get_entry (ip);
5836 #else
5837                 gpointer *jt = (gpointer*)(ip + 8);
5838 #endif
5839                 int i;
5840                 /* jt is the inlined jump table, 2 instructions after ip
5841                  * In the normal case we store the absolute addresses,
5842                  * otherwise the displacements.
5843                  */
5844                 for (i = 0; i < ji->data.table->table_size; i++)
5845                         jt [i] = code + (int)ji->data.table->table [i];
5846                 break;
5847         }
5848         case MONO_PATCH_INFO_IP:
5849                 g_assert_not_reached ();
5850                 patch_lis_ori (ip, ip);
5851                 break;
5852         case MONO_PATCH_INFO_METHOD_REL:
5853                 g_assert_not_reached ();
5854                 *((gpointer *)(ip)) = target;
5855                 break;
5856         case MONO_PATCH_INFO_METHODCONST:
5857         case MONO_PATCH_INFO_CLASS:
5858         case MONO_PATCH_INFO_IMAGE:
5859         case MONO_PATCH_INFO_FIELD:
5860         case MONO_PATCH_INFO_VTABLE:
5861         case MONO_PATCH_INFO_IID:
5862         case MONO_PATCH_INFO_SFLDA:
5863         case MONO_PATCH_INFO_LDSTR:
5864         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
5865         case MONO_PATCH_INFO_LDTOKEN:
5866                 g_assert_not_reached ();
5867                 /* from OP_AOTCONST : lis + ori */
5868                 patch_lis_ori (ip, target);
5869                 break;
5870         case MONO_PATCH_INFO_R4:
5871         case MONO_PATCH_INFO_R8:
5872                 g_assert_not_reached ();
5873                 *((gconstpointer *)(ip + 2)) = target;
5874                 break;
5875         case MONO_PATCH_INFO_EXC_NAME:
5876                 g_assert_not_reached ();
5877                 *((gconstpointer *)(ip + 1)) = target;
5878                 break;
5879         case MONO_PATCH_INFO_NONE:
5880         case MONO_PATCH_INFO_BB_OVF:
5881         case MONO_PATCH_INFO_EXC_OVF:
5882                 /* everything is dealt with at epilog output time */
5883                 break;
5884         default:
5885                 arm_patch_general (cfg, domain, ip, target);
5886                 break;
5887         }
5888 }
5889
5890 #ifndef DISABLE_JIT
5891
5892 /*
5893  * Stack frame layout:
5894  * 
5895  *   ------------------- fp
5896  *      MonoLMF structure or saved registers
5897  *   -------------------
5898  *      locals
5899  *   -------------------
5900  *      spilled regs
5901  *   -------------------
5902  *      optional 8 bytes for tracing
5903  *   -------------------
5904  *      param area             size is cfg->param_area
5905  *   ------------------- sp
5906  */
5907 guint8 *
5908 mono_arch_emit_prolog (MonoCompile *cfg)
5909 {
5910         MonoMethod *method = cfg->method;
5911         MonoBasicBlock *bb;
5912         MonoMethodSignature *sig;
5913         MonoInst *inst;
5914         int alloc_size, orig_alloc_size, pos, max_offset, i, rot_amount, part;
5915         guint8 *code;
5916         CallInfo *cinfo;
5917         int tracing = 0;
5918         int lmf_offset = 0;
5919         int prev_sp_offset, reg_offset;
5920
5921         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5922                 tracing = 1;
5923
5924         sig = mono_method_signature (method);
5925         cfg->code_size = 256 + sig->param_count * 64;
5926         code = cfg->native_code = g_malloc (cfg->code_size);
5927
5928         mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, 0);
5929
5930         alloc_size = cfg->stack_offset;
5931         pos = 0;
5932         prev_sp_offset = 0;
5933
5934         if (iphone_abi) {
5935                 /* 
5936                  * The iphone uses R7 as the frame pointer, and it points at the saved
5937                  * r7+lr:
5938                  *         <lr>
5939                  * r7 ->   <r7>
5940                  *         <rest of frame>
5941                  * We can't use r7 as a frame pointer since it points into the middle of
5942                  * the frame, so we keep using our own frame pointer.
5943                  * FIXME: Optimize this.
5944                  */
5945                 ARM_PUSH (code, (1 << ARMREG_R7) | (1 << ARMREG_LR));
5946                 ARM_MOV_REG_REG (code, ARMREG_R7, ARMREG_SP);
5947                 prev_sp_offset += 8; /* r7 and lr */
5948                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
5949                 mono_emit_unwind_op_offset (cfg, code, ARMREG_R7, (- prev_sp_offset) + 0);
5950         }
5951
5952         if (!method->save_lmf) {
5953                 if (iphone_abi) {
5954                         /* No need to push LR again */
5955                         if (cfg->used_int_regs)
5956                                 ARM_PUSH (code, cfg->used_int_regs);
5957                 } else {
5958                         ARM_PUSH (code, cfg->used_int_regs | (1 << ARMREG_LR));
5959                         prev_sp_offset += 4;
5960                 }
5961                 for (i = 0; i < 16; ++i) {
5962                         if (cfg->used_int_regs & (1 << i))
5963                                 prev_sp_offset += 4;
5964                 }
5965                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
5966                 reg_offset = 0;
5967                 for (i = 0; i < 16; ++i) {
5968                         if ((cfg->used_int_regs & (1 << i))) {
5969                                 mono_emit_unwind_op_offset (cfg, code, i, (- prev_sp_offset) + reg_offset);
5970                                 mini_gc_set_slot_type_from_cfa (cfg, (- prev_sp_offset) + reg_offset, SLOT_NOREF);
5971                                 reg_offset += 4;
5972                         }
5973                 }
5974                 if (iphone_abi) {
5975                         mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, -4);
5976                         mini_gc_set_slot_type_from_cfa (cfg, -4, SLOT_NOREF);
5977                 } else {
5978                         mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, -4);
5979                         mini_gc_set_slot_type_from_cfa (cfg, -4, SLOT_NOREF);
5980                 }
5981         } else {
5982                 ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
5983                 ARM_PUSH (code, 0x5ff0);
5984                 prev_sp_offset += 4 * 10; /* all but r0-r3, sp and pc */
5985                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
5986                 reg_offset = 0;
5987                 for (i = 0; i < 16; ++i) {
5988                         if ((i > ARMREG_R3) && (i != ARMREG_SP) && (i != ARMREG_PC)) {
5989                                 /* The original r7 is saved at the start */
5990                                 if (!(iphone_abi && i == ARMREG_R7))
5991                                         mono_emit_unwind_op_offset (cfg, code, i, (- prev_sp_offset) + reg_offset);
5992                                 reg_offset += 4;
5993                         }
5994                 }
5995                 g_assert (reg_offset == 4 * 10);
5996                 pos += sizeof (MonoLMF) - (4 * 10);
5997                 lmf_offset = pos;
5998         }
5999         alloc_size += pos;
6000         orig_alloc_size = alloc_size;
6001         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
6002         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
6003                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
6004                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
6005         }
6006
6007         /* the stack used in the pushed regs */
6008         if (prev_sp_offset & 4)
6009                 alloc_size += 4;
6010         cfg->stack_usage = alloc_size;
6011         if (alloc_size) {
6012                 if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
6013                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
6014                 } else {
6015                         code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
6016                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
6017                 }
6018                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset + alloc_size);
6019         }
6020         if (cfg->frame_reg != ARMREG_SP) {
6021                 ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
6022                 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
6023         }
6024         //g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
6025         prev_sp_offset += alloc_size;
6026
6027         for (i = 0; i < alloc_size - orig_alloc_size; i += 4)
6028                 mini_gc_set_slot_type_from_cfa (cfg, (- prev_sp_offset) + orig_alloc_size + i, SLOT_NOREF);
6029
6030         /* compute max_offset in order to use short forward jumps
6031          * we could skip do it on arm because the immediate displacement
6032          * for jumps is large enough, it may be useful later for constant pools
6033          */
6034         max_offset = 0;
6035         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
6036                 MonoInst *ins = bb->code;
6037                 bb->max_offset = max_offset;
6038
6039                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
6040                         max_offset += 6; 
6041
6042                 MONO_BB_FOR_EACH_INS (bb, ins)
6043                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
6044         }
6045
6046         /* store runtime generic context */
6047         if (cfg->rgctx_var) {
6048                 MonoInst *ins = cfg->rgctx_var;
6049
6050                 g_assert (ins->opcode == OP_REGOFFSET);
6051
6052                 if (arm_is_imm12 (ins->inst_offset)) {
6053                         ARM_STR_IMM (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
6054                 } else {
6055                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
6056                         ARM_STR_REG_REG (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ARMREG_LR);
6057                 }
6058         }
6059
6060         /* load arguments allocated to register from the stack */
6061         pos = 0;
6062
6063         cinfo = get_call_info (cfg->generic_sharing_context, NULL, sig);
6064
6065         if (cinfo->ret.storage == RegTypeStructByAddr) {
6066                 ArgInfo *ainfo = &cinfo->ret;
6067                 inst = cfg->vret_addr;
6068                 g_assert (arm_is_imm12 (inst->inst_offset));
6069                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
6070         }
6071
6072         if (sig->call_convention == MONO_CALL_VARARG) {
6073                 ArgInfo *cookie = &cinfo->sig_cookie;
6074
6075                 /* Save the sig cookie address */
6076                 g_assert (cookie->storage == RegTypeBase);
6077
6078                 g_assert (arm_is_imm12 (prev_sp_offset + cookie->offset));
6079                 g_assert (arm_is_imm12 (cfg->sig_cookie));
6080                 ARM_ADD_REG_IMM8 (code, ARMREG_IP, cfg->frame_reg, prev_sp_offset + cookie->offset);
6081                 ARM_STR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie);
6082         }
6083
6084         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6085                 ArgInfo *ainfo = cinfo->args + i;
6086                 inst = cfg->args [pos];
6087                 
6088                 if (cfg->verbose_level > 2)
6089                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
6090
6091                 if (inst->opcode == OP_REGVAR) {
6092                         if (ainfo->storage == RegTypeGeneral)
6093                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
6094                         else if (ainfo->storage == RegTypeFP) {
6095                                 g_assert_not_reached ();
6096                         } else if (ainfo->storage == RegTypeBase) {
6097                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
6098                                         ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
6099                                 } else {
6100                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
6101                                         ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
6102                                 }
6103                         } else
6104                                 g_assert_not_reached ();
6105
6106                         if (cfg->verbose_level > 2)
6107                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
6108                 } else {
6109                         switch (ainfo->storage) {
6110                         case RegTypeHFA:
6111                                 for (part = 0; part < ainfo->nregs; part ++) {
6112                                         if (ainfo->esize == 4)
6113                                                 ARM_FSTS (code, ainfo->reg + part, inst->inst_basereg, inst->inst_offset + (part * ainfo->esize));
6114                                         else
6115                                                 ARM_FSTD (code, ainfo->reg + (part * 2), inst->inst_basereg, inst->inst_offset + (part * ainfo->esize));
6116                                 }
6117                                 break;
6118                         case RegTypeGeneral:
6119                         case RegTypeIRegPair:
6120                         case RegTypeGSharedVtInReg:
6121                                 switch (ainfo->size) {
6122                                 case 1:
6123                                         if (arm_is_imm12 (inst->inst_offset))
6124                                                 ARM_STRB_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
6125                                         else {
6126                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6127                                                 ARM_STRB_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
6128                                         }
6129                                         break;
6130                                 case 2:
6131                                         if (arm_is_imm8 (inst->inst_offset)) {
6132                                                 ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
6133                                         } else {
6134                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6135                                                 ARM_STRH_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
6136                                         }
6137                                         break;
6138                                 case 8:
6139                                         if (arm_is_imm12 (inst->inst_offset)) {
6140                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
6141                                         } else {
6142                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6143                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
6144                                         }
6145                                         if (arm_is_imm12 (inst->inst_offset + 4)) {
6146                                                 ARM_STR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
6147                                         } else {
6148                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
6149                                                 ARM_STR_REG_REG (code, ainfo->reg + 1, inst->inst_basereg, ARMREG_IP);
6150                                         }
6151                                         break;
6152                                 default:
6153                                         if (arm_is_imm12 (inst->inst_offset)) {
6154                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
6155                                         } else {
6156                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6157                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
6158                                         }
6159                                         break;
6160                                 }
6161                                 break;
6162                         case RegTypeBaseGen:
6163                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
6164                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
6165                                 } else {
6166                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
6167                                         ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
6168                                 }
6169                                 if (arm_is_imm12 (inst->inst_offset + 4)) {
6170                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
6171                                         ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset);
6172                                 } else {
6173                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
6174                                         ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6175                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6176                                         ARM_STR_REG_REG (code, ARMREG_R3, inst->inst_basereg, ARMREG_IP);
6177                                 }
6178                                 break;
6179                         case RegTypeBase:
6180                         case RegTypeGSharedVtOnStack:
6181                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
6182                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
6183                                 } else {
6184                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
6185                                         ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
6186                                 }
6187
6188                                 switch (ainfo->size) {
6189                                 case 1:
6190                                         if (arm_is_imm8 (inst->inst_offset)) {
6191                                                 ARM_STRB_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
6192                                         } else {
6193                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6194                                                 ARM_STRB_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6195                                         }
6196                                         break;
6197                                 case 2:
6198                                         if (arm_is_imm8 (inst->inst_offset)) {
6199                                                 ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
6200                                         } else {
6201                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6202                                                 ARM_STRH_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6203                                         }
6204                                         break;
6205                                 case 8:
6206                                         if (arm_is_imm12 (inst->inst_offset)) {
6207                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
6208                                         } else {
6209                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6210                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6211                                         }
6212                                         if (arm_is_imm12 (prev_sp_offset + ainfo->offset + 4)) {
6213                                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset + 4));
6214                                         } else {
6215                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset + 4);
6216                                                 ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
6217                                         }
6218                                         if (arm_is_imm12 (inst->inst_offset + 4)) {
6219                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
6220                                         } else {
6221                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
6222                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6223                                         }
6224                                         break;
6225                                 default:
6226                                         if (arm_is_imm12 (inst->inst_offset)) {
6227                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
6228                                         } else {
6229                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6230                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
6231                                         }
6232                                         break;
6233                                 }
6234                                 break;
6235                         case RegTypeFP: {
6236                                 int imm8, rot_amount;
6237
6238                                 if ((imm8 = mono_arm_is_rotated_imm8 (inst->inst_offset, &rot_amount)) == -1) {
6239                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
6240                                         ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
6241                                 } else
6242                                         ARM_ADD_REG_IMM (code, ARMREG_IP, inst->inst_basereg, imm8, rot_amount);
6243
6244                                 if (ainfo->size == 8)
6245                                         ARM_FSTD (code, ainfo->reg, ARMREG_IP, 0);
6246                                 else
6247                                         ARM_FSTS (code, ainfo->reg, ARMREG_IP, 0);
6248                                 break;
6249                         }
6250                         case RegTypeStructByVal: {
6251                                 int doffset = inst->inst_offset;
6252                                 int soffset = 0;
6253                                 int cur_reg;
6254                                 int size = 0;
6255                                 size = mini_type_stack_size_full (cfg->generic_sharing_context, inst->inst_vtype, NULL, sig->pinvoke);
6256                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
6257                                         if (arm_is_imm12 (doffset)) {
6258                                                 ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
6259                                         } else {
6260                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
6261                                                 ARM_STR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
6262                                         }
6263                                         soffset += sizeof (gpointer);
6264                                         doffset += sizeof (gpointer);
6265                                 }
6266                                 if (ainfo->vtsize) {
6267                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
6268                                         //g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
6269                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
6270                                 }
6271                                 break;
6272                         }
6273                         case RegTypeStructByAddr:
6274                                 g_assert_not_reached ();
6275                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
6276                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
6277                         default:
6278                                 g_assert_not_reached ();
6279                                 break;
6280                         }
6281                 }
6282                 pos++;
6283         }
6284
6285         if (method->save_lmf)
6286                 code = emit_save_lmf (cfg, code, alloc_size - lmf_offset);
6287
6288         if (tracing)
6289                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
6290
6291         if (cfg->arch.seq_point_info_var) {
6292                 MonoInst *ins = cfg->arch.seq_point_info_var;
6293
6294                 /* Initialize the variable from a GOT slot */
6295                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_SEQ_POINT_INFO, cfg->method);
6296 #ifdef USE_JUMP_TABLES
6297                 {
6298                         gpointer *jte = mono_jumptable_add_entry ();
6299                         code = mono_arm_load_jumptable_entry (code, jte, ARMREG_IP);
6300                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_IP, 0);
6301                 }
6302                 /** XXX: is it correct? */
6303 #else
6304                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
6305                 ARM_B (code, 0);
6306                 *(gpointer*)code = NULL;
6307                 code += 4;
6308 #endif
6309                 ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
6310
6311                 g_assert (ins->opcode == OP_REGOFFSET);
6312
6313                 if (arm_is_imm12 (ins->inst_offset)) {
6314                         ARM_STR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
6315                 } else {
6316                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
6317                         ARM_STR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
6318                 }
6319         }
6320
6321         /* Initialize ss_trigger_page_var */
6322         if (!cfg->soft_breakpoints) {
6323                 MonoInst *info_var = cfg->arch.seq_point_info_var;
6324                 MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
6325                 int dreg = ARMREG_LR;
6326
6327                 if (info_var) {
6328                         g_assert (info_var->opcode == OP_REGOFFSET);
6329                         g_assert (arm_is_imm12 (info_var->inst_offset));
6330
6331                         ARM_LDR_IMM (code, dreg, info_var->inst_basereg, info_var->inst_offset);
6332                         /* Load the trigger page addr */
6333                         ARM_LDR_IMM (code, dreg, dreg, MONO_STRUCT_OFFSET (SeqPointInfo, ss_trigger_page));
6334                         ARM_STR_IMM (code, dreg, ss_trigger_page_var->inst_basereg, ss_trigger_page_var->inst_offset);
6335                 }
6336         }
6337
6338         if (cfg->arch.seq_point_read_var) {
6339                 MonoInst *read_ins = cfg->arch.seq_point_read_var;
6340                 MonoInst *ss_method_ins = cfg->arch.seq_point_ss_method_var;
6341                 MonoInst *bp_method_ins = cfg->arch.seq_point_bp_method_var;
6342 #ifdef USE_JUMP_TABLES
6343                 gpointer *jte;
6344 #endif
6345                 g_assert (read_ins->opcode == OP_REGOFFSET);
6346                 g_assert (arm_is_imm12 (read_ins->inst_offset));
6347                 g_assert (ss_method_ins->opcode == OP_REGOFFSET);
6348                 g_assert (arm_is_imm12 (ss_method_ins->inst_offset));
6349                 g_assert (bp_method_ins->opcode == OP_REGOFFSET);
6350                 g_assert (arm_is_imm12 (bp_method_ins->inst_offset));
6351
6352 #ifdef USE_JUMP_TABLES
6353                 jte = mono_jumptable_add_entries (3);
6354                 jte [0] = (gpointer)&ss_trigger_var;
6355                 jte [1] = single_step_tramp;
6356                 jte [2] = breakpoint_tramp;
6357                 code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_LR);
6358 #else
6359                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
6360                 ARM_B (code, 2);
6361                 *(volatile int **)code = &ss_trigger_var;
6362                 code += 4;
6363                 *(gpointer*)code = single_step_tramp;
6364                 code += 4;
6365                 *(gpointer*)code = breakpoint_tramp;
6366                 code += 4;
6367 #endif
6368
6369                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 0);
6370                 ARM_STR_IMM (code, ARMREG_IP, read_ins->inst_basereg, read_ins->inst_offset);
6371                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 4);
6372                 ARM_STR_IMM (code, ARMREG_IP, ss_method_ins->inst_basereg, ss_method_ins->inst_offset);
6373                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_LR, 8);
6374                 ARM_STR_IMM (code, ARMREG_IP, bp_method_ins->inst_basereg, bp_method_ins->inst_offset);
6375         }
6376
6377         cfg->code_len = code - cfg->native_code;
6378         g_assert (cfg->code_len < cfg->code_size);
6379         g_free (cinfo);
6380
6381         return code;
6382 }
6383
6384 void
6385 mono_arch_emit_epilog (MonoCompile *cfg)
6386 {
6387         MonoMethod *method = cfg->method;
6388         int pos, i, rot_amount;
6389         int max_epilog_size = 16 + 20*4;
6390         guint8 *code;
6391         CallInfo *cinfo;
6392
6393         if (cfg->method->save_lmf)
6394                 max_epilog_size += 128;
6395         
6396         if (mono_jit_trace_calls != NULL)
6397                 max_epilog_size += 50;
6398
6399         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
6400                 max_epilog_size += 50;
6401
6402         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
6403                 cfg->code_size *= 2;
6404                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
6405                 cfg->stat_code_reallocs++;
6406         }
6407
6408         /*
6409          * Keep in sync with OP_JMP
6410          */
6411         code = cfg->native_code + cfg->code_len;
6412
6413         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
6414                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
6415         }
6416         pos = 0;
6417
6418         /* Load returned vtypes into registers if needed */
6419         cinfo = cfg->arch.cinfo;
6420         switch (cinfo->ret.storage) {
6421         case RegTypeStructByVal: {
6422                 MonoInst *ins = cfg->ret;
6423
6424                 if (arm_is_imm12 (ins->inst_offset)) {
6425                         ARM_LDR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
6426                 } else {
6427                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
6428                         ARM_LDR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
6429                 }
6430                 break;
6431         }
6432         case RegTypeHFA: {
6433                 MonoInst *ins = cfg->ret;
6434
6435                 for (i = 0; i < cinfo->ret.nregs; ++i) {
6436                         if (cinfo->ret.esize == 4)
6437                                 ARM_FLDS (code, cinfo->ret.reg + i, ins->inst_basereg, ins->inst_offset + (i * cinfo->ret.esize));
6438                         else
6439                                 ARM_FLDD (code, cinfo->ret.reg + (i * 2), ins->inst_basereg, ins->inst_offset + (i * cinfo->ret.esize));
6440                 }
6441                 break;
6442         }
6443         default:
6444                 break;
6445         }
6446
6447         if (method->save_lmf) {
6448                 int lmf_offset, reg, sp_adj, regmask;
6449                 /* all but r0-r3, sp and pc */
6450                 pos += sizeof (MonoLMF) - (MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t));
6451                 lmf_offset = pos;
6452
6453                 code = emit_restore_lmf (cfg, code, cfg->stack_usage - lmf_offset);
6454
6455                 /* This points to r4 inside MonoLMF->iregs */
6456                 sp_adj = (sizeof (MonoLMF) - MONO_ARM_NUM_SAVED_REGS * sizeof (mgreg_t));
6457                 reg = ARMREG_R4;
6458                 regmask = 0x9ff0; /* restore lr to pc */
6459                 /* Skip caller saved registers not used by the method */
6460                 while (!(cfg->used_int_regs & (1 << reg)) && reg < ARMREG_FP) {
6461                         regmask &= ~(1 << reg);
6462                         sp_adj += 4;
6463                         reg ++;
6464                 }
6465                 if (iphone_abi)
6466                         /* Restored later */
6467                         regmask &= ~(1 << ARMREG_PC);
6468                 /* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
6469                 code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage - lmf_offset + sp_adj);
6470                 /* restore iregs */
6471                 ARM_POP (code, regmask); 
6472                 if (iphone_abi) {
6473                         /* Restore saved r7, restore LR to PC */
6474                         /* Skip lr from the lmf */
6475                         ARM_ADD_REG_IMM (code, ARMREG_SP, ARMREG_SP, sizeof (gpointer), 0);
6476                         ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_PC));
6477                 }
6478         } else {
6479                 if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
6480                         ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
6481                 } else {
6482                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage);
6483                         ARM_ADD_REG_REG (code, ARMREG_SP, cfg->frame_reg, ARMREG_IP);
6484                 }
6485
6486                 if (iphone_abi) {
6487                         /* Restore saved gregs */
6488                         if (cfg->used_int_regs)
6489                                 ARM_POP (code, cfg->used_int_regs);
6490                         /* Restore saved r7, restore LR to PC */
6491                         ARM_POP (code, (1 << ARMREG_R7) | (1 << ARMREG_PC));
6492                 } else {
6493                         ARM_POP (code, cfg->used_int_regs | (1 << ARMREG_PC));
6494                 }
6495         }
6496
6497         cfg->code_len = code - cfg->native_code;
6498
6499         g_assert (cfg->code_len < cfg->code_size);
6500
6501 }
6502
6503 void
6504 mono_arch_emit_exceptions (MonoCompile *cfg)
6505 {
6506         MonoJumpInfo *patch_info;
6507         int i;
6508         guint8 *code;
6509         guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
6510         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
6511         int max_epilog_size = 50;
6512
6513         for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
6514                 exc_throw_pos [i] = NULL;
6515                 exc_throw_found [i] = 0;
6516         }
6517
6518         /* count the number of exception infos */
6519      
6520         /* 
6521          * make sure we have enough space for exceptions
6522          */
6523         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
6524                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
6525                         i = mini_exception_id_by_name (patch_info->data.target);
6526                         if (!exc_throw_found [i]) {
6527                                 max_epilog_size += 32;
6528                                 exc_throw_found [i] = TRUE;
6529                         }
6530                 }
6531         }
6532
6533         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
6534                 cfg->code_size *= 2;
6535                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
6536                 cfg->stat_code_reallocs++;
6537         }
6538
6539         code = cfg->native_code + cfg->code_len;
6540
6541         /* add code to raise exceptions */
6542         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
6543                 switch (patch_info->type) {
6544                 case MONO_PATCH_INFO_EXC: {
6545                         MonoClass *exc_class;
6546                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
6547
6548                         i = mini_exception_id_by_name (patch_info->data.target);
6549                         if (exc_throw_pos [i]) {
6550                                 arm_patch (ip, exc_throw_pos [i]);
6551                                 patch_info->type = MONO_PATCH_INFO_NONE;
6552                                 break;
6553                         } else {
6554                                 exc_throw_pos [i] = code;
6555                         }
6556                         arm_patch (ip, code);
6557
6558                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
6559                         g_assert (exc_class);
6560
6561                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR);
6562 #ifdef USE_JUMP_TABLES
6563                         {
6564                                 gpointer *jte = mono_jumptable_add_entries (2);
6565                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
6566                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
6567                                 patch_info->ip.i = code - cfg->native_code;
6568                                 code = mono_arm_load_jumptable_entry_addr (code, jte, ARMREG_R0);
6569                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, 0);
6570                                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, 4);
6571                                 ARM_BLX_REG (code, ARMREG_IP);
6572                                 jte [1] = GUINT_TO_POINTER (exc_class->type_token);
6573                         }
6574 #else
6575                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
6576                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
6577                         patch_info->data.name = "mono_arch_throw_corlib_exception";
6578                         patch_info->ip.i = code - cfg->native_code;
6579                         ARM_BL (code, 0);
6580                         cfg->thunk_area += THUNK_SIZE;
6581                         *(guint32*)(gpointer)code = exc_class->type_token;
6582                         code += 4;
6583 #endif
6584                         break;
6585                 }
6586                 default:
6587                         /* do nothing */
6588                         break;
6589                 }
6590         }
6591
6592         cfg->code_len = code - cfg->native_code;
6593
6594         g_assert (cfg->code_len < cfg->code_size);
6595
6596 }
6597
6598 #endif /* #ifndef DISABLE_JIT */
6599
6600 void
6601 mono_arch_finish_init (void)
6602 {
6603 }
6604
6605 void
6606 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
6607 {
6608 }
6609
6610 MonoInst*
6611 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
6612 {
6613         /* FIXME: */
6614         return NULL;
6615 }
6616
6617 gboolean
6618 mono_arch_print_tree (MonoInst *tree, int arity)
6619 {
6620         return 0;
6621 }
6622
6623 #ifndef DISABLE_JIT
6624
6625 #endif
6626
6627 guint32
6628 mono_arch_get_patch_offset (guint8 *code)
6629 {
6630         /* OP_AOTCONST */
6631         return 8;
6632 }
6633
6634 void
6635 mono_arch_flush_register_windows (void)
6636 {
6637 }
6638
6639 MonoMethod*
6640 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
6641 {
6642         return (MonoMethod*)regs [MONO_ARCH_IMT_REG];
6643 }
6644
6645 MonoVTable*
6646 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
6647 {
6648         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
6649 }
6650
6651 /* #define ENABLE_WRONG_METHOD_CHECK 1 */
6652 #define BASE_SIZE (6 * 4)
6653 #define BSEARCH_ENTRY_SIZE (4 * 4)
6654 #define CMP_SIZE (3 * 4)
6655 #define BRANCH_SIZE (1 * 4)
6656 #define CALL_SIZE (2 * 4)
6657 #define WMC_SIZE (8 * 4)
6658 #define DISTANCE(A, B) (((gint32)(B)) - ((gint32)(A)))
6659
6660 #ifdef USE_JUMP_TABLES
6661 static void
6662 set_jumptable_element (gpointer *base, guint32 index, gpointer value)
6663 {
6664         g_assert (base [index] == NULL);
6665         base [index] = value;
6666 }
6667 static arminstr_t *
6668 load_element_with_regbase_cond (arminstr_t *code, ARMReg dreg, ARMReg base, guint32 jti, int cond)
6669 {
6670         if (arm_is_imm12 (jti * 4)) {
6671                 ARM_LDR_IMM_COND (code, dreg, base, jti * 4, cond);
6672         } else {
6673                 ARM_MOVW_REG_IMM_COND (code, dreg, (jti * 4) & 0xffff, cond);
6674                 if ((jti * 4) >> 16)
6675                         ARM_MOVT_REG_IMM_COND (code, dreg, ((jti * 4) >> 16) & 0xffff, cond);
6676                 ARM_LDR_REG_REG_SHIFT_COND (code, dreg, base, dreg, ARMSHIFT_LSL, 0, cond);
6677         }
6678         return code;
6679 }
6680 #else
6681 static arminstr_t *
6682 arm_emit_value_and_patch_ldr (arminstr_t *code, arminstr_t *target, guint32 value)
6683 {
6684         guint32 delta = DISTANCE (target, code);
6685         delta -= 8;
6686         g_assert (delta >= 0 && delta <= 0xFFF);
6687         *target = *target | delta;
6688         *code = value;
6689         return code + 1;
6690 }
6691 #endif
6692
6693 #ifdef ENABLE_WRONG_METHOD_CHECK
6694 static void
6695 mini_dump_bad_imt (int input_imt, int compared_imt, int pc)
6696 {
6697         g_print ("BAD IMT comparing %x with expected %x at ip %x", input_imt, compared_imt, pc);
6698         g_assert (0);
6699 }
6700 #endif
6701
6702 gpointer
6703 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
6704         gpointer fail_tramp)
6705 {
6706         int size, i;
6707         arminstr_t *code, *start;
6708 #ifdef USE_JUMP_TABLES
6709         gpointer *jte;
6710 #else
6711         gboolean large_offsets = FALSE;
6712         guint32 **constant_pool_starts;
6713         arminstr_t *vtable_target = NULL;
6714         int extra_space = 0;
6715 #endif
6716 #ifdef ENABLE_WRONG_METHOD_CHECK
6717         char * cond;
6718 #endif
6719
6720         size = BASE_SIZE;
6721 #ifdef USE_JUMP_TABLES
6722         for (i = 0; i < count; ++i) {
6723                 MonoIMTCheckItem *item = imt_entries [i];
6724                 item->chunk_size += 4 * 16;
6725                 if (!item->is_equals)
6726                         imt_entries [item->check_target_idx]->compare_done = TRUE;
6727                 size += item->chunk_size;
6728         }
6729 #else
6730         constant_pool_starts = g_new0 (guint32*, count);
6731
6732         for (i = 0; i < count; ++i) {
6733                 MonoIMTCheckItem *item = imt_entries [i];
6734                 if (item->is_equals) {
6735                         gboolean fail_case = !item->check_target_idx && fail_tramp;
6736
6737                         if (item->has_target_code || !arm_is_imm12 (DISTANCE (vtable, &vtable->vtable[item->value.vtable_slot]))) {
6738                                 item->chunk_size += 32;
6739                                 large_offsets = TRUE;
6740                         }
6741
6742                         if (item->check_target_idx || fail_case) {
6743                                 if (!item->compare_done || fail_case)
6744                                         item->chunk_size += CMP_SIZE;
6745                                 item->chunk_size += BRANCH_SIZE;
6746                         } else {
6747 #ifdef ENABLE_WRONG_METHOD_CHECK
6748                                 item->chunk_size += WMC_SIZE;
6749 #endif
6750                         }
6751                         if (fail_case) {
6752                                 item->chunk_size += 16;
6753                                 large_offsets = TRUE;
6754                         }
6755                         item->chunk_size += CALL_SIZE;
6756                 } else {
6757                         item->chunk_size += BSEARCH_ENTRY_SIZE;
6758                         imt_entries [item->check_target_idx]->compare_done = TRUE;
6759                 }
6760                 size += item->chunk_size;
6761         }
6762
6763         if (large_offsets)
6764                 size += 4 * count; /* The ARM_ADD_REG_IMM to pop the stack */
6765 #endif
6766
6767         if (fail_tramp)
6768                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
6769         else
6770                 code = mono_domain_code_reserve (domain, size);
6771         start = code;
6772
6773 #ifdef DEBUG_IMT
6774         g_print ("Building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p fail_tramp %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable, fail_tramp);
6775         for (i = 0; i < count; ++i) {
6776                 MonoIMTCheckItem *item = imt_entries [i];
6777                 g_print ("method %d (%p) %s vtable slot %p is_equals %d chunk size %d\n", i, item->key, ((MonoMethod*)item->key)->name, &vtable->vtable [item->value.vtable_slot], item->is_equals, item->chunk_size);
6778         }
6779 #endif
6780
6781 #ifdef USE_JUMP_TABLES
6782         ARM_PUSH3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6783 #define VTABLE_JTI 0
6784 #define IMT_METHOD_OFFSET 0
6785 #define TARGET_CODE_OFFSET 1
6786 #define JUMP_CODE_OFFSET 2
6787 #define RECORDS_PER_ENTRY 3
6788 #define IMT_METHOD_JTI(idx) (1 + idx * RECORDS_PER_ENTRY + IMT_METHOD_OFFSET)
6789 #define TARGET_CODE_JTI(idx) (1 + idx * RECORDS_PER_ENTRY + TARGET_CODE_OFFSET)
6790 #define JUMP_CODE_JTI(idx) (1 + idx * RECORDS_PER_ENTRY + JUMP_CODE_OFFSET)
6791
6792         jte = mono_jumptable_add_entries (RECORDS_PER_ENTRY * count + 1 /* vtable */);
6793         code = (arminstr_t *) mono_arm_load_jumptable_entry_addr ((guint8 *) code, jte, ARMREG_R2);
6794         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, VTABLE_JTI);
6795         set_jumptable_element (jte, VTABLE_JTI, vtable);
6796 #else
6797         if (large_offsets)
6798                 ARM_PUSH4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
6799         else
6800                 ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
6801         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
6802         vtable_target = code;
6803         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
6804 #endif
6805         ARM_MOV_REG_REG (code, ARMREG_R0, ARMREG_V5);
6806
6807         for (i = 0; i < count; ++i) {
6808                 MonoIMTCheckItem *item = imt_entries [i];
6809 #ifdef USE_JUMP_TABLES
6810                 guint32 imt_method_jti = 0, target_code_jti = 0;
6811 #else
6812                 arminstr_t *imt_method = NULL, *vtable_offset_ins = NULL, *target_code_ins = NULL;
6813 #endif
6814                 gint32 vtable_offset;
6815
6816                 item->code_target = (guint8*)code;
6817
6818                 if (item->is_equals) {
6819                         gboolean fail_case = !item->check_target_idx && fail_tramp;
6820
6821                         if (item->check_target_idx || fail_case) {
6822                                 if (!item->compare_done || fail_case) {
6823 #ifdef USE_JUMP_TABLES
6824                                         imt_method_jti = IMT_METHOD_JTI (i);
6825                                         code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, imt_method_jti, ARMCOND_AL);
6826 #else
6827                                         imt_method = code;
6828                                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6829 #endif
6830                                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
6831                                 }
6832 #ifdef USE_JUMP_TABLES
6833                                 code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, JUMP_CODE_JTI (i), ARMCOND_NE);
6834                                 ARM_BX_COND (code, ARMCOND_NE, ARMREG_R1);
6835                                 item->jmp_code = GUINT_TO_POINTER (JUMP_CODE_JTI (i));
6836 #else
6837                                 item->jmp_code = (guint8*)code;
6838                                 ARM_B_COND (code, ARMCOND_NE, 0);
6839 #endif
6840                         } else {
6841                                 /*Enable the commented code to assert on wrong method*/
6842 #ifdef ENABLE_WRONG_METHOD_CHECK
6843 #ifdef USE_JUMP_TABLES
6844                                 imt_method_jti = IMT_METHOD_JTI (i);
6845                                 code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, imt_method_jti, ARMCOND_AL);
6846 #else
6847                                 imt_method = code;
6848                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6849 #endif
6850                                 ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
6851                                 cond = code;
6852                                 ARM_B_COND (code, ARMCOND_EQ, 0);
6853
6854 /* Define this if your system is so bad that gdb is failing. */
6855 #ifdef BROKEN_DEV_ENV
6856                                 ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
6857                                 ARM_BL (code, 0);
6858                                 arm_patch (code - 1, mini_dump_bad_imt);
6859 #else
6860                                 ARM_DBRK (code);
6861 #endif
6862                                 arm_patch (cond, code);
6863 #endif
6864                         }
6865
6866                         if (item->has_target_code) {
6867                                 /* Load target address */
6868 #ifdef USE_JUMP_TABLES
6869                                 target_code_jti = TARGET_CODE_JTI (i);
6870                                 code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, target_code_jti, ARMCOND_AL);
6871                                 /* Restore registers */
6872                                 ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6873                                 /*  And branch */
6874                                 ARM_BX (code, ARMREG_R1);
6875                                 set_jumptable_element (jte, target_code_jti, item->value.target_code);
6876 #else
6877                                 target_code_ins = code;
6878                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6879                                 /* Save it to the fourth slot */
6880                                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (gpointer));
6881                                 /* Restore registers and branch */
6882                                 ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
6883                                 
6884                                 code = arm_emit_value_and_patch_ldr (code, target_code_ins, (gsize)item->value.target_code);
6885 #endif
6886                         } else {
6887                                 vtable_offset = DISTANCE (vtable, &vtable->vtable[item->value.vtable_slot]);
6888                                 if (!arm_is_imm12 (vtable_offset)) {
6889                                         /* 
6890                                          * We need to branch to a computed address but we don't have
6891                                          * a free register to store it, since IP must contain the 
6892                                          * vtable address. So we push the two values to the stack, and
6893                                          * load them both using LDM.
6894                                          */
6895                                         /* Compute target address */
6896 #ifdef USE_JUMP_TABLES
6897                                         ARM_MOVW_REG_IMM (code, ARMREG_R1, vtable_offset & 0xffff);
6898                                         if (vtable_offset >> 16)
6899                                                 ARM_MOVT_REG_IMM (code, ARMREG_R1, (vtable_offset >> 16) & 0xffff);
6900                                         /* IP had vtable base. */
6901                                         ARM_LDR_REG_REG (code, ARMREG_IP, ARMREG_IP, ARMREG_R1);
6902                                         /* Restore registers and branch */
6903                                         ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6904                                         ARM_BX (code, ARMREG_IP);
6905 #else
6906                                         vtable_offset_ins = code;
6907                                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6908                                         ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_IP, ARMREG_R1);
6909                                         /* Save it to the fourth slot */
6910                                         ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (gpointer));
6911                                         /* Restore registers and branch */
6912                                         ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
6913                                 
6914                                         code = arm_emit_value_and_patch_ldr (code, vtable_offset_ins, vtable_offset);
6915 #endif
6916                                 } else {
6917 #ifdef USE_JUMP_TABLES
6918                                         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_IP, vtable_offset);
6919                                         ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6920                                         ARM_BX (code, ARMREG_IP);
6921 #else
6922                                         ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
6923                                         if (large_offsets)
6924                                                 ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 2 * sizeof (gpointer));
6925                                         ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, vtable_offset);
6926 #endif
6927                                 }
6928                         }
6929
6930                         if (fail_case) {
6931 #ifdef USE_JUMP_TABLES
6932                                 set_jumptable_element (jte, GPOINTER_TO_UINT (item->jmp_code), code);
6933                                 target_code_jti = TARGET_CODE_JTI (i);
6934                                 /* Load target address */
6935                                 code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, target_code_jti, ARMCOND_AL);
6936                                 /* Restore registers */
6937                                 ARM_POP3 (code, ARMREG_R0, ARMREG_R1, ARMREG_R2);
6938                                 /* And branch */
6939                                 ARM_BX (code, ARMREG_R1);
6940                                 set_jumptable_element (jte, target_code_jti, fail_tramp);
6941 #else
6942                                 arm_patch (item->jmp_code, (guchar*)code);
6943
6944                                 target_code_ins = code;
6945                                 /* Load target address */
6946                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6947                                 /* Save it to the fourth slot */
6948                                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (gpointer));
6949                                 /* Restore registers and branch */
6950                                 ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
6951                                 
6952                                 code = arm_emit_value_and_patch_ldr (code, target_code_ins, (gsize)fail_tramp);
6953 #endif
6954                                 item->jmp_code = NULL;
6955                         }
6956
6957 #ifdef USE_JUMP_TABLES
6958                         if (imt_method_jti)
6959                                 set_jumptable_element (jte, imt_method_jti, item->key);
6960 #else
6961                         if (imt_method)
6962                                 code = arm_emit_value_and_patch_ldr (code, imt_method, (guint32)item->key);
6963
6964                         /*must emit after unconditional branch*/
6965                         if (vtable_target) {
6966                                 code = arm_emit_value_and_patch_ldr (code, vtable_target, (guint32)vtable);
6967                                 item->chunk_size += 4;
6968                                 vtable_target = NULL;
6969                         }
6970
6971                         /*We reserve the space for bsearch IMT values after the first entry with an absolute jump*/
6972                         constant_pool_starts [i] = code;
6973                         if (extra_space) {
6974                                 code += extra_space;
6975                                 extra_space = 0;
6976                         }
6977 #endif
6978                 } else {
6979 #ifdef USE_JUMP_TABLES
6980                         code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, IMT_METHOD_JTI (i), ARMCOND_AL);
6981                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
6982                         code = load_element_with_regbase_cond (code, ARMREG_R1, ARMREG_R2, JUMP_CODE_JTI (i), ARMCOND_HS);
6983                         ARM_BX_COND (code, ARMCOND_HS, ARMREG_R1);
6984                         item->jmp_code = GUINT_TO_POINTER (JUMP_CODE_JTI (i));
6985 #else
6986                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
6987                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
6988
6989                         item->jmp_code = (guint8*)code;
6990                         ARM_B_COND (code, ARMCOND_HS, 0);
6991                         ++extra_space;
6992 #endif
6993                 }
6994         }
6995
6996         for (i = 0; i < count; ++i) {
6997                 MonoIMTCheckItem *item = imt_entries [i];
6998                 if (item->jmp_code) {
6999                         if (item->check_target_idx)
7000 #ifdef USE_JUMP_TABLES
7001                                 set_jumptable_element (jte, GPOINTER_TO_UINT (item->jmp_code), imt_entries [item->check_target_idx]->code_target);
7002 #else
7003                                 arm_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
7004 #endif
7005                 }
7006                 if (i > 0 && item->is_equals) {
7007                         int j;
7008 #ifdef USE_JUMP_TABLES
7009                         for (j = i - 1; j >= 0 && !imt_entries [j]->is_equals; --j)
7010                                 set_jumptable_element (jte, IMT_METHOD_JTI (j), imt_entries [j]->key);
7011 #else
7012                         arminstr_t *space_start = constant_pool_starts [i];
7013                         for (j = i - 1; j >= 0 && !imt_entries [j]->is_equals; --j) {
7014                                 space_start = arm_emit_value_and_patch_ldr (space_start, (arminstr_t*)imt_entries [j]->code_target, (guint32)imt_entries [j]->key);
7015                         }
7016 #endif
7017                 }
7018         }
7019
7020 #ifdef DEBUG_IMT
7021         {
7022                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
7023                 mono_disassemble_code (NULL, (guint8*)start, size, buff);
7024                 g_free (buff);
7025         }
7026 #endif
7027
7028 #ifndef USE_JUMP_TABLES
7029         g_free (constant_pool_starts);
7030 #endif
7031
7032         mono_arch_flush_icache ((guint8*)start, size);
7033         mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL);
7034         mono_stats.imt_thunks_size += code - start;
7035
7036         g_assert (DISTANCE (start, code) <= size);
7037         return start;
7038 }
7039
7040 mgreg_t
7041 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
7042 {
7043         return ctx->regs [reg];
7044 }
7045
7046 void
7047 mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
7048 {
7049         ctx->regs [reg] = val;
7050 }
7051
7052 /*
7053  * mono_arch_get_trampolines:
7054  *
7055  *   Return a list of MonoTrampInfo structures describing arch specific trampolines
7056  * for AOT.
7057  */
7058 GSList *
7059 mono_arch_get_trampolines (gboolean aot)
7060 {
7061         return mono_arm_get_exception_trampolines (aot);
7062 }
7063
7064 gpointer
7065 mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
7066 {
7067         gpointer *lr_loc;
7068         char *old_value;
7069         char *bp;
7070
7071         /*Load the spvar*/
7072         bp = MONO_CONTEXT_GET_BP (ctx);
7073         lr_loc = (gpointer*)(bp + clause->exvar_offset);
7074
7075         old_value = *lr_loc;
7076         if ((char*)old_value < (char*)ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
7077                 return old_value;
7078
7079         *lr_loc = new_value;
7080
7081         return old_value;
7082 }
7083
7084 #if defined(MONO_ARCH_SOFT_DEBUG_SUPPORTED)
7085 /*
7086  * mono_arch_set_breakpoint:
7087  *
7088  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
7089  * The location should contain code emitted by OP_SEQ_POINT.
7090  */
7091 void
7092 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
7093 {
7094         guint8 *code = ip;
7095         guint32 native_offset = ip - (guint8*)ji->code_start;
7096         MonoDebugOptions *opt = mini_get_debug_options ();
7097
7098         if (opt->soft_breakpoints) {
7099                 g_assert (!ji->from_aot);
7100                 code += 4;
7101                 ARM_BLX_REG (code, ARMREG_LR);
7102                 mono_arch_flush_icache (code - 4, 4);
7103         } else if (ji->from_aot) {
7104                 SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
7105
7106                 g_assert (native_offset % 4 == 0);
7107                 g_assert (info->bp_addrs [native_offset / 4] == 0);
7108                 info->bp_addrs [native_offset / 4] = bp_trigger_page;
7109         } else {
7110                 int dreg = ARMREG_LR;
7111
7112                 /* Read from another trigger page */
7113 #ifdef USE_JUMP_TABLES
7114                 gpointer *jte = mono_jumptable_add_entry ();
7115                 code = mono_arm_load_jumptable_entry (code, jte, dreg);
7116                 jte [0] = bp_trigger_page;
7117 #else
7118                 ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
7119                 ARM_B (code, 0);
7120                 *(int*)code = (int)bp_trigger_page;
7121                 code += 4;
7122 #endif
7123                 ARM_LDR_IMM (code, dreg, dreg, 0);
7124
7125                 mono_arch_flush_icache (code - 16, 16);
7126
7127 #if 0
7128                 /* This is currently implemented by emitting an SWI instruction, which 
7129                  * qemu/linux seems to convert to a SIGILL.
7130                  */
7131                 *(int*)code = (0xef << 24) | 8;
7132                 code += 4;
7133                 mono_arch_flush_icache (code - 4, 4);
7134 #endif
7135         }
7136 }
7137
7138 /*
7139  * mono_arch_clear_breakpoint:
7140  *
7141  *   Clear the breakpoint at IP.
7142  */
7143 void
7144 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
7145 {
7146         MonoDebugOptions *opt = mini_get_debug_options ();
7147         guint8 *code = ip;
7148         int i;
7149
7150         if (opt->soft_breakpoints) {
7151                 g_assert (!ji->from_aot);
7152                 code += 4;
7153                 ARM_NOP (code);
7154                 mono_arch_flush_icache (code - 4, 4);
7155         } else if (ji->from_aot) {
7156                 guint32 native_offset = ip - (guint8*)ji->code_start;
7157                 SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
7158
7159                 g_assert (native_offset % 4 == 0);
7160                 g_assert (info->bp_addrs [native_offset / 4] == bp_trigger_page);
7161                 info->bp_addrs [native_offset / 4] = 0;
7162         } else {
7163                 for (i = 0; i < 4; ++i)
7164                         ARM_NOP (code);
7165
7166                 mono_arch_flush_icache (ip, code - ip);
7167         }
7168 }
7169         
7170 /*
7171  * mono_arch_start_single_stepping:
7172  *
7173  *   Start single stepping.
7174  */
7175 void
7176 mono_arch_start_single_stepping (void)
7177 {
7178         if (ss_trigger_page)
7179                 mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
7180         else
7181                 ss_trigger_var = 1;
7182 }
7183         
7184 /*
7185  * mono_arch_stop_single_stepping:
7186  *
7187  *   Stop single stepping.
7188  */
7189 void
7190 mono_arch_stop_single_stepping (void)
7191 {
7192         if (ss_trigger_page)
7193                 mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
7194         else
7195                 ss_trigger_var = 0;
7196 }
7197
7198 #if __APPLE__
7199 #define DBG_SIGNAL SIGBUS
7200 #else
7201 #define DBG_SIGNAL SIGSEGV
7202 #endif
7203
7204 /*
7205  * mono_arch_is_single_step_event:
7206  *
7207  *   Return whenever the machine state in SIGCTX corresponds to a single
7208  * step event.
7209  */
7210 gboolean
7211 mono_arch_is_single_step_event (void *info, void *sigctx)
7212 {
7213         siginfo_t *sinfo = info;
7214
7215         if (!ss_trigger_page)
7216                 return FALSE;
7217
7218         /* Sometimes the address is off by 4 */
7219         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
7220                 return TRUE;
7221         else
7222                 return FALSE;
7223 }
7224
7225 /*
7226  * mono_arch_is_breakpoint_event:
7227  *
7228  *   Return whenever the machine state in SIGCTX corresponds to a breakpoint event.
7229  */
7230 gboolean
7231 mono_arch_is_breakpoint_event (void *info, void *sigctx)
7232 {
7233         siginfo_t *sinfo = info;
7234
7235         if (!ss_trigger_page)
7236                 return FALSE;
7237
7238         if (sinfo->si_signo == DBG_SIGNAL) {
7239                 /* Sometimes the address is off by 4 */
7240                 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
7241                         return TRUE;
7242                 else
7243                         return FALSE;
7244         } else {
7245                 return FALSE;
7246         }
7247 }
7248
7249 /*
7250  * mono_arch_skip_breakpoint:
7251  *
7252  *   See mini-amd64.c for docs.
7253  */
7254 void
7255 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
7256 {
7257         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
7258 }
7259
7260 /*
7261  * mono_arch_skip_single_step:
7262  *
7263  *   See mini-amd64.c for docs.
7264  */
7265 void
7266 mono_arch_skip_single_step (MonoContext *ctx)
7267 {
7268         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
7269 }
7270
7271 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
7272
7273 /*
7274  * mono_arch_get_seq_point_info:
7275  *
7276  *   See mini-amd64.c for docs.
7277  */
7278 gpointer
7279 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
7280 {
7281         SeqPointInfo *info;
7282         MonoJitInfo *ji;
7283
7284         // FIXME: Add a free function
7285
7286         mono_domain_lock (domain);
7287         info = g_hash_table_lookup (domain_jit_info (domain)->arch_seq_points, 
7288                                                                 code);
7289         mono_domain_unlock (domain);
7290
7291         if (!info) {
7292                 ji = mono_jit_info_table_find (domain, (char*)code);
7293                 g_assert (ji);
7294
7295                 info = g_malloc0 (sizeof (SeqPointInfo) + ji->code_size);
7296
7297                 info->ss_trigger_page = ss_trigger_page;
7298                 info->bp_trigger_page = bp_trigger_page;
7299
7300                 mono_domain_lock (domain);
7301                 g_hash_table_insert (domain_jit_info (domain)->arch_seq_points,
7302                                                          code, info);
7303                 mono_domain_unlock (domain);
7304         }
7305
7306         return info;
7307 }
7308
7309 void
7310 mono_arch_init_lmf_ext (MonoLMFExt *ext, gpointer prev_lmf)
7311 {
7312         ext->lmf.previous_lmf = prev_lmf;
7313         /* Mark that this is a MonoLMFExt */
7314         ext->lmf.previous_lmf = (gpointer)(((gssize)ext->lmf.previous_lmf) | 2);
7315         ext->lmf.sp = (gssize)ext;
7316 }
7317
7318 /*
7319  * mono_arch_set_target:
7320  *
7321  *   Set the target architecture the JIT backend should generate code for, in the form
7322  * of a GNU target triplet. Only used in AOT mode.
7323  */
7324 void
7325 mono_arch_set_target (char *mtriple)
7326 {
7327         /* The GNU target triple format is not very well documented */
7328         if (strstr (mtriple, "armv7")) {
7329                 v5_supported = TRUE;
7330                 v6_supported = TRUE;
7331                 v7_supported = TRUE;
7332         }
7333         if (strstr (mtriple, "armv6")) {
7334                 v5_supported = TRUE;
7335                 v6_supported = TRUE;
7336         }
7337         if (strstr (mtriple, "armv7s")) {
7338                 v7s_supported = TRUE;
7339         }
7340         if (strstr (mtriple, "thumbv7s")) {
7341                 v5_supported = TRUE;
7342                 v6_supported = TRUE;
7343                 v7_supported = TRUE;
7344                 v7s_supported = TRUE;
7345                 thumb_supported = TRUE;
7346                 thumb2_supported = TRUE;
7347         }
7348         if (strstr (mtriple, "darwin") || strstr (mtriple, "ios")) {
7349                 v5_supported = TRUE;
7350                 v6_supported = TRUE;
7351                 thumb_supported = TRUE;
7352                 iphone_abi = TRUE;
7353         }
7354         if (strstr (mtriple, "gnueabi"))
7355                 eabi_supported = TRUE;
7356 }
7357
7358 gboolean
7359 mono_arch_opcode_supported (int opcode)
7360 {
7361         switch (opcode) {
7362         case OP_ATOMIC_ADD_I4:
7363         case OP_ATOMIC_EXCHANGE_I4:
7364         case OP_ATOMIC_CAS_I4:
7365         case OP_ATOMIC_LOAD_I1:
7366         case OP_ATOMIC_LOAD_I2:
7367         case OP_ATOMIC_LOAD_I4:
7368         case OP_ATOMIC_LOAD_U1:
7369         case OP_ATOMIC_LOAD_U2:
7370         case OP_ATOMIC_LOAD_U4:
7371         case OP_ATOMIC_STORE_I1:
7372         case OP_ATOMIC_STORE_I2:
7373         case OP_ATOMIC_STORE_I4:
7374         case OP_ATOMIC_STORE_U1:
7375         case OP_ATOMIC_STORE_U2:
7376         case OP_ATOMIC_STORE_U4:
7377                 return v7_supported;
7378         case OP_ATOMIC_LOAD_R4:
7379         case OP_ATOMIC_LOAD_R8:
7380         case OP_ATOMIC_STORE_R4:
7381         case OP_ATOMIC_STORE_R8:
7382                 return v7_supported && IS_VFP;
7383         default:
7384                 return FALSE;
7385         }
7386 }
7387
7388 #if defined(ENABLE_GSHAREDVT)
7389
7390 #include "../../../mono-extensions/mono/mini/mini-arm-gsharedvt.c"
7391
7392 #endif /* !MONOTOUCH */