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