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