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