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