1 /**
2  * \file
3  * ARM64 backend for the Mono code generator
4  *
5  * Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
6  *
7  * Based on mini-arm.c:
8  *
9  * Authors:
10  *   Paolo Molaro (lupus@ximian.com)
11  *   Dietmar Maurer (dietmar@ximian.com)
12  *
13  * (C) 2003 Ximian, Inc.
14  * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
15  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
16  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
17  */
18 
19 #include "mini.h"
20 #include "cpu-arm64.h"
21 #include "ir-emit.h"
22 #include "aot-runtime.h"
23 #include "mini-runtime.h"
24 
25 #include <mono/arch/arm64/arm64-codegen.h>
26 #include <mono/utils/mono-mmap.h>
27 #include <mono/utils/mono-memory-model.h>
28 #include <mono/metadata/abi-details.h>
29 
30 /*
31  * Documentation:
32  *
33  * - ARM(R) Architecture Reference Manual, ARMv8, for ARMv8-A architecture profile (DDI0487A_a_armv8_arm.pdf)
34  * - Procedure Call Standard for the ARM 64-bit Architecture (AArch64) (IHI0055B_aapcs64.pdf)
35  * - ELF for the ARM 64-bit Architecture (IHI0056B_aaelf64.pdf)
36  *
37  * Register usage:
38  * - ip0/ip1/lr are used as temporary registers
39  * - r27 is used as the rgctx/imt register
40  * - r28 is used to access arguments passed on the stack
41  * - d15/d16 are used as fp temporary registers
42  */
43 
44 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
45 
46 #define FP_TEMP_REG ARMREG_D16
47 #define FP_TEMP_REG2 ARMREG_D17
48 
49 #define THUNK_SIZE (4 * 4)
50 
51 /* The single step trampoline */
52 static gpointer ss_trampoline;
53 
54 /* The breakpoint trampoline */
55 static gpointer bp_trampoline;
56 
57 static gboolean ios_abi;
58 
59 static __attribute__ ((__warn_unused_result__)) guint8* emit_load_regset (guint8 *code, guint64 regs, int basereg, int offset);
60 
61 const char*
mono_arch_regname(int reg)62 mono_arch_regname (int reg)
63 {
64 	static const char * rnames[] = {
65 		"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
66 		"r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
67 		"r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "fp",
68 		"lr", "sp"
69 	};
70 	if (reg >= 0 && reg < 32)
71 		return rnames [reg];
72 	return "unknown";
73 }
74 
75 const char*
mono_arch_fregname(int reg)76 mono_arch_fregname (int reg)
77 {
78 	static const char * rnames[] = {
79 		"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9",
80 		"d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19",
81 		"d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29",
82 		"d30", "d31"
83 	};
84 	if (reg >= 0 && reg < 32)
85 		return rnames [reg];
86 	return "unknown fp";
87 }
88 
89 int
mono_arch_get_argument_info(MonoMethodSignature * csig,int param_count,MonoJitArgumentInfo * arg_info)90 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
91 {
92 	NOT_IMPLEMENTED;
93 	return 0;
94 }
95 
96 #define MAX_ARCH_DELEGATE_PARAMS 7
97 
98 static gpointer
get_delegate_invoke_impl(gboolean has_target,gboolean param_count,guint32 * code_size)99 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
100 {
101 	guint8 *code, *start;
102 
103 	if (has_target) {
104 		start = code = mono_global_codeman_reserve (12);
105 
106 		/* Replace the this argument with the target */
107 		arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
108 		arm_ldrx (code, ARMREG_R0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, target));
109 		arm_brx (code, ARMREG_IP0);
110 
111 		g_assert ((code - start) <= 12);
112 
113 		mono_arch_flush_icache (start, 12);
114 	} else {
115 		int size, i;
116 
117 		size = 8 + param_count * 4;
118 		start = code = mono_global_codeman_reserve (size);
119 
120 		arm_ldrx (code, ARMREG_IP0, ARMREG_R0, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
121 		/* slide down the arguments */
122 		for (i = 0; i < param_count; ++i)
123 			arm_movx (code, i, i + 1);
124 		arm_brx (code, ARMREG_IP0);
125 
126 		g_assert ((code - start) <= size);
127 
128 		mono_arch_flush_icache (start, size);
129 	}
130 
131 	if (code_size)
132 		*code_size = code - start;
133 
134 	return start;
135 }
136 
137 /*
138  * mono_arch_get_delegate_invoke_impls:
139  *
140  *   Return a list of MonoAotTrampInfo structures for the delegate invoke impl
141  * trampolines.
142  */
143 GSList*
mono_arch_get_delegate_invoke_impls(void)144 mono_arch_get_delegate_invoke_impls (void)
145 {
146 	GSList *res = NULL;
147 	guint8 *code;
148 	guint32 code_len;
149 	int i;
150 	char *tramp_name;
151 
152 	code = get_delegate_invoke_impl (TRUE, 0, &code_len);
153 	res = g_slist_prepend (res, mono_tramp_info_create ("delegate_invoke_impl_has_target", code, code_len, NULL, NULL));
154 
155 	for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
156 		code = get_delegate_invoke_impl (FALSE, i, &code_len);
157 		tramp_name = g_strdup_printf ("delegate_invoke_impl_target_%d", i);
158 		res = g_slist_prepend (res, mono_tramp_info_create (tramp_name, code, code_len, NULL, NULL));
159 		g_free (tramp_name);
160 	}
161 
162 	return res;
163 }
164 
165 gpointer
mono_arch_get_delegate_invoke_impl(MonoMethodSignature * sig,gboolean has_target)166 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
167 {
168 	guint8 *code, *start;
169 
170 	/*
171 	 * vtypes are returned in registers, or using the dedicated r8 register, so
172 	 * they can be supported by delegate invokes.
173 	 */
174 
175 	if (has_target) {
176 		static guint8* cached = NULL;
177 
178 		if (cached)
179 			return cached;
180 
181 		if (mono_aot_only)
182 			start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
183 		else
184 			start = get_delegate_invoke_impl (TRUE, 0, NULL);
185 		mono_memory_barrier ();
186 		cached = start;
187 		return cached;
188 	} else {
189 		static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
190 		int i;
191 
192 		if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
193 			return NULL;
194 		for (i = 0; i < sig->param_count; ++i)
195 			if (!mono_is_regsize_var (sig->params [i]))
196 				return NULL;
197 
198 		code = cache [sig->param_count];
199 		if (code)
200 			return code;
201 
202 		if (mono_aot_only) {
203 			char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
204 			start = mono_aot_get_trampoline (name);
205 			g_free (name);
206 		} else {
207 			start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
208 		}
209 		mono_memory_barrier ();
210 		cache [sig->param_count] = start;
211 		return start;
212 	}
213 
214 	return NULL;
215 }
216 
217 gpointer
mono_arch_get_delegate_virtual_invoke_impl(MonoMethodSignature * sig,MonoMethod * method,int offset,gboolean load_imt_reg)218 mono_arch_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method, int offset, gboolean load_imt_reg)
219 {
220 	return NULL;
221 }
222 
223 gpointer
mono_arch_get_this_arg_from_call(mgreg_t * regs,guint8 * code)224 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
225 {
226 	return (gpointer)regs [ARMREG_R0];
227 }
228 
229 void
mono_arch_cpu_init(void)230 mono_arch_cpu_init (void)
231 {
232 }
233 
234 void
mono_arch_init(void)235 mono_arch_init (void)
236 {
237 	mono_aot_register_jit_icall ("mono_arm_throw_exception", mono_arm_throw_exception);
238 	mono_aot_register_jit_icall ("mono_arm_resume_unwind", mono_arm_resume_unwind);
239 
240 	if (!mono_aot_only)
241 		bp_trampoline = mini_get_breakpoint_trampoline ();
242 
243 	mono_arm_gsharedvt_init ();
244 
245 #if defined(TARGET_IOS)
246 	ios_abi = TRUE;
247 #endif
248 }
249 
250 void
mono_arch_cleanup(void)251 mono_arch_cleanup (void)
252 {
253 }
254 
255 guint32
mono_arch_cpu_optimizations(guint32 * exclude_mask)256 mono_arch_cpu_optimizations (guint32 *exclude_mask)
257 {
258 	*exclude_mask = 0;
259 	return 0;
260 }
261 
262 guint32
mono_arch_cpu_enumerate_simd_versions(void)263 mono_arch_cpu_enumerate_simd_versions (void)
264 {
265 	return 0;
266 }
267 
268 void
mono_arch_register_lowlevel_calls(void)269 mono_arch_register_lowlevel_calls (void)
270 {
271 }
272 
273 void
mono_arch_finish_init(void)274 mono_arch_finish_init (void)
275 {
276 }
277 
278 /* The maximum length is 2 instructions */
279 static guint8*
emit_imm(guint8 * code,int dreg,int imm)280 emit_imm (guint8 *code, int dreg, int imm)
281 {
282 	// FIXME: Optimize this
283 	if (imm < 0) {
284 		gint64 limm = imm;
285 		arm_movnx (code, dreg, (~limm) & 0xffff, 0);
286 		arm_movkx (code, dreg, (limm >> 16) & 0xffff, 16);
287 	} else {
288 		arm_movzx (code, dreg, imm & 0xffff, 0);
289 		if (imm >> 16)
290 			arm_movkx (code, dreg, (imm >> 16) & 0xffff, 16);
291 	}
292 
293 	return code;
294 }
295 
296 /* The maximum length is 4 instructions */
297 static guint8*
emit_imm64(guint8 * code,int dreg,guint64 imm)298 emit_imm64 (guint8 *code, int dreg, guint64 imm)
299 {
300 	// FIXME: Optimize this
301 	arm_movzx (code, dreg, imm & 0xffff, 0);
302 	if ((imm >> 16) & 0xffff)
303 		arm_movkx (code, dreg, (imm >> 16) & 0xffff, 16);
304 	if ((imm >> 32) & 0xffff)
305 		arm_movkx (code, dreg, (imm >> 32) & 0xffff, 32);
306 	if ((imm >> 48) & 0xffff)
307 		arm_movkx (code, dreg, (imm >> 48) & 0xffff, 48);
308 
309 	return code;
310 }
311 
312 guint8*
mono_arm_emit_imm64(guint8 * code,int dreg,gint64 imm)313 mono_arm_emit_imm64 (guint8 *code, int dreg, gint64 imm)
314 {
315 	return emit_imm64 (code, dreg, imm);
316 }
317 
318 /*
319  * emit_imm_template:
320  *
321  *   Emit a patchable code sequence for constructing a 64 bit immediate.
322  */
323 static guint8*
emit_imm64_template(guint8 * code,int dreg)324 emit_imm64_template (guint8 *code, int dreg)
325 {
326 	arm_movzx (code, dreg, 0, 0);
327 	arm_movkx (code, dreg, 0, 16);
328 	arm_movkx (code, dreg, 0, 32);
329 	arm_movkx (code, dreg, 0, 48);
330 
331 	return code;
332 }
333 
334 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_addw_imm(guint8 * code,int dreg,int sreg,int imm)335 emit_addw_imm (guint8 *code, int dreg, int sreg, int imm)
336 {
337 	if (!arm_is_arith_imm (imm)) {
338 		code = emit_imm (code, ARMREG_LR, imm);
339 		arm_addw (code, dreg, sreg, ARMREG_LR);
340 	} else {
341 		arm_addw_imm (code, dreg, sreg, imm);
342 	}
343 	return code;
344 }
345 
346 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_addx_imm(guint8 * code,int dreg,int sreg,int imm)347 emit_addx_imm (guint8 *code, int dreg, int sreg, int imm)
348 {
349 	if (!arm_is_arith_imm (imm)) {
350 		code = emit_imm (code, ARMREG_LR, imm);
351 		arm_addx (code, dreg, sreg, ARMREG_LR);
352 	} else {
353 		arm_addx_imm (code, dreg, sreg, imm);
354 	}
355 	return code;
356 }
357 
358 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_subw_imm(guint8 * code,int dreg,int sreg,int imm)359 emit_subw_imm (guint8 *code, int dreg, int sreg, int imm)
360 {
361 	if (!arm_is_arith_imm (imm)) {
362 		code = emit_imm (code, ARMREG_LR, imm);
363 		arm_subw (code, dreg, sreg, ARMREG_LR);
364 	} else {
365 		arm_subw_imm (code, dreg, sreg, imm);
366 	}
367 	return code;
368 }
369 
370 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_subx_imm(guint8 * code,int dreg,int sreg,int imm)371 emit_subx_imm (guint8 *code, int dreg, int sreg, int imm)
372 {
373 	if (!arm_is_arith_imm (imm)) {
374 		code = emit_imm (code, ARMREG_LR, imm);
375 		arm_subx (code, dreg, sreg, ARMREG_LR);
376 	} else {
377 		arm_subx_imm (code, dreg, sreg, imm);
378 	}
379 	return code;
380 }
381 
382 /* Emit sp+=imm. Clobbers ip0/ip1 */
383 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_addx_sp_imm(guint8 * code,int imm)384 emit_addx_sp_imm (guint8 *code, int imm)
385 {
386 	code = emit_imm (code, ARMREG_IP0, imm);
387 	arm_movspx (code, ARMREG_IP1, ARMREG_SP);
388 	arm_addx (code, ARMREG_IP1, ARMREG_IP1, ARMREG_IP0);
389 	arm_movspx (code, ARMREG_SP, ARMREG_IP1);
390 	return code;
391 }
392 
393 /* Emit sp-=imm. Clobbers ip0/ip1 */
394 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_subx_sp_imm(guint8 * code,int imm)395 emit_subx_sp_imm (guint8 *code, int imm)
396 {
397 	code = emit_imm (code, ARMREG_IP0, imm);
398 	arm_movspx (code, ARMREG_IP1, ARMREG_SP);
399 	arm_subx (code, ARMREG_IP1, ARMREG_IP1, ARMREG_IP0);
400 	arm_movspx (code, ARMREG_SP, ARMREG_IP1);
401 	return code;
402 }
403 
404 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_andw_imm(guint8 * code,int dreg,int sreg,int imm)405 emit_andw_imm (guint8 *code, int dreg, int sreg, int imm)
406 {
407 	// FIXME:
408 	code = emit_imm (code, ARMREG_LR, imm);
409 	arm_andw (code, dreg, sreg, ARMREG_LR);
410 
411 	return code;
412 }
413 
414 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_andx_imm(guint8 * code,int dreg,int sreg,int imm)415 emit_andx_imm (guint8 *code, int dreg, int sreg, int imm)
416 {
417 	// FIXME:
418 	code = emit_imm (code, ARMREG_LR, imm);
419 	arm_andx (code, dreg, sreg, ARMREG_LR);
420 
421 	return code;
422 }
423 
424 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_orrw_imm(guint8 * code,int dreg,int sreg,int imm)425 emit_orrw_imm (guint8 *code, int dreg, int sreg, int imm)
426 {
427 	// FIXME:
428 	code = emit_imm (code, ARMREG_LR, imm);
429 	arm_orrw (code, dreg, sreg, ARMREG_LR);
430 
431 	return code;
432 }
433 
434 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_orrx_imm(guint8 * code,int dreg,int sreg,int imm)435 emit_orrx_imm (guint8 *code, int dreg, int sreg, int imm)
436 {
437 	// FIXME:
438 	code = emit_imm (code, ARMREG_LR, imm);
439 	arm_orrx (code, dreg, sreg, ARMREG_LR);
440 
441 	return code;
442 }
443 
444 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_eorw_imm(guint8 * code,int dreg,int sreg,int imm)445 emit_eorw_imm (guint8 *code, int dreg, int sreg, int imm)
446 {
447 	// FIXME:
448 	code = emit_imm (code, ARMREG_LR, imm);
449 	arm_eorw (code, dreg, sreg, ARMREG_LR);
450 
451 	return code;
452 }
453 
454 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_eorx_imm(guint8 * code,int dreg,int sreg,int imm)455 emit_eorx_imm (guint8 *code, int dreg, int sreg, int imm)
456 {
457 	// FIXME:
458 	code = emit_imm (code, ARMREG_LR, imm);
459 	arm_eorx (code, dreg, sreg, ARMREG_LR);
460 
461 	return code;
462 }
463 
464 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_cmpw_imm(guint8 * code,int sreg,int imm)465 emit_cmpw_imm (guint8 *code, int sreg, int imm)
466 {
467 	if (imm == 0) {
468 		arm_cmpw (code, sreg, ARMREG_RZR);
469 	} else {
470 		// FIXME:
471 		code = emit_imm (code, ARMREG_LR, imm);
472 		arm_cmpw (code, sreg, ARMREG_LR);
473 	}
474 
475 	return code;
476 }
477 
478 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_cmpx_imm(guint8 * code,int sreg,int imm)479 emit_cmpx_imm (guint8 *code, int sreg, int imm)
480 {
481 	if (imm == 0) {
482 		arm_cmpx (code, sreg, ARMREG_RZR);
483 	} else {
484 		// FIXME:
485 		code = emit_imm (code, ARMREG_LR, imm);
486 		arm_cmpx (code, sreg, ARMREG_LR);
487 	}
488 
489 	return code;
490 }
491 
492 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_strb(guint8 * code,int rt,int rn,int imm)493 emit_strb (guint8 *code, int rt, int rn, int imm)
494 {
495 	if (arm_is_strb_imm (imm)) {
496 		arm_strb (code, rt, rn, imm);
497 	} else {
498 		g_assert (rt != ARMREG_IP0);
499 		g_assert (rn != ARMREG_IP0);
500 		code = emit_imm (code, ARMREG_IP0, imm);
501 		arm_strb_reg (code, rt, rn, ARMREG_IP0);
502 	}
503 	return code;
504 }
505 
506 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_strh(guint8 * code,int rt,int rn,int imm)507 emit_strh (guint8 *code, int rt, int rn, int imm)
508 {
509 	if (arm_is_strh_imm (imm)) {
510 		arm_strh (code, rt, rn, imm);
511 	} else {
512 		g_assert (rt != ARMREG_IP0);
513 		g_assert (rn != ARMREG_IP0);
514 		code = emit_imm (code, ARMREG_IP0, imm);
515 		arm_strh_reg (code, rt, rn, ARMREG_IP0);
516 	}
517 	return code;
518 }
519 
520 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_strw(guint8 * code,int rt,int rn,int imm)521 emit_strw (guint8 *code, int rt, int rn, int imm)
522 {
523 	if (arm_is_strw_imm (imm)) {
524 		arm_strw (code, rt, rn, imm);
525 	} else {
526 		g_assert (rt != ARMREG_IP0);
527 		g_assert (rn != ARMREG_IP0);
528 		code = emit_imm (code, ARMREG_IP0, imm);
529 		arm_strw_reg (code, rt, rn, ARMREG_IP0);
530 	}
531 	return code;
532 }
533 
534 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_strfpw(guint8 * code,int rt,int rn,int imm)535 emit_strfpw (guint8 *code, int rt, int rn, int imm)
536 {
537 	if (arm_is_strw_imm (imm)) {
538 		arm_strfpw (code, rt, rn, imm);
539 	} else {
540 		g_assert (rn != ARMREG_IP0);
541 		code = emit_imm (code, ARMREG_IP0, imm);
542 		arm_addx (code, ARMREG_IP0, rn, ARMREG_IP0);
543 		arm_strfpw (code, rt, ARMREG_IP0, 0);
544 	}
545 	return code;
546 }
547 
548 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_strfpx(guint8 * code,int rt,int rn,int imm)549 emit_strfpx (guint8 *code, int rt, int rn, int imm)
550 {
551 	if (arm_is_strx_imm (imm)) {
552 		arm_strfpx (code, rt, rn, imm);
553 	} else {
554 		g_assert (rn != ARMREG_IP0);
555 		code = emit_imm (code, ARMREG_IP0, imm);
556 		arm_addx (code, ARMREG_IP0, rn, ARMREG_IP0);
557 		arm_strfpx (code, rt, ARMREG_IP0, 0);
558 	}
559 	return code;
560 }
561 
562 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_strx(guint8 * code,int rt,int rn,int imm)563 emit_strx (guint8 *code, int rt, int rn, int imm)
564 {
565 	if (arm_is_strx_imm (imm)) {
566 		arm_strx (code, rt, rn, imm);
567 	} else {
568 		g_assert (rt != ARMREG_IP0);
569 		g_assert (rn != ARMREG_IP0);
570 		code = emit_imm (code, ARMREG_IP0, imm);
571 		arm_strx_reg (code, rt, rn, ARMREG_IP0);
572 	}
573 	return code;
574 }
575 
576 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrb(guint8 * code,int rt,int rn,int imm)577 emit_ldrb (guint8 *code, int rt, int rn, int imm)
578 {
579 	if (arm_is_pimm12_scaled (imm, 1)) {
580 		arm_ldrb (code, rt, rn, imm);
581 	} else {
582 		g_assert (rt != ARMREG_IP0);
583 		g_assert (rn != ARMREG_IP0);
584 		code = emit_imm (code, ARMREG_IP0, imm);
585 		arm_ldrb_reg (code, rt, rn, ARMREG_IP0);
586 	}
587 	return code;
588 }
589 
590 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrsbx(guint8 * code,int rt,int rn,int imm)591 emit_ldrsbx (guint8 *code, int rt, int rn, int imm)
592 {
593 	if (arm_is_pimm12_scaled (imm, 1)) {
594 		arm_ldrsbx (code, rt, rn, imm);
595 	} else {
596 		g_assert (rt != ARMREG_IP0);
597 		g_assert (rn != ARMREG_IP0);
598 		code = emit_imm (code, ARMREG_IP0, imm);
599 		arm_ldrsbx_reg (code, rt, rn, ARMREG_IP0);
600 	}
601 	return code;
602 }
603 
604 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrh(guint8 * code,int rt,int rn,int imm)605 emit_ldrh (guint8 *code, int rt, int rn, int imm)
606 {
607 	if (arm_is_pimm12_scaled (imm, 2)) {
608 		arm_ldrh (code, rt, rn, imm);
609 	} else {
610 		g_assert (rt != ARMREG_IP0);
611 		g_assert (rn != ARMREG_IP0);
612 		code = emit_imm (code, ARMREG_IP0, imm);
613 		arm_ldrh_reg (code, rt, rn, ARMREG_IP0);
614 	}
615 	return code;
616 }
617 
618 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrshx(guint8 * code,int rt,int rn,int imm)619 emit_ldrshx (guint8 *code, int rt, int rn, int imm)
620 {
621 	if (arm_is_pimm12_scaled (imm, 2)) {
622 		arm_ldrshx (code, rt, rn, imm);
623 	} else {
624 		g_assert (rt != ARMREG_IP0);
625 		g_assert (rn != ARMREG_IP0);
626 		code = emit_imm (code, ARMREG_IP0, imm);
627 		arm_ldrshx_reg (code, rt, rn, ARMREG_IP0);
628 	}
629 	return code;
630 }
631 
632 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrswx(guint8 * code,int rt,int rn,int imm)633 emit_ldrswx (guint8 *code, int rt, int rn, int imm)
634 {
635 	if (arm_is_pimm12_scaled (imm, 4)) {
636 		arm_ldrswx (code, rt, rn, imm);
637 	} else {
638 		g_assert (rt != ARMREG_IP0);
639 		g_assert (rn != ARMREG_IP0);
640 		code = emit_imm (code, ARMREG_IP0, imm);
641 		arm_ldrswx_reg (code, rt, rn, ARMREG_IP0);
642 	}
643 	return code;
644 }
645 
646 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrw(guint8 * code,int rt,int rn,int imm)647 emit_ldrw (guint8 *code, int rt, int rn, int imm)
648 {
649 	if (arm_is_pimm12_scaled (imm, 4)) {
650 		arm_ldrw (code, rt, rn, imm);
651 	} else {
652 		g_assert (rn != ARMREG_IP0);
653 		code = emit_imm (code, ARMREG_IP0, imm);
654 		arm_ldrw_reg (code, rt, rn, ARMREG_IP0);
655 	}
656 	return code;
657 }
658 
659 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrx(guint8 * code,int rt,int rn,int imm)660 emit_ldrx (guint8 *code, int rt, int rn, int imm)
661 {
662 	if (arm_is_pimm12_scaled (imm, 8)) {
663 		arm_ldrx (code, rt, rn, imm);
664 	} else {
665 		g_assert (rn != ARMREG_IP0);
666 		code = emit_imm (code, ARMREG_IP0, imm);
667 		arm_ldrx_reg (code, rt, rn, ARMREG_IP0);
668 	}
669 	return code;
670 }
671 
672 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrfpw(guint8 * code,int rt,int rn,int imm)673 emit_ldrfpw (guint8 *code, int rt, int rn, int imm)
674 {
675 	if (arm_is_pimm12_scaled (imm, 4)) {
676 		arm_ldrfpw (code, rt, rn, imm);
677 	} else {
678 		g_assert (rn != ARMREG_IP0);
679 		code = emit_imm (code, ARMREG_IP0, imm);
680 		arm_addx (code, ARMREG_IP0, rn, ARMREG_IP0);
681 		arm_ldrfpw (code, rt, ARMREG_IP0, 0);
682 	}
683 	return code;
684 }
685 
686 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_ldrfpx(guint8 * code,int rt,int rn,int imm)687 emit_ldrfpx (guint8 *code, int rt, int rn, int imm)
688 {
689 	if (arm_is_pimm12_scaled (imm, 8)) {
690 		arm_ldrfpx (code, rt, rn, imm);
691 	} else {
692 		g_assert (rn != ARMREG_IP0);
693 		code = emit_imm (code, ARMREG_IP0, imm);
694 		arm_addx (code, ARMREG_IP0, rn, ARMREG_IP0);
695 		arm_ldrfpx (code, rt, ARMREG_IP0, 0);
696 	}
697 	return code;
698 }
699 
700 guint8*
mono_arm_emit_ldrx(guint8 * code,int rt,int rn,int imm)701 mono_arm_emit_ldrx (guint8 *code, int rt, int rn, int imm)
702 {
703 	return emit_ldrx (code, rt, rn, imm);
704 }
705 
706 static guint8*
emit_call(MonoCompile * cfg,guint8 * code,guint32 patch_type,gconstpointer data)707 emit_call (MonoCompile *cfg, guint8* code, guint32 patch_type, gconstpointer data)
708 {
709 	/*
710 	mono_add_patch_info_rel (cfg, code - cfg->native_code, patch_type, data, MONO_R_ARM64_IMM);
711 	code = emit_imm64_template (code, ARMREG_LR);
712 	arm_blrx (code, ARMREG_LR);
713 	*/
714 	mono_add_patch_info_rel (cfg, code - cfg->native_code, patch_type, data, MONO_R_ARM64_BL);
715 	arm_bl (code, code);
716 	cfg->thunk_area += THUNK_SIZE;
717 	return code;
718 }
719 
720 static guint8*
emit_aotconst_full(MonoCompile * cfg,MonoJumpInfo ** ji,guint8 * code,guint8 * start,int dreg,guint32 patch_type,gconstpointer data)721 emit_aotconst_full (MonoCompile *cfg, MonoJumpInfo **ji, guint8 *code, guint8 *start, int dreg, guint32 patch_type, gconstpointer data)
722 {
723 	if (cfg)
724 		mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
725 	else
726 		*ji = mono_patch_info_list_prepend (*ji, code - start, patch_type, data);
727 	/* See arch_emit_got_access () in aot-compiler.c */
728 	arm_ldrx_lit (code, dreg, 0);
729 	arm_nop (code);
730 	arm_nop (code);
731 	return code;
732 }
733 
734 static guint8*
emit_aotconst(MonoCompile * cfg,guint8 * code,int dreg,guint32 patch_type,gconstpointer data)735 emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, guint32 patch_type, gconstpointer data)
736 {
737 	return emit_aotconst_full (cfg, NULL, code, NULL, dreg, patch_type, data);
738 }
739 
740 /*
741  * mono_arm_emit_aotconst:
742  *
743  *   Emit code to load an AOT constant into DREG. Usable from trampolines.
744  */
745 guint8*
mono_arm_emit_aotconst(gpointer ji,guint8 * code,guint8 * code_start,int dreg,guint32 patch_type,gconstpointer data)746 mono_arm_emit_aotconst (gpointer ji, guint8 *code, guint8 *code_start, int dreg, guint32 patch_type, gconstpointer data)
747 {
748 	return emit_aotconst_full (NULL, (MonoJumpInfo**)ji, code, code_start, dreg, patch_type, data);
749 }
750 
751 gboolean
mono_arch_have_fast_tls(void)752 mono_arch_have_fast_tls (void)
753 {
754 #ifdef TARGET_IOS
755 	return FALSE;
756 #else
757 	return TRUE;
758 #endif
759 }
760 
761 static guint8*
emit_tls_get(guint8 * code,int dreg,int tls_offset)762 emit_tls_get (guint8 *code, int dreg, int tls_offset)
763 {
764 	arm_mrs (code, dreg, ARM_MRS_REG_TPIDR_EL0);
765 	if (tls_offset < 256) {
766 		arm_ldrx (code, dreg, dreg, tls_offset);
767 	} else {
768 		code = emit_addx_imm (code, dreg, dreg, tls_offset);
769 		arm_ldrx (code, dreg, dreg, 0);
770 	}
771 	return code;
772 }
773 
774 static guint8*
emit_tls_set(guint8 * code,int sreg,int tls_offset)775 emit_tls_set (guint8 *code, int sreg, int tls_offset)
776 {
777 	int tmpreg = ARMREG_IP0;
778 
779 	g_assert (sreg != tmpreg);
780 	arm_mrs (code, tmpreg, ARM_MRS_REG_TPIDR_EL0);
781 	if (tls_offset < 256) {
782 		arm_strx (code, sreg, tmpreg, tls_offset);
783 	} else {
784 		code = emit_addx_imm (code, tmpreg, tmpreg, tls_offset);
785 		arm_strx (code, sreg, tmpreg, 0);
786 	}
787 	return code;
788 }
789 
790 /*
791  * Emits
792  * - mov sp, fp
793  * - ldrp [fp, lr], [sp], !stack_offfset
794  * Clobbers TEMP_REGS.
795  */
796 __attribute__ ((__warn_unused_result__)) guint8*
mono_arm_emit_destroy_frame(guint8 * code,int stack_offset,guint64 temp_regs)797 mono_arm_emit_destroy_frame (guint8 *code, int stack_offset, guint64 temp_regs)
798 {
799 	arm_movspx (code, ARMREG_SP, ARMREG_FP);
800 
801 	if (arm_is_ldpx_imm (stack_offset)) {
802 		arm_ldpx_post (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, stack_offset);
803 	} else {
804 		arm_ldpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0);
805 		/* sp += stack_offset */
806 		g_assert (temp_regs & (1 << ARMREG_IP0));
807 		if (temp_regs & (1 << ARMREG_IP1)) {
808 			code = emit_addx_sp_imm (code, stack_offset);
809 		} else {
810 			int imm = stack_offset;
811 
812 			/* Can't use addx_sp_imm () since we can't clobber ip0/ip1 */
813 			arm_addx_imm (code, ARMREG_IP0, ARMREG_SP, 0);
814 			while (imm > 256) {
815 				arm_addx_imm (code, ARMREG_IP0, ARMREG_IP0, 256);
816 				imm -= 256;
817 			}
818 			arm_addx_imm (code, ARMREG_SP, ARMREG_IP0, imm);
819 		}
820 	}
821 	return code;
822 }
823 
824 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
825 
826 static guint8*
emit_thunk(guint8 * code,gconstpointer target)827 emit_thunk (guint8 *code, gconstpointer target)
828 {
829 	guint8 *p = code;
830 
831 	arm_ldrx_lit (code, ARMREG_IP0, code + 8);
832 	arm_brx (code, ARMREG_IP0);
833 	*(guint64*)code = (guint64)target;
834 	code += sizeof (guint64);
835 
836 	mono_arch_flush_icache (p, code - p);
837 	return code;
838 }
839 
840 static gpointer
create_thunk(MonoCompile * cfg,MonoDomain * domain,guchar * code,const guchar * target)841 create_thunk (MonoCompile *cfg, MonoDomain *domain, guchar *code, const guchar *target)
842 {
843 	MonoJitInfo *ji;
844 	MonoThunkJitInfo *info;
845 	guint8 *thunks, *p;
846 	int thunks_size;
847 	guint8 *orig_target;
848 	guint8 *target_thunk;
849 
850 	if (!domain)
851 		domain = mono_domain_get ();
852 
853 	if (cfg) {
854 		/*
855 		 * This can be called multiple times during JITting,
856 		 * save the current position in cfg->arch to avoid
857 		 * doing a O(n^2) search.
858 		 */
859 		if (!cfg->arch.thunks) {
860 			cfg->arch.thunks = cfg->thunks;
861 			cfg->arch.thunks_size = cfg->thunk_area;
862 		}
863 		thunks = cfg->arch.thunks;
864 		thunks_size = cfg->arch.thunks_size;
865 		if (!thunks_size) {
866 			g_print ("thunk failed %p->%p, thunk space=%d method %s", code, target, thunks_size, mono_method_full_name (cfg->method, TRUE));
867 			g_assert_not_reached ();
868 		}
869 
870 		g_assert (*(guint32*)thunks == 0);
871 		emit_thunk (thunks, target);
872 
873 		cfg->arch.thunks += THUNK_SIZE;
874 		cfg->arch.thunks_size -= THUNK_SIZE;
875 
876 		return thunks;
877 	} else {
878 		ji = mini_jit_info_table_find (domain, (char*)code, NULL);
879 		g_assert (ji);
880 		info = mono_jit_info_get_thunk_info (ji);
881 		g_assert (info);
882 
883 		thunks = (guint8*)ji->code_start + info->thunks_offset;
884 		thunks_size = info->thunks_size;
885 
886 		orig_target = mono_arch_get_call_target (code + 4);
887 
888 		mono_domain_lock (domain);
889 
890 		target_thunk = NULL;
891 		if (orig_target >= thunks && orig_target < thunks + thunks_size) {
892 			/* The call already points to a thunk, because of trampolines etc. */
893 			target_thunk = orig_target;
894 		} else {
895 			for (p = thunks; p < thunks + thunks_size; p += THUNK_SIZE) {
896 				if (((guint32*)p) [0] == 0) {
897 					/* Free entry */
898 					target_thunk = p;
899 					break;
900 				} else if (((guint64*)p) [1] == (guint64)target) {
901 					/* Thunk already points to target */
902 					target_thunk = p;
903 					break;
904 				}
905 			}
906 		}
907 
908 		//printf ("THUNK: %p %p %p\n", code, target, target_thunk);
909 
910 		if (!target_thunk) {
911 			mono_domain_unlock (domain);
912 			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));
913 			g_assert_not_reached ();
914 		}
915 
916 		emit_thunk (target_thunk, target);
917 
918 		mono_domain_unlock (domain);
919 
920 		return target_thunk;
921 	}
922 }
923 
924 static void
arm_patch_full(MonoCompile * cfg,MonoDomain * domain,guint8 * code,guint8 * target,int relocation)925 arm_patch_full (MonoCompile *cfg, MonoDomain *domain, guint8 *code, guint8 *target, int relocation)
926 {
927 	switch (relocation) {
928 	case MONO_R_ARM64_B:
929 		if (arm_is_bl_disp (code, target)) {
930 			arm_b (code, target);
931 		} else {
932 			gpointer thunk;
933 
934 			thunk = create_thunk (cfg, domain, code, target);
935 			g_assert (arm_is_bl_disp (code, thunk));
936 			arm_b (code, thunk);
937 		}
938 		break;
939 	case MONO_R_ARM64_BCC: {
940 		int cond;
941 
942 		cond = arm_get_bcc_cond (code);
943 		arm_bcc (code, cond, target);
944 		break;
945 	}
946 	case MONO_R_ARM64_CBZ:
947 		arm_set_cbz_target (code, target);
948 		break;
949 	case MONO_R_ARM64_IMM: {
950 		guint64 imm = (guint64)target;
951 		int dreg;
952 
953 		/* emit_imm64_template () */
954 		dreg = arm_get_movzx_rd (code);
955 		arm_movzx (code, dreg, imm & 0xffff, 0);
956 		arm_movkx (code, dreg, (imm >> 16) & 0xffff, 16);
957 		arm_movkx (code, dreg, (imm >> 32) & 0xffff, 32);
958 		arm_movkx (code, dreg, (imm >> 48) & 0xffff, 48);
959 		break;
960 	}
961 	case MONO_R_ARM64_BL:
962 		if (arm_is_bl_disp (code, target)) {
963 			arm_bl (code, target);
964 		} else {
965 			gpointer thunk;
966 
967 			thunk = create_thunk (cfg, domain, code, target);
968 			g_assert (arm_is_bl_disp (code, thunk));
969 			arm_bl (code, thunk);
970 		}
971 		break;
972 	default:
973 		g_assert_not_reached ();
974 	}
975 }
976 
977 static void
arm_patch_rel(guint8 * code,guint8 * target,int relocation)978 arm_patch_rel (guint8 *code, guint8 *target, int relocation)
979 {
980 	arm_patch_full (NULL, NULL, code, target, relocation);
981 }
982 
983 void
mono_arm_patch(guint8 * code,guint8 * target,int relocation)984 mono_arm_patch (guint8 *code, guint8 *target, int relocation)
985 {
986 	arm_patch_rel (code, target, relocation);
987 }
988 
989 void
mono_arch_patch_code_new(MonoCompile * cfg,MonoDomain * domain,guint8 * code,MonoJumpInfo * ji,gpointer target)990 mono_arch_patch_code_new (MonoCompile *cfg, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gpointer target)
991 {
992 	guint8 *ip;
993 
994 	ip = ji->ip.i + code;
995 
996 	switch (ji->type) {
997 	case MONO_PATCH_INFO_METHOD_JUMP:
998 		/* ji->relocation is not set by the caller */
999 		arm_patch_full (cfg, domain, ip, (guint8*)target, MONO_R_ARM64_B);
1000 		break;
1001 	default:
1002 		arm_patch_full (cfg, domain, ip, (guint8*)target, ji->relocation);
1003 		break;
1004 	}
1005 }
1006 
1007 void
mono_arch_free_jit_tls_data(MonoJitTlsData * tls)1008 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
1009 {
1010 }
1011 
1012 void
mono_arch_flush_register_windows(void)1013 mono_arch_flush_register_windows (void)
1014 {
1015 }
1016 
1017 MonoMethod*
mono_arch_find_imt_method(mgreg_t * regs,guint8 * code)1018 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
1019 {
1020 	return (gpointer)regs [MONO_ARCH_RGCTX_REG];
1021 }
1022 
1023 MonoVTable*
mono_arch_find_static_call_vtable(mgreg_t * regs,guint8 * code)1024 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
1025 {
1026 	return (gpointer)regs [MONO_ARCH_RGCTX_REG];
1027 }
1028 
1029 mgreg_t
mono_arch_context_get_int_reg(MonoContext * ctx,int reg)1030 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
1031 {
1032 	return ctx->regs [reg];
1033 }
1034 
1035 void
mono_arch_context_set_int_reg(MonoContext * ctx,int reg,mgreg_t val)1036 mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
1037 {
1038 	ctx->regs [reg] = val;
1039 }
1040 
1041 /*
1042  * mono_arch_set_target:
1043  *
1044  *   Set the target architecture the JIT backend should generate code for, in the form
1045  * of a GNU target triplet. Only used in AOT mode.
1046  */
1047 void
mono_arch_set_target(char * mtriple)1048 mono_arch_set_target (char *mtriple)
1049 {
1050 	if (strstr (mtriple, "darwin") || strstr (mtriple, "ios")) {
1051 		ios_abi = TRUE;
1052 	}
1053 }
1054 
1055 static void
add_general(CallInfo * cinfo,ArgInfo * ainfo,int size,gboolean sign)1056 add_general (CallInfo *cinfo, ArgInfo *ainfo, int size, gboolean sign)
1057 {
1058 	if (cinfo->gr >= PARAM_REGS) {
1059 		ainfo->storage = ArgOnStack;
1060 		if (ios_abi) {
1061 			/* Assume size == align */
1062 			cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, size);
1063 			ainfo->offset = cinfo->stack_usage;
1064 			ainfo->slot_size = size;
1065 			ainfo->sign = sign;
1066 			cinfo->stack_usage += size;
1067 		} else {
1068 			ainfo->offset = cinfo->stack_usage;
1069 			ainfo->slot_size = 8;
1070 			ainfo->sign = FALSE;
1071 			/* Put arguments into 8 byte aligned stack slots */
1072 			cinfo->stack_usage += 8;
1073 		}
1074 	} else {
1075 		ainfo->storage = ArgInIReg;
1076 		ainfo->reg = cinfo->gr;
1077 		cinfo->gr ++;
1078 	}
1079 }
1080 
1081 static void
add_fp(CallInfo * cinfo,ArgInfo * ainfo,gboolean single)1082 add_fp (CallInfo *cinfo, ArgInfo *ainfo, gboolean single)
1083 {
1084 	int size = single ? 4 : 8;
1085 
1086 	if (cinfo->fr >= FP_PARAM_REGS) {
1087 		ainfo->storage = single ? ArgOnStackR4 : ArgOnStackR8;
1088 		if (ios_abi) {
1089 			cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, size);
1090 			ainfo->offset = cinfo->stack_usage;
1091 			ainfo->slot_size = size;
1092 			cinfo->stack_usage += size;
1093 		} else {
1094 			ainfo->offset = cinfo->stack_usage;
1095 			ainfo->slot_size = 8;
1096 			/* Put arguments into 8 byte aligned stack slots */
1097 			cinfo->stack_usage += 8;
1098 		}
1099 	} else {
1100 		if (single)
1101 			ainfo->storage = ArgInFRegR4;
1102 		else
1103 			ainfo->storage = ArgInFReg;
1104 		ainfo->reg = cinfo->fr;
1105 		cinfo->fr ++;
1106 	}
1107 }
1108 
1109 static gboolean
is_hfa(MonoType * t,int * out_nfields,int * out_esize,int * field_offsets)1110 is_hfa (MonoType *t, int *out_nfields, int *out_esize, int *field_offsets)
1111 {
1112 	MonoClass *klass;
1113 	gpointer iter;
1114 	MonoClassField *field;
1115 	MonoType *ftype, *prev_ftype = NULL;
1116 	int i, nfields = 0;
1117 
1118 	klass = mono_class_from_mono_type (t);
1119 	iter = NULL;
1120 	while ((field = mono_class_get_fields (klass, &iter))) {
1121 		if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
1122 			continue;
1123 		ftype = mono_field_get_type (field);
1124 		ftype = mini_get_underlying_type (ftype);
1125 
1126 		if (MONO_TYPE_ISSTRUCT (ftype)) {
1127 			int nested_nfields, nested_esize;
1128 			int nested_field_offsets [16];
1129 
1130 			if (!is_hfa (ftype, &nested_nfields, &nested_esize, nested_field_offsets))
1131 				return FALSE;
1132 			if (nested_esize == 4)
1133 				ftype = &mono_defaults.single_class->byval_arg;
1134 			else
1135 				ftype = &mono_defaults.double_class->byval_arg;
1136 			if (prev_ftype && prev_ftype->type != ftype->type)
1137 				return FALSE;
1138 			prev_ftype = ftype;
1139 			for (i = 0; i < nested_nfields; ++i) {
1140 				if (nfields + i < 4)
1141 					field_offsets [nfields + i] = field->offset - sizeof (MonoObject) + nested_field_offsets [i];
1142 			}
1143 			nfields += nested_nfields;
1144 		} else {
1145 			if (!(!ftype->byref && (ftype->type == MONO_TYPE_R4 || ftype->type == MONO_TYPE_R8)))
1146 				return FALSE;
1147 			if (prev_ftype && prev_ftype->type != ftype->type)
1148 				return FALSE;
1149 			prev_ftype = ftype;
1150 			if (nfields < 4)
1151 				field_offsets [nfields] = field->offset - sizeof (MonoObject);
1152 			nfields ++;
1153 		}
1154 	}
1155 	if (nfields == 0 || nfields > 4)
1156 		return FALSE;
1157 	*out_nfields = nfields;
1158 	*out_esize = prev_ftype->type == MONO_TYPE_R4 ? 4 : 8;
1159 	return TRUE;
1160 }
1161 
1162 static void
add_valuetype(CallInfo * cinfo,ArgInfo * ainfo,MonoType * t)1163 add_valuetype (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t)
1164 {
1165 	int i, size, align_size, nregs, nfields, esize;
1166 	int field_offsets [16];
1167 	guint32 align;
1168 
1169 	size = mini_type_stack_size_full (t, &align, cinfo->pinvoke);
1170 	align_size = ALIGN_TO (size, 8);
1171 
1172 	nregs = align_size / 8;
1173 	if (is_hfa (t, &nfields, &esize, field_offsets)) {
1174 		/*
1175 		 * The struct might include nested float structs aligned at 8,
1176 		 * so need to keep track of the offsets of the individual fields.
1177 		 */
1178 		if (cinfo->fr + nfields <= FP_PARAM_REGS) {
1179 			ainfo->storage = ArgHFA;
1180 			ainfo->reg = cinfo->fr;
1181 			ainfo->nregs = nfields;
1182 			ainfo->size = size;
1183 			ainfo->esize = esize;
1184 			for (i = 0; i < nfields; ++i)
1185 				ainfo->foffsets [i] = field_offsets [i];
1186 			cinfo->fr += ainfo->nregs;
1187 		} else {
1188 			ainfo->nfregs_to_skip = FP_PARAM_REGS > cinfo->fr ? FP_PARAM_REGS - cinfo->fr : 0;
1189 			cinfo->fr = FP_PARAM_REGS;
1190 			size = ALIGN_TO (size, 8);
1191 			ainfo->storage = ArgVtypeOnStack;
1192 			ainfo->offset = cinfo->stack_usage;
1193 			ainfo->size = size;
1194 			ainfo->hfa = TRUE;
1195 			ainfo->nregs = nfields;
1196 			ainfo->esize = esize;
1197 			cinfo->stack_usage += size;
1198 		}
1199 		return;
1200 	}
1201 
1202 	if (align_size > 16) {
1203 		ainfo->storage = ArgVtypeByRef;
1204 		ainfo->size = size;
1205 		return;
1206 	}
1207 
1208 	if (cinfo->gr + nregs > PARAM_REGS) {
1209 		size = ALIGN_TO (size, 8);
1210 		ainfo->storage = ArgVtypeOnStack;
1211 		ainfo->offset = cinfo->stack_usage;
1212 		ainfo->size = size;
1213 		cinfo->stack_usage += size;
1214 		cinfo->gr = PARAM_REGS;
1215 	} else {
1216 		ainfo->storage = ArgVtypeInIRegs;
1217 		ainfo->reg = cinfo->gr;
1218 		ainfo->nregs = nregs;
1219 		ainfo->size = size;
1220 		cinfo->gr += nregs;
1221 	}
1222 }
1223 
1224 static void
add_param(CallInfo * cinfo,ArgInfo * ainfo,MonoType * t)1225 add_param (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t)
1226 {
1227 	MonoType *ptype;
1228 
1229 	ptype = mini_get_underlying_type (t);
1230 	switch (ptype->type) {
1231 	case MONO_TYPE_I1:
1232 		add_general (cinfo, ainfo, 1, TRUE);
1233 		break;
1234 	case MONO_TYPE_U1:
1235 		add_general (cinfo, ainfo, 1, FALSE);
1236 		break;
1237 	case MONO_TYPE_I2:
1238 		add_general (cinfo, ainfo, 2, TRUE);
1239 		break;
1240 	case MONO_TYPE_U2:
1241 		add_general (cinfo, ainfo, 2, FALSE);
1242 		break;
1243 	case MONO_TYPE_I4:
1244 		add_general (cinfo, ainfo, 4, TRUE);
1245 		break;
1246 	case MONO_TYPE_U4:
1247 		add_general (cinfo, ainfo, 4, FALSE);
1248 		break;
1249 	case MONO_TYPE_I:
1250 	case MONO_TYPE_U:
1251 	case MONO_TYPE_PTR:
1252 	case MONO_TYPE_FNPTR:
1253 	case MONO_TYPE_OBJECT:
1254 	case MONO_TYPE_U8:
1255 	case MONO_TYPE_I8:
1256 		add_general (cinfo, ainfo, 8, FALSE);
1257 		break;
1258 	case MONO_TYPE_R8:
1259 		add_fp (cinfo, ainfo, FALSE);
1260 		break;
1261 	case MONO_TYPE_R4:
1262 		add_fp (cinfo, ainfo, TRUE);
1263 		break;
1264 	case MONO_TYPE_VALUETYPE:
1265 	case MONO_TYPE_TYPEDBYREF:
1266 		add_valuetype (cinfo, ainfo, ptype);
1267 		break;
1268 	case MONO_TYPE_VOID:
1269 		ainfo->storage = ArgNone;
1270 		break;
1271 	case MONO_TYPE_GENERICINST:
1272 		if (!mono_type_generic_inst_is_valuetype (ptype)) {
1273 			add_general (cinfo, ainfo, 8, FALSE);
1274 		} else if (mini_is_gsharedvt_variable_type (ptype)) {
1275 			/*
1276 			 * Treat gsharedvt arguments as large vtypes
1277 			 */
1278 			ainfo->storage = ArgVtypeByRef;
1279 			ainfo->gsharedvt = TRUE;
1280 		} else {
1281 			add_valuetype (cinfo, ainfo, ptype);
1282 		}
1283 		break;
1284 	case MONO_TYPE_VAR:
1285 	case MONO_TYPE_MVAR:
1286 		g_assert (mini_is_gsharedvt_type (ptype));
1287 		ainfo->storage = ArgVtypeByRef;
1288 		ainfo->gsharedvt = TRUE;
1289 		break;
1290 	default:
1291 		g_assert_not_reached ();
1292 		break;
1293 	}
1294 }
1295 
1296 /*
1297  * get_call_info:
1298  *
1299  *  Obtain information about a call according to the calling convention.
1300  */
1301 static CallInfo*
get_call_info(MonoMemPool * mp,MonoMethodSignature * sig)1302 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
1303 {
1304 	CallInfo *cinfo;
1305 	ArgInfo *ainfo;
1306 	int n, pstart, pindex;
1307 
1308 	n = sig->hasthis + sig->param_count;
1309 
1310 	if (mp)
1311 		cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1312 	else
1313 		cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
1314 
1315 	cinfo->nargs = n;
1316 	cinfo->pinvoke = sig->pinvoke;
1317 
1318 	/* Return value */
1319 	add_param (cinfo, &cinfo->ret, sig->ret);
1320 	if (cinfo->ret.storage == ArgVtypeByRef)
1321 		cinfo->ret.reg = ARMREG_R8;
1322 	/* Reset state */
1323 	cinfo->gr = 0;
1324 	cinfo->fr = 0;
1325 	cinfo->stack_usage = 0;
1326 
1327 	/* Parameters */
1328 	if (sig->hasthis)
1329 		add_general (cinfo, cinfo->args + 0, 8, FALSE);
1330 	pstart = 0;
1331 	for (pindex = pstart; pindex < sig->param_count; ++pindex) {
1332 		ainfo = cinfo->args + sig->hasthis + pindex;
1333 
1334 		if ((sig->call_convention == MONO_CALL_VARARG) && (pindex == sig->sentinelpos)) {
1335 			/* Prevent implicit arguments and sig_cookie from
1336 			   being passed in registers */
1337 			cinfo->gr = PARAM_REGS;
1338 			cinfo->fr = FP_PARAM_REGS;
1339 			/* Emit the signature cookie just before the implicit arguments */
1340 			add_param (cinfo, &cinfo->sig_cookie, &mono_defaults.int_class->byval_arg);
1341 		}
1342 
1343 		add_param (cinfo, ainfo, sig->params [pindex]);
1344 		if (ainfo->storage == ArgVtypeByRef) {
1345 			/* Pass the argument address in the next register */
1346 			if (cinfo->gr >= PARAM_REGS) {
1347 				ainfo->storage = ArgVtypeByRefOnStack;
1348 				cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, 8);
1349 				ainfo->offset = cinfo->stack_usage;
1350 				cinfo->stack_usage += 8;
1351 			} else {
1352 				ainfo->reg = cinfo->gr;
1353 				cinfo->gr ++;
1354 			}
1355 		}
1356 	}
1357 
1358 	/* Handle the case where there are no implicit arguments */
1359 	if ((sig->call_convention == MONO_CALL_VARARG) && (pindex == sig->sentinelpos)) {
1360 		/* Prevent implicit arguments and sig_cookie from
1361 		   being passed in registers */
1362 		cinfo->gr = PARAM_REGS;
1363 		cinfo->fr = FP_PARAM_REGS;
1364 		/* Emit the signature cookie just before the implicit arguments */
1365 		add_param (cinfo, &cinfo->sig_cookie, &mono_defaults.int_class->byval_arg);
1366 	}
1367 
1368 	cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, MONO_ARCH_FRAME_ALIGNMENT);
1369 
1370 	return cinfo;
1371 }
1372 
1373 typedef struct {
1374 	MonoMethodSignature *sig;
1375 	CallInfo *cinfo;
1376 	MonoType *rtype;
1377 	MonoType **param_types;
1378 	int n_fpargs, n_fpret;
1379 } ArchDynCallInfo;
1380 
1381 static gboolean
dyn_call_supported(CallInfo * cinfo,MonoMethodSignature * sig)1382 dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
1383 {
1384 	int i;
1385 
1386 	// FIXME: Add more cases
1387 	switch (cinfo->ret.storage) {
1388 	case ArgNone:
1389 	case ArgInIReg:
1390 	case ArgInFReg:
1391 	case ArgInFRegR4:
1392 	case ArgVtypeByRef:
1393 		break;
1394 	case ArgVtypeInIRegs:
1395 		if (cinfo->ret.nregs > 2)
1396 			return FALSE;
1397 		break;
1398 	case ArgHFA:
1399 		break;
1400 	default:
1401 		return FALSE;
1402 	}
1403 
1404 	for (i = 0; i < cinfo->nargs; ++i) {
1405 		ArgInfo *ainfo = &cinfo->args [i];
1406 
1407 		switch (ainfo->storage) {
1408 		case ArgInIReg:
1409 		case ArgVtypeInIRegs:
1410 		case ArgInFReg:
1411 		case ArgInFRegR4:
1412 		case ArgHFA:
1413 		case ArgVtypeByRef:
1414 		case ArgOnStack:
1415 		case ArgVtypeOnStack:
1416 			break;
1417 		default:
1418 			return FALSE;
1419 		}
1420 	}
1421 
1422 	return TRUE;
1423 }
1424 
1425 MonoDynCallInfo*
mono_arch_dyn_call_prepare(MonoMethodSignature * sig)1426 mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
1427 {
1428 	ArchDynCallInfo *info;
1429 	CallInfo *cinfo;
1430 	int i;
1431 
1432 	cinfo = get_call_info (NULL, sig);
1433 
1434 	if (!dyn_call_supported (cinfo, sig)) {
1435 		g_free (cinfo);
1436 		return NULL;
1437 	}
1438 
1439 	info = g_new0 (ArchDynCallInfo, 1);
1440 	// FIXME: Preprocess the info to speed up start_dyn_call ()
1441 	info->sig = sig;
1442 	info->cinfo = cinfo;
1443 	info->rtype = mini_get_underlying_type (sig->ret);
1444 	info->param_types = g_new0 (MonoType*, sig->param_count);
1445 	for (i = 0; i < sig->param_count; ++i)
1446 		info->param_types [i] = mini_get_underlying_type (sig->params [i]);
1447 
1448 	switch (cinfo->ret.storage) {
1449 	case ArgInFReg:
1450 	case ArgInFRegR4:
1451 		info->n_fpret = 1;
1452 		break;
1453 	case ArgHFA:
1454 		info->n_fpret = cinfo->ret.nregs;
1455 		break;
1456 	default:
1457 		break;
1458 	}
1459 
1460 	return (MonoDynCallInfo*)info;
1461 }
1462 
1463 void
mono_arch_dyn_call_free(MonoDynCallInfo * info)1464 mono_arch_dyn_call_free (MonoDynCallInfo *info)
1465 {
1466 	ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
1467 
1468 	g_free (ainfo->cinfo);
1469 	g_free (ainfo->param_types);
1470 	g_free (ainfo);
1471 }
1472 
1473 int
mono_arch_dyn_call_get_buf_size(MonoDynCallInfo * info)1474 mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info)
1475 {
1476 	ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
1477 
1478 	g_assert (ainfo->cinfo->stack_usage % MONO_ARCH_FRAME_ALIGNMENT == 0);
1479 	return sizeof (DynCallArgs) + ainfo->cinfo->stack_usage;
1480 }
1481 
1482 static double
bitcast_r4_to_r8(float f)1483 bitcast_r4_to_r8 (float f)
1484 {
1485 	float *p = &f;
1486 
1487 	return *(double*)p;
1488 }
1489 
1490 static float
bitcast_r8_to_r4(double f)1491 bitcast_r8_to_r4 (double f)
1492 {
1493 	double *p = &f;
1494 
1495 	return *(float*)p;
1496 }
1497 
1498 void
mono_arch_start_dyn_call(MonoDynCallInfo * info,gpointer ** args,guint8 * ret,guint8 * buf)1499 mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf)
1500 {
1501 	ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
1502 	DynCallArgs *p = (DynCallArgs*)buf;
1503 	int aindex, arg_index, greg, i, pindex;
1504 	MonoMethodSignature *sig = dinfo->sig;
1505 	CallInfo *cinfo = dinfo->cinfo;
1506 	int buffer_offset = 0;
1507 
1508 	p->res = 0;
1509 	p->ret = ret;
1510 	p->n_fpargs = dinfo->n_fpargs;
1511 	p->n_fpret = dinfo->n_fpret;
1512 	p->n_stackargs = cinfo->stack_usage / sizeof (mgreg_t);
1513 
1514 	arg_index = 0;
1515 	greg = 0;
1516 	pindex = 0;
1517 
1518 	if (sig->hasthis)
1519 		p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);
1520 
1521 	if (cinfo->ret.storage == ArgVtypeByRef)
1522 		p->regs [ARMREG_R8] = (mgreg_t)ret;
1523 
1524 	for (aindex = pindex; aindex < sig->param_count; aindex++) {
1525 		MonoType *t = dinfo->param_types [aindex];
1526 		gpointer *arg = args [arg_index ++];
1527 		ArgInfo *ainfo = &cinfo->args [aindex + sig->hasthis];
1528 		int slot = -1;
1529 
1530 		if (ainfo->storage == ArgOnStack || ainfo->storage == ArgVtypeOnStack) {
1531 			slot = PARAM_REGS + 1 + (ainfo->offset / sizeof (mgreg_t));
1532 		} else {
1533 			slot = ainfo->reg;
1534 		}
1535 
1536 		if (t->byref) {
1537 			p->regs [slot] = (mgreg_t)*arg;
1538 			continue;
1539 		}
1540 
1541 		if (ios_abi && ainfo->storage == ArgOnStack) {
1542 			guint8 *stack_arg = (guint8*)&(p->regs [PARAM_REGS + 1]) + ainfo->offset;
1543 			gboolean handled = TRUE;
1544 
1545 			/* Special case arguments smaller than 1 machine word */
1546 			switch (t->type) {
1547 			case MONO_TYPE_U1:
1548 				*(guint8*)stack_arg = *(guint8*)arg;
1549 				break;
1550 			case MONO_TYPE_I1:
1551 				*(gint8*)stack_arg = *(gint8*)arg;
1552 				break;
1553 			case MONO_TYPE_U2:
1554 				*(guint16*)stack_arg = *(guint16*)arg;
1555 				break;
1556 			case MONO_TYPE_I2:
1557 				*(gint16*)stack_arg = *(gint16*)arg;
1558 				break;
1559 			case MONO_TYPE_I4:
1560 				*(gint32*)stack_arg = *(gint32*)arg;
1561 				break;
1562 			case MONO_TYPE_U4:
1563 				*(guint32*)stack_arg = *(guint32*)arg;
1564 				break;
1565 			default:
1566 				handled = FALSE;
1567 				break;
1568 			}
1569 			if (handled)
1570 				continue;
1571 		}
1572 
1573 		switch (t->type) {
1574 		case MONO_TYPE_OBJECT:
1575 		case MONO_TYPE_PTR:
1576 		case MONO_TYPE_I:
1577 		case MONO_TYPE_U:
1578 		case MONO_TYPE_I8:
1579 		case MONO_TYPE_U8:
1580 			p->regs [slot] = (mgreg_t)*arg;
1581 			break;
1582 		case MONO_TYPE_U1:
1583 			p->regs [slot] = *(guint8*)arg;
1584 			break;
1585 		case MONO_TYPE_I1:
1586 			p->regs [slot] = *(gint8*)arg;
1587 			break;
1588 		case MONO_TYPE_I2:
1589 			p->regs [slot] = *(gint16*)arg;
1590 			break;
1591 		case MONO_TYPE_U2:
1592 			p->regs [slot] = *(guint16*)arg;
1593 			break;
1594 		case MONO_TYPE_I4:
1595 			p->regs [slot] = *(gint32*)arg;
1596 			break;
1597 		case MONO_TYPE_U4:
1598 			p->regs [slot] = *(guint32*)arg;
1599 			break;
1600 		case MONO_TYPE_R4:
1601 			p->fpregs [ainfo->reg] = bitcast_r4_to_r8 (*(float*)arg);
1602 			p->n_fpargs ++;
1603 			break;
1604 		case MONO_TYPE_R8:
1605 			p->fpregs [ainfo->reg] = *(double*)arg;
1606 			p->n_fpargs ++;
1607 			break;
1608 		case MONO_TYPE_GENERICINST:
1609 			if (MONO_TYPE_IS_REFERENCE (t)) {
1610 				p->regs [slot] = (mgreg_t)*arg;
1611 				break;
1612 			} else {
1613 				if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type (t))) {
1614 					MonoClass *klass = mono_class_from_mono_type (t);
1615 					guint8 *nullable_buf;
1616 					int size;
1617 
1618 					/*
1619 					 * Use p->buffer as a temporary buffer since the data needs to be available after this call
1620 					 * if the nullable param is passed by ref.
1621 					 */
1622 					size = mono_class_value_size (klass, NULL);
1623 					nullable_buf = p->buffer + buffer_offset;
1624 					buffer_offset += size;
1625 					g_assert (buffer_offset <= 256);
1626 
1627 					/* The argument pointed to by arg is either a boxed vtype or null */
1628 					mono_nullable_init (nullable_buf, (MonoObject*)arg, klass);
1629 
1630 					arg = (gpointer*)nullable_buf;
1631 					/* Fall though */
1632 				} else {
1633 					/* Fall though */
1634 				}
1635 			}
1636 		case MONO_TYPE_VALUETYPE:
1637 			switch (ainfo->storage) {
1638 			case ArgVtypeInIRegs:
1639 				for (i = 0; i < ainfo->nregs; ++i)
1640 					p->regs [slot ++] = ((mgreg_t*)arg) [i];
1641 				break;
1642 			case ArgHFA:
1643 				if (ainfo->esize == 4) {
1644 					for (i = 0; i < ainfo->nregs; ++i)
1645 						p->fpregs [ainfo->reg + i] = bitcast_r4_to_r8 (((float*)arg) [ainfo->foffsets [i] / 4]);
1646 				} else {
1647 					for (i = 0; i < ainfo->nregs; ++i)
1648 						p->fpregs [ainfo->reg + i] = ((double*)arg) [ainfo->foffsets [i] / 8];
1649 				}
1650 				p->n_fpargs += ainfo->nregs;
1651 				break;
1652 			case ArgVtypeByRef:
1653 				p->regs [slot] = (mgreg_t)arg;
1654 				break;
1655 			case ArgVtypeOnStack:
1656 				for (i = 0; i < ainfo->size / 8; ++i)
1657 					p->regs [slot ++] = ((mgreg_t*)arg) [i];
1658 				break;
1659 			default:
1660 				g_assert_not_reached ();
1661 				break;
1662 			}
1663 			break;
1664 		default:
1665 			g_assert_not_reached ();
1666 		}
1667 	}
1668 }
1669 
1670 void
mono_arch_finish_dyn_call(MonoDynCallInfo * info,guint8 * buf)1671 mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
1672 {
1673 	ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
1674 	CallInfo *cinfo = ainfo->cinfo;
1675 	DynCallArgs *args = (DynCallArgs*)buf;
1676 	MonoType *ptype = ainfo->rtype;
1677 	guint8 *ret = args->ret;
1678 	mgreg_t res = args->res;
1679 	mgreg_t res2 = args->res2;
1680 	int i;
1681 
1682 	if (cinfo->ret.storage == ArgVtypeByRef)
1683 		return;
1684 
1685 	switch (ptype->type) {
1686 	case MONO_TYPE_VOID:
1687 		*(gpointer*)ret = NULL;
1688 		break;
1689 	case MONO_TYPE_OBJECT:
1690 	case MONO_TYPE_I:
1691 	case MONO_TYPE_U:
1692 	case MONO_TYPE_PTR:
1693 		*(gpointer*)ret = (gpointer)res;
1694 		break;
1695 	case MONO_TYPE_I1:
1696 		*(gint8*)ret = res;
1697 		break;
1698 	case MONO_TYPE_U1:
1699 		*(guint8*)ret = res;
1700 		break;
1701 	case MONO_TYPE_I2:
1702 		*(gint16*)ret = res;
1703 		break;
1704 	case MONO_TYPE_U2:
1705 		*(guint16*)ret = res;
1706 		break;
1707 	case MONO_TYPE_I4:
1708 		*(gint32*)ret = res;
1709 		break;
1710 	case MONO_TYPE_U4:
1711 		*(guint32*)ret = res;
1712 		break;
1713 	case MONO_TYPE_I8:
1714 	case MONO_TYPE_U8:
1715 		*(guint64*)ret = res;
1716 		break;
1717 	case MONO_TYPE_R4:
1718 		*(float*)ret = bitcast_r8_to_r4 (args->fpregs [0]);
1719 		break;
1720 	case MONO_TYPE_R8:
1721 		*(double*)ret = args->fpregs [0];
1722 		break;
1723 	case MONO_TYPE_GENERICINST:
1724 		if (MONO_TYPE_IS_REFERENCE (ptype)) {
1725 			*(gpointer*)ret = (gpointer)res;
1726 			break;
1727 		} else {
1728 			/* Fall though */
1729 		}
1730 	case MONO_TYPE_VALUETYPE:
1731 		switch (ainfo->cinfo->ret.storage) {
1732 		case ArgVtypeInIRegs:
1733 			*(mgreg_t*)ret = res;
1734 			if (ainfo->cinfo->ret.nregs > 1)
1735 				((mgreg_t*)ret) [1] = res2;
1736 			break;
1737 		case ArgHFA:
1738 			/* Use the same area for returning fp values */
1739 			if (cinfo->ret.esize == 4) {
1740 				for (i = 0; i < cinfo->ret.nregs; ++i)
1741 					((float*)ret) [cinfo->ret.foffsets [i] / 4] = bitcast_r8_to_r4 (args->fpregs [i]);
1742 			} else {
1743 				for (i = 0; i < cinfo->ret.nregs; ++i)
1744 					((double*)ret) [cinfo->ret.foffsets [i] / 8] = args->fpregs [i];
1745 			}
1746 			break;
1747 		default:
1748 			g_assert_not_reached ();
1749 			break;
1750 		}
1751 		break;
1752 	default:
1753 		g_assert_not_reached ();
1754 	}
1755 }
1756 
1757 #if __APPLE__
1758 void sys_icache_invalidate (void *start, size_t len);
1759 #endif
1760 
1761 void
mono_arch_flush_icache(guint8 * code,gint size)1762 mono_arch_flush_icache (guint8 *code, gint size)
1763 {
1764 #ifndef MONO_CROSS_COMPILE
1765 #if __APPLE__
1766 	sys_icache_invalidate (code, size);
1767 #else
1768 	/* Don't rely on GCC's __clear_cache implementation, as it caches
1769 	 * icache/dcache cache line sizes, that can vary between cores on
1770 	 * big.LITTLE architectures. */
1771 	guint64 end = (guint64) (code + size);
1772 	guint64 addr;
1773 	/* always go with cacheline size of 4 bytes as this code isn't perf critical
1774 	 * anyway. Reading the cache line size from a machine register can be racy
1775 	 * on a big.LITTLE architecture if the cores don't have the same cache line
1776 	 * sizes. */
1777 	const size_t icache_line_size = 4;
1778 	const size_t dcache_line_size = 4;
1779 
1780 	addr = (guint64) code & ~(guint64) (dcache_line_size - 1);
1781 	for (; addr < end; addr += dcache_line_size)
1782 		asm volatile("dc civac, %0" : : "r" (addr) : "memory");
1783 	asm volatile("dsb ish" : : : "memory");
1784 
1785 	addr = (guint64) code & ~(guint64) (icache_line_size - 1);
1786 	for (; addr < end; addr += icache_line_size)
1787 		asm volatile("ic ivau, %0" : : "r" (addr) : "memory");
1788 
1789 	asm volatile ("dsb ish" : : : "memory");
1790 	asm volatile ("isb" : : : "memory");
1791 #endif
1792 #endif
1793 }
1794 
1795 #ifndef DISABLE_JIT
1796 
1797 gboolean
mono_arch_opcode_needs_emulation(MonoCompile * cfg,int opcode)1798 mono_arch_opcode_needs_emulation (MonoCompile *cfg, int opcode)
1799 {
1800 	NOT_IMPLEMENTED;
1801 	return FALSE;
1802 }
1803 
1804 GList *
mono_arch_get_allocatable_int_vars(MonoCompile * cfg)1805 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
1806 {
1807 	GList *vars = NULL;
1808 	int i;
1809 
1810 	for (i = 0; i < cfg->num_varinfo; i++) {
1811 		MonoInst *ins = cfg->varinfo [i];
1812 		MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
1813 
1814 		/* unused vars */
1815 		if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
1816 			continue;
1817 
1818 		if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) ||
1819 		    (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
1820 			continue;
1821 
1822 		if (mono_is_regsize_var (ins->inst_vtype)) {
1823 			g_assert (MONO_VARINFO (cfg, i)->reg == -1);
1824 			g_assert (i == vmv->idx);
1825 			vars = g_list_prepend (vars, vmv);
1826 		}
1827 	}
1828 
1829 	vars = mono_varlist_sort (cfg, vars, 0);
1830 
1831 	return vars;
1832 }
1833 
1834 GList *
mono_arch_get_global_int_regs(MonoCompile * cfg)1835 mono_arch_get_global_int_regs (MonoCompile *cfg)
1836 {
1837 	GList *regs = NULL;
1838 	int i;
1839 
1840 	/* r28 is reserved for cfg->arch.args_reg */
1841 	/* r27 is reserved for the imt argument */
1842 	for (i = ARMREG_R19; i <= ARMREG_R26; ++i)
1843 		regs = g_list_prepend (regs, GUINT_TO_POINTER (i));
1844 
1845 	return regs;
1846 }
1847 
1848 guint32
mono_arch_regalloc_cost(MonoCompile * cfg,MonoMethodVar * vmv)1849 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1850 {
1851 	MonoInst *ins = cfg->varinfo [vmv->idx];
1852 
1853 	if (ins->opcode == OP_ARG)
1854 		return 1;
1855 	else
1856 		return 2;
1857 }
1858 
1859 void
mono_arch_create_vars(MonoCompile * cfg)1860 mono_arch_create_vars (MonoCompile *cfg)
1861 {
1862 	MonoMethodSignature *sig;
1863 	CallInfo *cinfo;
1864 
1865 	sig = mono_method_signature (cfg->method);
1866 	if (!cfg->arch.cinfo)
1867 		cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1868 	cinfo = cfg->arch.cinfo;
1869 
1870 	if (cinfo->ret.storage == ArgVtypeByRef) {
1871 		cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1872 		cfg->vret_addr->flags |= MONO_INST_VOLATILE;
1873 	}
1874 
1875 	if (cfg->gen_sdb_seq_points) {
1876 		MonoInst *ins;
1877 
1878 		if (cfg->compile_aot) {
1879 			ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1880 			ins->flags |= MONO_INST_VOLATILE;
1881 			cfg->arch.seq_point_info_var = ins;
1882 		}
1883 
1884 		ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1885 		ins->flags |= MONO_INST_VOLATILE;
1886 		cfg->arch.ss_tramp_var = ins;
1887 
1888 		ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1889 		ins->flags |= MONO_INST_VOLATILE;
1890 		cfg->arch.bp_tramp_var = ins;
1891 	}
1892 
1893 	if (cfg->method->save_lmf) {
1894 		cfg->create_lmf_var = TRUE;
1895 		cfg->lmf_ir = TRUE;
1896 	}
1897 }
1898 
1899 void
mono_arch_allocate_vars(MonoCompile * cfg)1900 mono_arch_allocate_vars (MonoCompile *cfg)
1901 {
1902 	MonoMethodSignature *sig;
1903 	MonoInst *ins;
1904 	CallInfo *cinfo;
1905 	ArgInfo *ainfo;
1906 	int i, offset, size, align;
1907 	guint32 locals_stack_size, locals_stack_align;
1908 	gint32 *offsets;
1909 
1910 	/*
1911 	 * Allocate arguments and locals to either register (OP_REGVAR) or to a stack slot (OP_REGOFFSET).
1912 	 * Compute cfg->stack_offset and update cfg->used_int_regs.
1913 	 */
1914 
1915 	sig = mono_method_signature (cfg->method);
1916 
1917 	if (!cfg->arch.cinfo)
1918 		cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
1919 	cinfo = cfg->arch.cinfo;
1920 
1921 	/*
1922 	 * The ARM64 ABI always uses a frame pointer.
1923 	 * The instruction set prefers positive offsets, so fp points to the bottom of the
1924 	 * frame, and stack slots are at positive offsets.
1925 	 * If some arguments are received on the stack, their offsets relative to fp can
1926 	 * not be computed right now because the stack frame might grow due to spilling
1927 	 * done by the local register allocator. To solve this, we reserve a register
1928 	 * which points to them.
1929 	 * The stack frame looks like this:
1930 	 * args_reg -> <bottom of parent frame>
1931 	 *             <locals etc>
1932 	 *       fp -> <saved fp+lr>
1933      *       sp -> <localloc/params area>
1934 	 */
1935 	cfg->frame_reg = ARMREG_FP;
1936 	cfg->flags |= MONO_CFG_HAS_SPILLUP;
1937 	offset = 0;
1938 
1939 	/* Saved fp+lr */
1940 	offset += 16;
1941 
1942 	if (cinfo->stack_usage) {
1943 		g_assert (!(cfg->used_int_regs & (1 << ARMREG_R28)));
1944 		cfg->arch.args_reg = ARMREG_R28;
1945 		cfg->used_int_regs |= 1 << ARMREG_R28;
1946 	}
1947 
1948 	if (cfg->method->save_lmf) {
1949 		/* The LMF var is allocated normally */
1950 	} else {
1951 		/* Callee saved regs */
1952 		cfg->arch.saved_gregs_offset = offset;
1953 		for (i = 0; i < 32; ++i)
1954 			if ((MONO_ARCH_CALLEE_SAVED_REGS & (1 << i)) && (cfg->used_int_regs & (1 << i)))
1955 				offset += 8;
1956 	}
1957 
1958 	/* Return value */
1959 	switch (cinfo->ret.storage) {
1960 	case ArgNone:
1961 		break;
1962 	case ArgInIReg:
1963 	case ArgInFReg:
1964 	case ArgInFRegR4:
1965 		cfg->ret->opcode = OP_REGVAR;
1966 		cfg->ret->dreg = cinfo->ret.reg;
1967 		break;
1968 	case ArgVtypeInIRegs:
1969 	case ArgHFA:
1970 		/* Allocate a local to hold the result, the epilog will copy it to the correct place */
1971 		cfg->ret->opcode = OP_REGOFFSET;
1972 		cfg->ret->inst_basereg = cfg->frame_reg;
1973 		cfg->ret->inst_offset = offset;
1974 		if (cinfo->ret.storage == ArgHFA)
1975 			// FIXME:
1976 			offset += 64;
1977 		else
1978 			offset += 16;
1979 		break;
1980 	case ArgVtypeByRef:
1981 		/* This variable will be initalized in the prolog from R8 */
1982 		cfg->vret_addr->opcode = OP_REGOFFSET;
1983 		cfg->vret_addr->inst_basereg = cfg->frame_reg;
1984 		cfg->vret_addr->inst_offset = offset;
1985 		offset += 8;
1986 		if (G_UNLIKELY (cfg->verbose_level > 1)) {
1987 			printf ("vret_addr =");
1988 			mono_print_ins (cfg->vret_addr);
1989 		}
1990 		break;
1991 	default:
1992 		g_assert_not_reached ();
1993 		break;
1994 	}
1995 
1996 	/* Arguments */
1997 	for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1998 		ainfo = cinfo->args + i;
1999 
2000 		ins = cfg->args [i];
2001 		if (ins->opcode == OP_REGVAR)
2002 			continue;
2003 
2004 		ins->opcode = OP_REGOFFSET;
2005 		ins->inst_basereg = cfg->frame_reg;
2006 
2007 		switch (ainfo->storage) {
2008 		case ArgInIReg:
2009 		case ArgInFReg:
2010 		case ArgInFRegR4:
2011 			// FIXME: Use nregs/size
2012 			/* These will be copied to the stack in the prolog */
2013 			ins->inst_offset = offset;
2014 			offset += 8;
2015 			break;
2016 		case ArgOnStack:
2017 		case ArgOnStackR4:
2018 		case ArgOnStackR8:
2019 		case ArgVtypeOnStack:
2020 			/* These are in the parent frame */
2021 			g_assert (cfg->arch.args_reg);
2022 			ins->inst_basereg = cfg->arch.args_reg;
2023 			ins->inst_offset = ainfo->offset;
2024 			break;
2025 		case ArgVtypeInIRegs:
2026 		case ArgHFA:
2027 			ins->opcode = OP_REGOFFSET;
2028 			ins->inst_basereg = cfg->frame_reg;
2029 			/* These arguments are saved to the stack in the prolog */
2030 			ins->inst_offset = offset;
2031 			if (cfg->verbose_level >= 2)
2032 				printf ("arg %d allocated to %s+0x%0x.\n", i, mono_arch_regname (ins->inst_basereg), (int)ins->inst_offset);
2033 			if (ainfo->storage == ArgHFA)
2034 				// FIXME:
2035 				offset += 64;
2036 			else
2037 				offset += 16;
2038 			break;
2039 		case ArgVtypeByRefOnStack: {
2040 			MonoInst *vtaddr;
2041 
2042 			if (ainfo->gsharedvt) {
2043 				ins->opcode = OP_REGOFFSET;
2044 				ins->inst_basereg = cfg->arch.args_reg;
2045 				ins->inst_offset = ainfo->offset;
2046 				break;
2047 			}
2048 
2049 			/* The vtype address is in the parent frame */
2050 			g_assert (cfg->arch.args_reg);
2051 			MONO_INST_NEW (cfg, vtaddr, 0);
2052 			vtaddr->opcode = OP_REGOFFSET;
2053 			vtaddr->inst_basereg = cfg->arch.args_reg;
2054 			vtaddr->inst_offset = ainfo->offset;
2055 
2056 			/* Need an indirection */
2057 			ins->opcode = OP_VTARG_ADDR;
2058 			ins->inst_left = vtaddr;
2059 			break;
2060 		}
2061 		case ArgVtypeByRef: {
2062 			MonoInst *vtaddr;
2063 
2064 			if (ainfo->gsharedvt) {
2065 				ins->opcode = OP_REGOFFSET;
2066 				ins->inst_basereg = cfg->frame_reg;
2067 				ins->inst_offset = offset;
2068 				offset += 8;
2069 				break;
2070 			}
2071 
2072 			/* The vtype address is in a register, will be copied to the stack in the prolog */
2073 			MONO_INST_NEW (cfg, vtaddr, 0);
2074 			vtaddr->opcode = OP_REGOFFSET;
2075 			vtaddr->inst_basereg = cfg->frame_reg;
2076 			vtaddr->inst_offset = offset;
2077 			offset += 8;
2078 
2079 			/* Need an indirection */
2080 			ins->opcode = OP_VTARG_ADDR;
2081 			ins->inst_left = vtaddr;
2082 			break;
2083 		}
2084 		default:
2085 			g_assert_not_reached ();
2086 			break;
2087 		}
2088 	}
2089 
2090 	/* Allocate these first so they have a small offset, OP_SEQ_POINT depends on this */
2091 	// FIXME: Allocate these to registers
2092 	ins = cfg->arch.seq_point_info_var;
2093 	if (ins) {
2094 		size = 8;
2095 		align = 8;
2096 		offset += align - 1;
2097 		offset &= ~(align - 1);
2098 		ins->opcode = OP_REGOFFSET;
2099 		ins->inst_basereg = cfg->frame_reg;
2100 		ins->inst_offset = offset;
2101 		offset += size;
2102 	}
2103 	ins = cfg->arch.ss_tramp_var;
2104 	if (ins) {
2105 		size = 8;
2106 		align = 8;
2107 		offset += align - 1;
2108 		offset &= ~(align - 1);
2109 		ins->opcode = OP_REGOFFSET;
2110 		ins->inst_basereg = cfg->frame_reg;
2111 		ins->inst_offset = offset;
2112 		offset += size;
2113 	}
2114 	ins = cfg->arch.bp_tramp_var;
2115 	if (ins) {
2116 		size = 8;
2117 		align = 8;
2118 		offset += align - 1;
2119 		offset &= ~(align - 1);
2120 		ins->opcode = OP_REGOFFSET;
2121 		ins->inst_basereg = cfg->frame_reg;
2122 		ins->inst_offset = offset;
2123 		offset += size;
2124 	}
2125 
2126 	/* Locals */
2127 	offsets = mono_allocate_stack_slots (cfg, FALSE, &locals_stack_size, &locals_stack_align);
2128 	if (locals_stack_align)
2129 		offset = ALIGN_TO (offset, locals_stack_align);
2130 
2131 	for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
2132 		if (offsets [i] != -1) {
2133 			ins = cfg->varinfo [i];
2134 			ins->opcode = OP_REGOFFSET;
2135 			ins->inst_basereg = cfg->frame_reg;
2136 			ins->inst_offset = offset + offsets [i];
2137 			//printf ("allocated local %d to ", i); mono_print_tree_nl (ins);
2138 		}
2139 	}
2140 	offset += locals_stack_size;
2141 
2142 	offset = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
2143 
2144 	cfg->stack_offset = offset;
2145 }
2146 
2147 #ifdef ENABLE_LLVM
2148 LLVMCallInfo*
mono_arch_get_llvm_call_info(MonoCompile * cfg,MonoMethodSignature * sig)2149 mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
2150 {
2151 	int i, n;
2152 	CallInfo *cinfo;
2153 	ArgInfo *ainfo;
2154 	LLVMCallInfo *linfo;
2155 
2156 	n = sig->param_count + sig->hasthis;
2157 
2158 	cinfo = get_call_info (cfg->mempool, sig);
2159 
2160 	linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
2161 
2162 	switch (cinfo->ret.storage) {
2163 	case ArgInIReg:
2164 	case ArgInFReg:
2165 	case ArgInFRegR4:
2166 	case ArgNone:
2167 		break;
2168 	case ArgVtypeByRef:
2169 		linfo->ret.storage = LLVMArgVtypeByRef;
2170 		break;
2171 		//
2172 		// FIXME: This doesn't work yet since the llvm backend represents these types as an i8
2173 		// array which is returned in int regs
2174 		//
2175 	case ArgHFA:
2176 		linfo->ret.storage = LLVMArgFpStruct;
2177 		linfo->ret.nslots = cinfo->ret.nregs;
2178 		linfo->ret.esize = cinfo->ret.esize;
2179 		break;
2180 	case ArgVtypeInIRegs:
2181 		/* LLVM models this by returning an int */
2182 		linfo->ret.storage = LLVMArgVtypeAsScalar;
2183 		linfo->ret.nslots = cinfo->ret.nregs;
2184 		linfo->ret.esize = cinfo->ret.esize;
2185 		break;
2186 	default:
2187 		g_assert_not_reached ();
2188 		break;
2189 	}
2190 
2191 	for (i = 0; i < n; ++i) {
2192 		LLVMArgInfo *lainfo = &linfo->args [i];
2193 
2194 		ainfo = cinfo->args + i;
2195 
2196 		lainfo->storage = LLVMArgNone;
2197 
2198 		switch (ainfo->storage) {
2199 		case ArgInIReg:
2200 		case ArgInFReg:
2201 		case ArgInFRegR4:
2202 		case ArgOnStack:
2203 		case ArgOnStackR4:
2204 		case ArgOnStackR8:
2205 			lainfo->storage = LLVMArgNormal;
2206 			break;
2207 		case ArgVtypeByRef:
2208 		case ArgVtypeByRefOnStack:
2209 			lainfo->storage = LLVMArgVtypeByRef;
2210 			break;
2211 		case ArgHFA: {
2212 			int j;
2213 
2214 			lainfo->storage = LLVMArgAsFpArgs;
2215 			lainfo->nslots = ainfo->nregs;
2216 			lainfo->esize = ainfo->esize;
2217 			for (j = 0; j < ainfo->nregs; ++j)
2218 				lainfo->pair_storage [j] = LLVMArgInFPReg;
2219 			break;
2220 		}
2221 		case ArgVtypeInIRegs:
2222 			lainfo->storage = LLVMArgAsIArgs;
2223 			lainfo->nslots = ainfo->nregs;
2224 			break;
2225 		case ArgVtypeOnStack:
2226 			if (ainfo->hfa) {
2227 				int j;
2228 				/* Same as above */
2229 				lainfo->storage = LLVMArgAsFpArgs;
2230 				lainfo->nslots = ainfo->nregs;
2231 				lainfo->esize = ainfo->esize;
2232 				lainfo->ndummy_fpargs = ainfo->nfregs_to_skip;
2233 				for (j = 0; j < ainfo->nregs; ++j)
2234 					lainfo->pair_storage [j] = LLVMArgInFPReg;
2235 			} else {
2236 				lainfo->storage = LLVMArgAsIArgs;
2237 				lainfo->nslots = ainfo->size / 8;
2238 			}
2239 			break;
2240 		default:
2241 			g_assert_not_reached ();
2242 			break;
2243 		}
2244 	}
2245 
2246 	return linfo;
2247 }
2248 #endif
2249 
2250 static void
add_outarg_reg(MonoCompile * cfg,MonoCallInst * call,ArgStorage storage,int reg,MonoInst * arg)2251 add_outarg_reg (MonoCompile *cfg, MonoCallInst *call, ArgStorage storage, int reg, MonoInst *arg)
2252 {
2253 	MonoInst *ins;
2254 
2255 	switch (storage) {
2256 	case ArgInIReg:
2257 		MONO_INST_NEW (cfg, ins, OP_MOVE);
2258 		ins->dreg = mono_alloc_ireg_copy (cfg, arg->dreg);
2259 		ins->sreg1 = arg->dreg;
2260 		MONO_ADD_INS (cfg->cbb, ins);
2261 		mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, FALSE);
2262 		break;
2263 	case ArgInFReg:
2264 		MONO_INST_NEW (cfg, ins, OP_FMOVE);
2265 		ins->dreg = mono_alloc_freg (cfg);
2266 		ins->sreg1 = arg->dreg;
2267 		MONO_ADD_INS (cfg->cbb, ins);
2268 		mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
2269 		break;
2270 	case ArgInFRegR4:
2271 		if (COMPILE_LLVM (cfg))
2272 			MONO_INST_NEW (cfg, ins, OP_FMOVE);
2273 		else if (cfg->r4fp)
2274 			MONO_INST_NEW (cfg, ins, OP_RMOVE);
2275 		else
2276 			MONO_INST_NEW (cfg, ins, OP_ARM_SETFREG_R4);
2277 		ins->dreg = mono_alloc_freg (cfg);
2278 		ins->sreg1 = arg->dreg;
2279 		MONO_ADD_INS (cfg->cbb, ins);
2280 		mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, reg, TRUE);
2281 		break;
2282 	default:
2283 		g_assert_not_reached ();
2284 		break;
2285 	}
2286 }
2287 
2288 static void
emit_sig_cookie(MonoCompile * cfg,MonoCallInst * call,CallInfo * cinfo)2289 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
2290 {
2291 	MonoMethodSignature *tmp_sig;
2292 	int sig_reg;
2293 
2294 	if (call->tail_call)
2295 		NOT_IMPLEMENTED;
2296 
2297 	g_assert (cinfo->sig_cookie.storage == ArgOnStack);
2298 
2299 	/*
2300 	 * mono_ArgIterator_Setup assumes the signature cookie is
2301 	 * passed first and all the arguments which were before it are
2302 	 * passed on the stack after the signature. So compensate by
2303 	 * passing a different signature.
2304 	 */
2305 	tmp_sig = mono_metadata_signature_dup (call->signature);
2306 	tmp_sig->param_count -= call->signature->sentinelpos;
2307 	tmp_sig->sentinelpos = 0;
2308 	memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
2309 
2310 	sig_reg = mono_alloc_ireg (cfg);
2311 	MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig);
2312 
2313 	MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, cinfo->sig_cookie.offset, sig_reg);
2314 }
2315 
2316 void
mono_arch_emit_call(MonoCompile * cfg,MonoCallInst * call)2317 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
2318 {
2319 	MonoMethodSignature *sig;
2320 	MonoInst *arg, *vtarg;
2321 	CallInfo *cinfo;
2322 	ArgInfo *ainfo;
2323 	int i;
2324 
2325 	sig = call->signature;
2326 
2327 	cinfo = get_call_info (cfg->mempool, sig);
2328 
2329 	switch (cinfo->ret.storage) {
2330 	case ArgVtypeInIRegs:
2331 	case ArgHFA:
2332 		/*
2333 		 * The vtype is returned in registers, save the return area address in a local, and save the vtype into
2334 		 * the location pointed to by it after call in emit_move_return_value ().
2335 		 */
2336 		if (!cfg->arch.vret_addr_loc) {
2337 			cfg->arch.vret_addr_loc = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2338 			/* Prevent it from being register allocated or optimized away */
2339 			((MonoInst*)cfg->arch.vret_addr_loc)->flags |= MONO_INST_VOLATILE;
2340 		}
2341 
2342 		MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, ((MonoInst*)cfg->arch.vret_addr_loc)->dreg, call->vret_var->dreg);
2343 		break;
2344 	case ArgVtypeByRef:
2345 		/* Pass the vtype return address in R8 */
2346 		MONO_INST_NEW (cfg, vtarg, OP_MOVE);
2347 		vtarg->sreg1 = call->vret_var->dreg;
2348 		vtarg->dreg = mono_alloc_preg (cfg);
2349 		MONO_ADD_INS (cfg->cbb, vtarg);
2350 
2351 		mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
2352 		break;
2353 	default:
2354 		break;
2355 	}
2356 
2357 	for (i = 0; i < cinfo->nargs; ++i) {
2358 		ainfo = cinfo->args + i;
2359 		arg = call->args [i];
2360 
2361 		if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
2362 			/* Emit the signature cookie just before the implicit arguments */
2363 			emit_sig_cookie (cfg, call, cinfo);
2364 		}
2365 
2366 		switch (ainfo->storage) {
2367 		case ArgInIReg:
2368 		case ArgInFReg:
2369 		case ArgInFRegR4:
2370 			add_outarg_reg (cfg, call, ainfo->storage, ainfo->reg, arg);
2371 			break;
2372 		case ArgOnStack:
2373 			switch (ainfo->slot_size) {
2374 			case 8:
2375 				MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
2376 				break;
2377 			case 4:
2378 				MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
2379 				break;
2380 			case 2:
2381 				MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
2382 				break;
2383 			case 1:
2384 				MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
2385 				break;
2386 			default:
2387 				g_assert_not_reached ();
2388 				break;
2389 			}
2390 			break;
2391 		case ArgOnStackR8:
2392 			MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
2393 			break;
2394 		case ArgOnStackR4:
2395 			MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, ainfo->offset, arg->dreg);
2396 			break;
2397 		case ArgVtypeInIRegs:
2398 		case ArgVtypeByRef:
2399 		case ArgVtypeByRefOnStack:
2400 		case ArgVtypeOnStack:
2401 		case ArgHFA: {
2402 			MonoInst *ins;
2403 			guint32 align;
2404 			guint32 size;
2405 
2406 			size = mono_class_value_size (arg->klass, &align);
2407 
2408 			MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
2409 			ins->sreg1 = arg->dreg;
2410 			ins->klass = arg->klass;
2411 			ins->backend.size = size;
2412 			ins->inst_p0 = call;
2413 			ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
2414 			memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
2415 			MONO_ADD_INS (cfg->cbb, ins);
2416 			break;
2417 		}
2418 		default:
2419 			g_assert_not_reached ();
2420 			break;
2421 		}
2422 	}
2423 
2424 	/* Handle the case where there are no implicit arguments */
2425 	if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (cinfo->nargs == sig->sentinelpos))
2426 		emit_sig_cookie (cfg, call, cinfo);
2427 
2428 	call->call_info = cinfo;
2429 	call->stack_usage = cinfo->stack_usage;
2430 }
2431 
2432 void
mono_arch_emit_outarg_vt(MonoCompile * cfg,MonoInst * ins,MonoInst * src)2433 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
2434 {
2435 	MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
2436 	ArgInfo *ainfo = ins->inst_p1;
2437 	MonoInst *load;
2438 	int i;
2439 
2440 	if (ins->backend.size == 0 && !ainfo->gsharedvt)
2441 		return;
2442 
2443 	switch (ainfo->storage) {
2444 	case ArgVtypeInIRegs:
2445 		for (i = 0; i < ainfo->nregs; ++i) {
2446 			// FIXME: Smaller sizes
2447 			MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
2448 			load->dreg = mono_alloc_ireg (cfg);
2449 			load->inst_basereg = src->dreg;
2450 			load->inst_offset = i * sizeof(mgreg_t);
2451 			MONO_ADD_INS (cfg->cbb, load);
2452 			add_outarg_reg (cfg, call, ArgInIReg, ainfo->reg + i, load);
2453 		}
2454 		break;
2455 	case ArgHFA:
2456 		for (i = 0; i < ainfo->nregs; ++i) {
2457 			if (ainfo->esize == 4)
2458 				MONO_INST_NEW (cfg, load, OP_LOADR4_MEMBASE);
2459 			else
2460 				MONO_INST_NEW (cfg, load, OP_LOADR8_MEMBASE);
2461 			load->dreg = mono_alloc_freg (cfg);
2462 			load->inst_basereg = src->dreg;
2463 			load->inst_offset = ainfo->foffsets [i];
2464 			MONO_ADD_INS (cfg->cbb, load);
2465 			add_outarg_reg (cfg, call, ainfo->esize == 4 ? ArgInFRegR4 : ArgInFReg, ainfo->reg + i, load);
2466 		}
2467 		break;
2468 	case ArgVtypeByRef:
2469 	case ArgVtypeByRefOnStack: {
2470 		MonoInst *vtaddr, *load, *arg;
2471 
2472 		/* Pass the vtype address in a reg/on the stack */
2473 		if (ainfo->gsharedvt) {
2474 			load = src;
2475 		} else {
2476 			/* Make a copy of the argument */
2477 			vtaddr = mono_compile_create_var (cfg, &ins->klass->byval_arg, OP_LOCAL);
2478 
2479 			MONO_INST_NEW (cfg, load, OP_LDADDR);
2480 			load->inst_p0 = vtaddr;
2481 			vtaddr->flags |= MONO_INST_INDIRECT;
2482 			load->type = STACK_MP;
2483 			load->klass = vtaddr->klass;
2484 			load->dreg = mono_alloc_ireg (cfg);
2485 			MONO_ADD_INS (cfg->cbb, load);
2486 			mini_emit_memcpy (cfg, load->dreg, 0, src->dreg, 0, ainfo->size, 8);
2487 		}
2488 
2489 		if (ainfo->storage == ArgVtypeByRef) {
2490 			MONO_INST_NEW (cfg, arg, OP_MOVE);
2491 			arg->dreg = mono_alloc_preg (cfg);
2492 			arg->sreg1 = load->dreg;
2493 			MONO_ADD_INS (cfg->cbb, arg);
2494 			add_outarg_reg (cfg, call, ArgInIReg, ainfo->reg, arg);
2495 		} else {
2496 			MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, load->dreg);
2497 		}
2498 		break;
2499 	}
2500 	case ArgVtypeOnStack:
2501 		for (i = 0; i < ainfo->size / 8; ++i) {
2502 			MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE);
2503 			load->dreg = mono_alloc_ireg (cfg);
2504 			load->inst_basereg = src->dreg;
2505 			load->inst_offset = i * 8;
2506 			MONO_ADD_INS (cfg->cbb, load);
2507 			MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ARMREG_SP, ainfo->offset + (i * 8), load->dreg);
2508 		}
2509 		break;
2510 	default:
2511 		g_assert_not_reached ();
2512 		break;
2513 	}
2514 }
2515 
2516 void
mono_arch_emit_setret(MonoCompile * cfg,MonoMethod * method,MonoInst * val)2517 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
2518 {
2519 	MonoMethodSignature *sig;
2520 	CallInfo *cinfo;
2521 
2522 	sig = mono_method_signature (cfg->method);
2523 	if (!cfg->arch.cinfo)
2524 		cfg->arch.cinfo = get_call_info (cfg->mempool, sig);
2525 	cinfo = cfg->arch.cinfo;
2526 
2527 	switch (cinfo->ret.storage) {
2528 	case ArgNone:
2529 		break;
2530 	case ArgInIReg:
2531 		MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
2532 		break;
2533 	case ArgInFReg:
2534 		MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
2535 		break;
2536 	case ArgInFRegR4:
2537 		if (COMPILE_LLVM (cfg))
2538 			MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
2539 		else if (cfg->r4fp)
2540 			MONO_EMIT_NEW_UNALU (cfg, OP_RMOVE, cfg->ret->dreg, val->dreg);
2541 		else
2542 			MONO_EMIT_NEW_UNALU (cfg, OP_ARM_SETFREG_R4, cfg->ret->dreg, val->dreg);
2543 		break;
2544 	default:
2545 		g_assert_not_reached ();
2546 		break;
2547 	}
2548 }
2549 
2550 gboolean
mono_arch_tail_call_supported(MonoCompile * cfg,MonoMethodSignature * caller_sig,MonoMethodSignature * callee_sig)2551 mono_arch_tail_call_supported (MonoCompile *cfg, MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
2552 {
2553 	CallInfo *c1, *c2;
2554 	gboolean res;
2555 
2556 	if (cfg->compile_aot && !cfg->full_aot)
2557 		/* OP_TAILCALL doesn't work with AOT */
2558 		return FALSE;
2559 
2560 	c1 = get_call_info (NULL, caller_sig);
2561 	c2 = get_call_info (NULL, callee_sig);
2562 	res = TRUE;
2563 	// FIXME: Relax these restrictions
2564 	if (c1->stack_usage != 0)
2565 		res = FALSE;
2566 	if (c1->stack_usage != c2->stack_usage)
2567 		res = FALSE;
2568 	if ((c1->ret.storage != ArgNone && c1->ret.storage != ArgInIReg) || c1->ret.storage != c2->ret.storage)
2569 		res = FALSE;
2570 
2571 	g_free (c1);
2572 	g_free (c2);
2573 
2574 	return res;
2575 }
2576 
2577 gboolean
mono_arch_is_inst_imm(gint64 imm)2578 mono_arch_is_inst_imm (gint64 imm)
2579 {
2580 	return (imm >= -((gint64)1<<31) && imm <= (((gint64)1<<31)-1));
2581 }
2582 
2583 void*
mono_arch_instrument_prolog(MonoCompile * cfg,void * func,void * p,gboolean enable_arguments)2584 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
2585 {
2586 	NOT_IMPLEMENTED;
2587 	return NULL;
2588 }
2589 
2590 void*
mono_arch_instrument_epilog_full(MonoCompile * cfg,void * func,void * p,gboolean enable_arguments,gboolean preserve_argument_registers)2591 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
2592 {
2593 	NOT_IMPLEMENTED;
2594 	return NULL;
2595 }
2596 
2597 void
mono_arch_peephole_pass_1(MonoCompile * cfg,MonoBasicBlock * bb)2598 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2599 {
2600 	//NOT_IMPLEMENTED;
2601 }
2602 
2603 void
mono_arch_peephole_pass_2(MonoCompile * cfg,MonoBasicBlock * bb)2604 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2605 {
2606 	//NOT_IMPLEMENTED;
2607 }
2608 
2609 #define ADD_NEW_INS(cfg,dest,op) do {       \
2610 		MONO_INST_NEW ((cfg), (dest), (op)); \
2611         mono_bblock_insert_before_ins (bb, ins, (dest)); \
2612 	} while (0)
2613 
2614 void
mono_arch_lowering_pass(MonoCompile * cfg,MonoBasicBlock * bb)2615 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2616 {
2617 	MonoInst *ins, *temp, *last_ins = NULL;
2618 
2619 	MONO_BB_FOR_EACH_INS (bb, ins) {
2620 		switch (ins->opcode) {
2621 		case OP_SBB:
2622 		case OP_ISBB:
2623 		case OP_SUBCC:
2624 		case OP_ISUBCC:
2625 			if (ins->next  && (ins->next->opcode == OP_COND_EXC_C || ins->next->opcode == OP_COND_EXC_IC))
2626 				/* ARM sets the C flag to 1 if there was _no_ overflow */
2627 				ins->next->opcode = OP_COND_EXC_NC;
2628 			break;
2629 		case OP_IDIV_IMM:
2630 		case OP_IREM_IMM:
2631 		case OP_IDIV_UN_IMM:
2632 		case OP_IREM_UN_IMM:
2633 		case OP_LREM_IMM:
2634 			mono_decompose_op_imm (cfg, bb, ins);
2635 			break;
2636 		case OP_LOCALLOC_IMM:
2637 			if (ins->inst_imm > 32) {
2638 				ADD_NEW_INS (cfg, temp, OP_ICONST);
2639 				temp->inst_c0 = ins->inst_imm;
2640 				temp->dreg = mono_alloc_ireg (cfg);
2641 				ins->sreg1 = temp->dreg;
2642 				ins->opcode = mono_op_imm_to_op (ins->opcode);
2643 			}
2644 			break;
2645 		case OP_ICOMPARE_IMM:
2646 			if (ins->inst_imm == 0 && ins->next && ins->next->opcode == OP_IBEQ) {
2647 				ins->next->opcode = OP_ARM64_CBZW;
2648 				ins->next->sreg1 = ins->sreg1;
2649 				NULLIFY_INS (ins);
2650 			} else if (ins->inst_imm == 0 && ins->next && ins->next->opcode == OP_IBNE_UN) {
2651 				ins->next->opcode = OP_ARM64_CBNZW;
2652 				ins->next->sreg1 = ins->sreg1;
2653 				NULLIFY_INS (ins);
2654 			}
2655 			break;
2656 		case OP_LCOMPARE_IMM:
2657 		case OP_COMPARE_IMM:
2658 			if (ins->inst_imm == 0 && ins->next && ins->next->opcode == OP_LBEQ) {
2659 				ins->next->opcode = OP_ARM64_CBZX;
2660 				ins->next->sreg1 = ins->sreg1;
2661 				NULLIFY_INS (ins);
2662 			} else if (ins->inst_imm == 0 && ins->next && ins->next->opcode == OP_LBNE_UN) {
2663 				ins->next->opcode = OP_ARM64_CBNZX;
2664 				ins->next->sreg1 = ins->sreg1;
2665 				NULLIFY_INS (ins);
2666 			}
2667 			break;
2668 		case OP_FCOMPARE: {
2669 			gboolean swap = FALSE;
2670 			int reg;
2671 
2672 			if (!ins->next) {
2673 				/* Optimized away */
2674 				NULLIFY_INS (ins);
2675 				break;
2676 			}
2677 
2678 			/*
2679 			 * FP compares with unordered operands set the flags
2680 			 * to NZCV=0011, which matches some non-unordered compares
2681 			 * as well, like LE, so have to swap the operands.
2682 			 */
2683 			switch (ins->next->opcode) {
2684 			case OP_FBLT:
2685 				ins->next->opcode = OP_FBGT;
2686 				swap = TRUE;
2687 				break;
2688 			case OP_FBLE:
2689 				ins->next->opcode = OP_FBGE;
2690 				swap = TRUE;
2691 				break;
2692 			default:
2693 				break;
2694 			}
2695 			if (swap) {
2696 				reg = ins->sreg1;
2697 				ins->sreg1 = ins->sreg2;
2698 				ins->sreg2 = reg;
2699 			}
2700 			break;
2701 		}
2702 		default:
2703 			break;
2704 		}
2705 
2706 		last_ins = ins;
2707 	}
2708 	bb->last_ins = last_ins;
2709 	bb->max_vreg = cfg->next_vreg;
2710 }
2711 
2712 void
mono_arch_decompose_long_opts(MonoCompile * cfg,MonoInst * long_ins)2713 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
2714 {
2715 }
2716 
2717 static int
opcode_to_armcond(int opcode)2718 opcode_to_armcond (int opcode)
2719 {
2720 	switch (opcode) {
2721 	case OP_IBEQ:
2722 	case OP_LBEQ:
2723 	case OP_FBEQ:
2724 	case OP_CEQ:
2725 	case OP_ICEQ:
2726 	case OP_LCEQ:
2727 	case OP_FCEQ:
2728 	case OP_RCEQ:
2729 	case OP_COND_EXC_IEQ:
2730 	case OP_COND_EXC_EQ:
2731 		return ARMCOND_EQ;
2732 	case OP_IBGE:
2733 	case OP_LBGE:
2734 	case OP_FBGE:
2735 	case OP_ICGE:
2736 	case OP_FCGE:
2737 	case OP_RCGE:
2738 		return ARMCOND_GE;
2739 	case OP_IBGT:
2740 	case OP_LBGT:
2741 	case OP_FBGT:
2742 	case OP_CGT:
2743 	case OP_ICGT:
2744 	case OP_LCGT:
2745 	case OP_FCGT:
2746 	case OP_RCGT:
2747 	case OP_COND_EXC_IGT:
2748 	case OP_COND_EXC_GT:
2749 		return ARMCOND_GT;
2750 	case OP_IBLE:
2751 	case OP_LBLE:
2752 	case OP_FBLE:
2753 	case OP_ICLE:
2754 	case OP_FCLE:
2755 	case OP_RCLE:
2756 		return ARMCOND_LE;
2757 	case OP_IBLT:
2758 	case OP_LBLT:
2759 	case OP_FBLT:
2760 	case OP_CLT:
2761 	case OP_ICLT:
2762 	case OP_LCLT:
2763 	case OP_COND_EXC_ILT:
2764 	case OP_COND_EXC_LT:
2765 		return ARMCOND_LT;
2766 	case OP_IBNE_UN:
2767 	case OP_LBNE_UN:
2768 	case OP_FBNE_UN:
2769 	case OP_ICNEQ:
2770 	case OP_FCNEQ:
2771 	case OP_RCNEQ:
2772 	case OP_COND_EXC_INE_UN:
2773 	case OP_COND_EXC_NE_UN:
2774 		return ARMCOND_NE;
2775 	case OP_IBGE_UN:
2776 	case OP_LBGE_UN:
2777 	case OP_FBGE_UN:
2778 	case OP_ICGE_UN:
2779 	case OP_COND_EXC_IGE_UN:
2780 	case OP_COND_EXC_GE_UN:
2781 		return ARMCOND_HS;
2782 	case OP_IBGT_UN:
2783 	case OP_LBGT_UN:
2784 	case OP_FBGT_UN:
2785 	case OP_CGT_UN:
2786 	case OP_ICGT_UN:
2787 	case OP_LCGT_UN:
2788 	case OP_FCGT_UN:
2789 	case OP_RCGT_UN:
2790 	case OP_COND_EXC_IGT_UN:
2791 	case OP_COND_EXC_GT_UN:
2792 		return ARMCOND_HI;
2793 	case OP_IBLE_UN:
2794 	case OP_LBLE_UN:
2795 	case OP_FBLE_UN:
2796 	case OP_ICLE_UN:
2797 	case OP_COND_EXC_ILE_UN:
2798 	case OP_COND_EXC_LE_UN:
2799 		return ARMCOND_LS;
2800 	case OP_IBLT_UN:
2801 	case OP_LBLT_UN:
2802 	case OP_FBLT_UN:
2803 	case OP_CLT_UN:
2804 	case OP_ICLT_UN:
2805 	case OP_LCLT_UN:
2806 	case OP_COND_EXC_ILT_UN:
2807 	case OP_COND_EXC_LT_UN:
2808 		return ARMCOND_LO;
2809 		/*
2810 		 * FCMP sets the NZCV condition bits as follows:
2811 		 * eq = 0110
2812 		 * < = 1000
2813 		 * > = 0010
2814 		 * unordered = 0011
2815 		 * ARMCOND_LT is N!=V, so it matches unordered too, so
2816 		 * fclt and fclt_un need to be special cased.
2817 		 */
2818 	case OP_FCLT:
2819 	case OP_RCLT:
2820 		/* N==1 */
2821 		return ARMCOND_MI;
2822 	case OP_FCLT_UN:
2823 	case OP_RCLT_UN:
2824 		return ARMCOND_LT;
2825 	case OP_COND_EXC_C:
2826 	case OP_COND_EXC_IC:
2827 		return ARMCOND_CS;
2828 	case OP_COND_EXC_OV:
2829 	case OP_COND_EXC_IOV:
2830 		return ARMCOND_VS;
2831 	case OP_COND_EXC_NC:
2832 	case OP_COND_EXC_INC:
2833 		return ARMCOND_CC;
2834 	case OP_COND_EXC_NO:
2835 	case OP_COND_EXC_INO:
2836 		return ARMCOND_VC;
2837 	default:
2838 		printf ("%s\n", mono_inst_name (opcode));
2839 		g_assert_not_reached ();
2840 		return -1;
2841 	}
2842 }
2843 
2844 /* This clobbers LR */
2845 static inline __attribute__ ((__warn_unused_result__)) guint8*
emit_cond_exc(MonoCompile * cfg,guint8 * code,int opcode,const char * exc_name)2846 emit_cond_exc (MonoCompile *cfg, guint8 *code, int opcode, const char *exc_name)
2847 {
2848 	int cond;
2849 
2850 	cond = opcode_to_armcond (opcode);
2851 	/* Capture PC */
2852 	arm_adrx (code, ARMREG_IP1, code);
2853 	mono_add_patch_info_rel (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, exc_name, MONO_R_ARM64_BCC);
2854 	arm_bcc (code, cond, 0);
2855 	return code;
2856 }
2857 
2858 static guint8*
emit_move_return_value(MonoCompile * cfg,guint8 * code,MonoInst * ins)2859 emit_move_return_value (MonoCompile *cfg, guint8 * code, MonoInst *ins)
2860 {
2861 	CallInfo *cinfo;
2862 	MonoCallInst *call;
2863 
2864 	call = (MonoCallInst*)ins;
2865 	cinfo = call->call_info;
2866 	g_assert (cinfo);
2867 	switch (cinfo->ret.storage) {
2868 	case ArgNone:
2869 		break;
2870 	case ArgInIReg:
2871 		/* LLVM compiled code might only set the bottom bits */
2872 		if (call->signature && mini_get_underlying_type (call->signature->ret)->type == MONO_TYPE_I4)
2873 			arm_sxtwx (code, call->inst.dreg, cinfo->ret.reg);
2874 		else if (call->inst.dreg != cinfo->ret.reg)
2875 			arm_movx (code, call->inst.dreg, cinfo->ret.reg);
2876 		break;
2877 	case ArgInFReg:
2878 		if (call->inst.dreg != cinfo->ret.reg)
2879 			arm_fmovd (code, call->inst.dreg, cinfo->ret.reg);
2880 		break;
2881 	case ArgInFRegR4:
2882 		if (cfg->r4fp)
2883 			arm_fmovs (code, call->inst.dreg, cinfo->ret.reg);
2884 		else
2885 			arm_fcvt_sd (code, call->inst.dreg, cinfo->ret.reg);
2886 		break;
2887 	case ArgVtypeInIRegs: {
2888 		MonoInst *loc = cfg->arch.vret_addr_loc;
2889 		int i;
2890 
2891 		/* Load the destination address */
2892 		g_assert (loc && loc->opcode == OP_REGOFFSET);
2893 		code = emit_ldrx (code, ARMREG_LR, loc->inst_basereg, loc->inst_offset);
2894 		for (i = 0; i < cinfo->ret.nregs; ++i)
2895 			arm_strx (code, cinfo->ret.reg + i, ARMREG_LR, i * 8);
2896 		break;
2897 	}
2898 	case ArgHFA: {
2899 		MonoInst *loc = cfg->arch.vret_addr_loc;
2900 		int i;
2901 
2902 		/* Load the destination address */
2903 		g_assert (loc && loc->opcode == OP_REGOFFSET);
2904 		code = emit_ldrx (code, ARMREG_LR, loc->inst_basereg, loc->inst_offset);
2905 		for (i = 0; i < cinfo->ret.nregs; ++i) {
2906 			if (cinfo->ret.esize == 4)
2907 				arm_strfpw (code, cinfo->ret.reg + i, ARMREG_LR, cinfo->ret.foffsets [i]);
2908 			else
2909 				arm_strfpx (code, cinfo->ret.reg + i, ARMREG_LR, cinfo->ret.foffsets [i]);
2910 		}
2911 		break;
2912 	}
2913 	case ArgVtypeByRef:
2914 		break;
2915 	default:
2916 		g_assert_not_reached ();
2917 		break;
2918 	}
2919 	return code;
2920 }
2921 
2922 /*
2923  * emit_branch_island:
2924  *
2925  *   Emit a branch island for the conditional branches from cfg->native_code + start_offset to code.
2926  */
2927 static guint8*
emit_branch_island(MonoCompile * cfg,guint8 * code,int start_offset)2928 emit_branch_island (MonoCompile *cfg, guint8 *code, int start_offset)
2929 {
2930 	MonoJumpInfo *ji;
2931 	int offset, island_size;
2932 
2933 	/* Iterate over the patch infos added so far by this bb */
2934 	island_size = 0;
2935 	for (ji = cfg->patch_info; ji; ji = ji->next) {
2936 		if (ji->ip.i < start_offset)
2937 			/* The patch infos are in reverse order, so this means the end */
2938 			break;
2939 		if (ji->relocation == MONO_R_ARM64_BCC || ji->relocation == MONO_R_ARM64_CBZ)
2940 			island_size += 4;
2941 	}
2942 
2943 	if (island_size) {
2944 		offset = code - cfg->native_code;
2945 		if (offset > (cfg->code_size - island_size - 16)) {
2946 			cfg->code_size *= 2;
2947 			cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2948 			code = cfg->native_code + offset;
2949 		}
2950 
2951 		/* Branch over the island */
2952 		arm_b (code, code + 4 + island_size);
2953 
2954 		for (ji = cfg->patch_info; ji; ji = ji->next) {
2955 			if (ji->ip.i < start_offset)
2956 				break;
2957 			if (ji->relocation == MONO_R_ARM64_BCC || ji->relocation == MONO_R_ARM64_CBZ) {
2958 				/* Rewrite the cond branch so it branches to an uncoditional branch in the branch island */
2959 				arm_patch_rel (cfg->native_code + ji->ip.i, code, ji->relocation);
2960 				/* Rewrite the patch so it points to the unconditional branch */
2961 				ji->ip.i = code - cfg->native_code;
2962 				ji->relocation = MONO_R_ARM64_B;
2963 				arm_b (code, code);
2964 			}
2965 		}
2966 	}
2967 	return code;
2968 }
2969 
2970 void
mono_arch_output_basic_block(MonoCompile * cfg,MonoBasicBlock * bb)2971 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2972 {
2973 	MonoInst *ins;
2974 	MonoCallInst *call;
2975 	guint offset;
2976 	guint8 *code = cfg->native_code + cfg->code_len;
2977 	int start_offset, max_len, dreg, sreg1, sreg2;
2978 	mgreg_t imm;
2979 
2980 	if (cfg->verbose_level > 2)
2981 		g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2982 
2983 	start_offset = code - cfg->native_code;
2984 
2985 	MONO_BB_FOR_EACH_INS (bb, ins) {
2986 		offset = code - cfg->native_code;
2987 
2988 		max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2989 
2990 		if (offset > (cfg->code_size - max_len - 16)) {
2991 			cfg->code_size *= 2;
2992 			cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2993 			code = cfg->native_code + offset;
2994 		}
2995 
2996 		if (G_UNLIKELY (cfg->arch.cond_branch_islands && offset - start_offset > 4 * 0x1ffff)) {
2997 			/* Emit a branch island for large basic blocks */
2998 			code = emit_branch_island (cfg, code, start_offset);
2999 			offset = code - cfg->native_code;
3000 			start_offset = offset;
3001 		}
3002 
3003 		mono_debug_record_line_number (cfg, ins, offset);
3004 
3005 		dreg = ins->dreg;
3006 		sreg1 = ins->sreg1;
3007 		sreg2 = ins->sreg2;
3008 		imm = ins->inst_imm;
3009 
3010 		switch (ins->opcode) {
3011 		case OP_ICONST:
3012 			code = emit_imm (code, dreg, ins->inst_c0);
3013 			break;
3014 		case OP_I8CONST:
3015 			code = emit_imm64 (code, dreg, ins->inst_c0);
3016 			break;
3017 		case OP_MOVE:
3018 			if (dreg != sreg1)
3019 				arm_movx (code, dreg, sreg1);
3020 			break;
3021 		case OP_NOP:
3022 		case OP_RELAXED_NOP:
3023 			break;
3024 		case OP_JUMP_TABLE:
3025 			mono_add_patch_info_rel (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0, MONO_R_ARM64_IMM);
3026 			code = emit_imm64_template (code, dreg);
3027 			break;
3028 		case OP_BREAK:
3029 			/*
3030 			 * gdb does not like encountering the hw breakpoint ins in the debugged code.
3031 			 * So instead of emitting a trap, we emit a call a C function and place a
3032 			 * breakpoint there.
3033 			 */
3034 			code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_break");
3035 			break;
3036 		case OP_LOCALLOC: {
3037 			guint8 *buf [16];
3038 
3039 			arm_addx_imm (code, ARMREG_IP0, sreg1, (MONO_ARCH_FRAME_ALIGNMENT - 1));
3040 			// FIXME: andx_imm doesn't work yet
3041 			code = emit_imm (code, ARMREG_IP1, -MONO_ARCH_FRAME_ALIGNMENT);
3042 			arm_andx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
3043 			//arm_andx_imm (code, ARMREG_IP0, sreg1, - MONO_ARCH_FRAME_ALIGNMENT);
3044 			arm_movspx (code, ARMREG_IP1, ARMREG_SP);
3045 			arm_subx (code, ARMREG_IP1, ARMREG_IP1, ARMREG_IP0);
3046 			arm_movspx (code, ARMREG_SP, ARMREG_IP1);
3047 
3048 			/* Init */
3049 			/* ip1 = pointer, ip0 = end */
3050 			arm_addx (code, ARMREG_IP0, ARMREG_IP1, ARMREG_IP0);
3051 			buf [0] = code;
3052 			arm_cmpx (code, ARMREG_IP1, ARMREG_IP0);
3053 			buf [1] = code;
3054 			arm_bcc (code, ARMCOND_EQ, 0);
3055 			arm_stpx (code, ARMREG_RZR, ARMREG_RZR, ARMREG_IP1, 0);
3056 			arm_addx_imm (code, ARMREG_IP1, ARMREG_IP1, 16);
3057 			arm_b (code, buf [0]);
3058 			arm_patch_rel (buf [1], code, MONO_R_ARM64_BCC);
3059 
3060 			arm_movspx (code, dreg, ARMREG_SP);
3061 			if (cfg->param_area)
3062 				code = emit_subx_sp_imm (code, cfg->param_area);
3063 			break;
3064 		}
3065 		case OP_LOCALLOC_IMM: {
3066 			int imm, offset;
3067 
3068 			imm = ALIGN_TO (ins->inst_imm, MONO_ARCH_FRAME_ALIGNMENT);
3069 			g_assert (arm_is_arith_imm (imm));
3070 			arm_subx_imm (code, ARMREG_SP, ARMREG_SP, imm);
3071 
3072 			/* Init */
3073 			g_assert (MONO_ARCH_FRAME_ALIGNMENT == 16);
3074 			offset = 0;
3075 			while (offset < imm) {
3076 				arm_stpx (code, ARMREG_RZR, ARMREG_RZR, ARMREG_SP, offset);
3077 				offset += 16;
3078 			}
3079 			arm_movspx (code, dreg, ARMREG_SP);
3080 			if (cfg->param_area)
3081 				code = emit_subx_sp_imm (code, cfg->param_area);
3082 			break;
3083 		}
3084 		case OP_AOTCONST:
3085 			code = emit_aotconst (cfg, code, dreg, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3086 			break;
3087 		case OP_OBJC_GET_SELECTOR:
3088 			mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_OBJC_SELECTOR_REF, ins->inst_p0);
3089 			/* See arch_emit_objc_selector_ref () in aot-compiler.c */
3090 			arm_ldrx_lit (code, ins->dreg, 0);
3091 			arm_nop (code);
3092 			arm_nop (code);
3093 			break;
3094 		case OP_SEQ_POINT: {
3095 			MonoInst *info_var = cfg->arch.seq_point_info_var;
3096 
3097 			/*
3098 			 * For AOT, we use one got slot per method, which will point to a
3099 			 * SeqPointInfo structure, containing all the information required
3100 			 * by the code below.
3101 			 */
3102 			if (cfg->compile_aot) {
3103 				g_assert (info_var);
3104 				g_assert (info_var->opcode == OP_REGOFFSET);
3105 			}
3106 
3107 			if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3108 				MonoInst *var = cfg->arch.ss_tramp_var;
3109 
3110 				g_assert (var);
3111 				g_assert (var->opcode == OP_REGOFFSET);
3112 				/* Load ss_tramp_var */
3113 				/* This is equal to &ss_trampoline */
3114 				arm_ldrx (code, ARMREG_IP1, var->inst_basereg, var->inst_offset);
3115 				/* Load the trampoline address */
3116 				arm_ldrx (code, ARMREG_IP1, ARMREG_IP1, 0);
3117 				/* Call it if it is non-null */
3118 				arm_cbzx (code, ARMREG_IP1, code + 8);
3119 				arm_blrx (code, ARMREG_IP1);
3120 			}
3121 
3122 			mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3123 
3124 			if (cfg->compile_aot) {
3125 				guint32 offset = code - cfg->native_code;
3126 				guint32 val;
3127 
3128 				arm_ldrx (code, ARMREG_IP1, info_var->inst_basereg, info_var->inst_offset);
3129 				/* Add the offset */
3130 				val = ((offset / 4) * sizeof (guint8*)) + MONO_STRUCT_OFFSET (SeqPointInfo, bp_addrs);
3131 				/* Load the info->bp_addrs [offset], which is either 0 or the address of the bp trampoline */
3132 				code = emit_ldrx (code, ARMREG_IP1, ARMREG_IP1, val);
3133 				/* Skip the load if its 0 */
3134 				arm_cbzx (code, ARMREG_IP1, code + 8);
3135 				/* Call the breakpoint trampoline */
3136 				arm_blrx (code, ARMREG_IP1);
3137 			} else {
3138 				MonoInst *var = cfg->arch.bp_tramp_var;
3139 
3140 				g_assert (var);
3141 				g_assert (var->opcode == OP_REGOFFSET);
3142 				/* Load the address of the bp trampoline into IP0 */
3143 				arm_ldrx (code, ARMREG_IP0, var->inst_basereg, var->inst_offset);
3144 				/*
3145 				 * A placeholder for a possible breakpoint inserted by
3146 				 * mono_arch_set_breakpoint ().
3147 				 */
3148 				arm_nop (code);
3149 			}
3150 			break;
3151 		}
3152 
3153 			/* BRANCH */
3154 		case OP_BR:
3155 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb, MONO_R_ARM64_B);
3156 			arm_b (code, code);
3157 			break;
3158 		case OP_BR_REG:
3159 			arm_brx (code, sreg1);
3160 			break;
3161 		case OP_IBEQ:
3162 		case OP_IBGE:
3163 		case OP_IBGT:
3164 		case OP_IBLE:
3165 		case OP_IBLT:
3166 		case OP_IBNE_UN:
3167 		case OP_IBGE_UN:
3168 		case OP_IBGT_UN:
3169 		case OP_IBLE_UN:
3170 		case OP_IBLT_UN:
3171 		case OP_LBEQ:
3172 		case OP_LBGE:
3173 		case OP_LBGT:
3174 		case OP_LBLE:
3175 		case OP_LBLT:
3176 		case OP_LBNE_UN:
3177 		case OP_LBGE_UN:
3178 		case OP_LBGT_UN:
3179 		case OP_LBLE_UN:
3180 		case OP_LBLT_UN:
3181 		case OP_FBEQ:
3182 		case OP_FBNE_UN:
3183 		case OP_FBLT:
3184 		case OP_FBGT:
3185 		case OP_FBGT_UN:
3186 		case OP_FBLE:
3187 		case OP_FBGE:
3188 		case OP_FBGE_UN: {
3189 			int cond;
3190 
3191 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_BCC);
3192 			cond = opcode_to_armcond (ins->opcode);
3193 			arm_bcc (code, cond, 0);
3194 			break;
3195 		}
3196 		case OP_FBLT_UN:
3197 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_BCC);
3198 			/* For fp compares, ARMCOND_LT is lt or unordered */
3199 			arm_bcc (code, ARMCOND_LT, 0);
3200 			break;
3201 		case OP_FBLE_UN:
3202 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_BCC);
3203 			arm_bcc (code, ARMCOND_EQ, 0);
3204 			offset = code - cfg->native_code;
3205 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_BCC);
3206 			/* For fp compares, ARMCOND_LT is lt or unordered */
3207 			arm_bcc (code, ARMCOND_LT, 0);
3208 			break;
3209 		case OP_ARM64_CBZW:
3210 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_CBZ);
3211 			arm_cbzw (code, sreg1, 0);
3212 			break;
3213 		case OP_ARM64_CBZX:
3214 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_CBZ);
3215 			arm_cbzx (code, sreg1, 0);
3216 			break;
3217 		case OP_ARM64_CBNZW:
3218 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_CBZ);
3219 			arm_cbnzw (code, sreg1, 0);
3220 			break;
3221 		case OP_ARM64_CBNZX:
3222 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_true_bb, MONO_R_ARM64_CBZ);
3223 			arm_cbnzx (code, sreg1, 0);
3224 			break;
3225 			/* ALU */
3226 		case OP_IADD:
3227 			arm_addw (code, dreg, sreg1, sreg2);
3228 			break;
3229 		case OP_LADD:
3230 			arm_addx (code, dreg, sreg1, sreg2);
3231 			break;
3232 		case OP_ISUB:
3233 			arm_subw (code, dreg, sreg1, sreg2);
3234 			break;
3235 		case OP_LSUB:
3236 			arm_subx (code, dreg, sreg1, sreg2);
3237 			break;
3238 		case OP_IAND:
3239 			arm_andw (code, dreg, sreg1, sreg2);
3240 			break;
3241 		case OP_LAND:
3242 			arm_andx (code, dreg, sreg1, sreg2);
3243 			break;
3244 		case OP_IOR:
3245 			arm_orrw (code, dreg, sreg1, sreg2);
3246 			break;
3247 		case OP_LOR:
3248 			arm_orrx (code, dreg, sreg1, sreg2);
3249 			break;
3250 		case OP_IXOR:
3251 			arm_eorw (code, dreg, sreg1, sreg2);
3252 			break;
3253 		case OP_LXOR:
3254 			arm_eorx (code, dreg, sreg1, sreg2);
3255 			break;
3256 		case OP_INEG:
3257 			arm_negw (code, dreg, sreg1);
3258 			break;
3259 		case OP_LNEG:
3260 			arm_negx (code, dreg, sreg1);
3261 			break;
3262 		case OP_INOT:
3263 			arm_mvnw (code, dreg, sreg1);
3264 			break;
3265 		case OP_LNOT:
3266 			arm_mvnx (code, dreg, sreg1);
3267 			break;
3268 		case OP_IADDCC:
3269 			arm_addsw (code, dreg, sreg1, sreg2);
3270 			break;
3271 		case OP_ADDCC:
3272 		case OP_LADDCC:
3273 			arm_addsx (code, dreg, sreg1, sreg2);
3274 			break;
3275 		case OP_ISUBCC:
3276 			arm_subsw (code, dreg, sreg1, sreg2);
3277 			break;
3278 		case OP_LSUBCC:
3279 		case OP_SUBCC:
3280 			arm_subsx (code, dreg, sreg1, sreg2);
3281 			break;
3282 		case OP_ICOMPARE:
3283 			arm_cmpw (code, sreg1, sreg2);
3284 			break;
3285 		case OP_COMPARE:
3286 		case OP_LCOMPARE:
3287 			arm_cmpx (code, sreg1, sreg2);
3288 			break;
3289 		case OP_IADD_IMM:
3290 			code = emit_addw_imm (code, dreg, sreg1, imm);
3291 			break;
3292 		case OP_LADD_IMM:
3293 		case OP_ADD_IMM:
3294 			code = emit_addx_imm (code, dreg, sreg1, imm);
3295 			break;
3296 		case OP_ISUB_IMM:
3297 			code = emit_subw_imm (code, dreg, sreg1, imm);
3298 			break;
3299 		case OP_LSUB_IMM:
3300 			code = emit_subx_imm (code, dreg, sreg1, imm);
3301 			break;
3302 		case OP_IAND_IMM:
3303 			code = emit_andw_imm (code, dreg, sreg1, imm);
3304 			break;
3305 		case OP_LAND_IMM:
3306 		case OP_AND_IMM:
3307 			code = emit_andx_imm (code, dreg, sreg1, imm);
3308 			break;
3309 		case OP_IOR_IMM:
3310 			code = emit_orrw_imm (code, dreg, sreg1, imm);
3311 			break;
3312 		case OP_LOR_IMM:
3313 			code = emit_orrx_imm (code, dreg, sreg1, imm);
3314 			break;
3315 		case OP_IXOR_IMM:
3316 			code = emit_eorw_imm (code, dreg, sreg1, imm);
3317 			break;
3318 		case OP_LXOR_IMM:
3319 			code = emit_eorx_imm (code, dreg, sreg1, imm);
3320 			break;
3321 		case OP_ICOMPARE_IMM:
3322 			code = emit_cmpw_imm (code, sreg1, imm);
3323 			break;
3324 		case OP_LCOMPARE_IMM:
3325 		case OP_COMPARE_IMM:
3326 			if (imm == 0) {
3327 				arm_cmpx (code, sreg1, ARMREG_RZR);
3328 			} else {
3329 				// FIXME: 32 vs 64 bit issues for 0xffffffff
3330 				code = emit_imm64 (code, ARMREG_LR, imm);
3331 				arm_cmpx (code, sreg1, ARMREG_LR);
3332 			}
3333 			break;
3334 		case OP_ISHL:
3335 			arm_lslvw (code, dreg, sreg1, sreg2);
3336 			break;
3337 		case OP_LSHL:
3338 			arm_lslvx (code, dreg, sreg1, sreg2);
3339 			break;
3340 		case OP_ISHR:
3341 			arm_asrvw (code, dreg, sreg1, sreg2);
3342 			break;
3343 		case OP_LSHR:
3344 			arm_asrvx (code, dreg, sreg1, sreg2);
3345 			break;
3346 		case OP_ISHR_UN:
3347 			arm_lsrvw (code, dreg, sreg1, sreg2);
3348 			break;
3349 		case OP_LSHR_UN:
3350 			arm_lsrvx (code, dreg, sreg1, sreg2);
3351 			break;
3352 		case OP_ISHL_IMM:
3353 			if (imm == 0)
3354 				arm_movx (code, dreg, sreg1);
3355 			else
3356 				arm_lslw (code, dreg, sreg1, imm);
3357 			break;
3358 		case OP_LSHL_IMM:
3359 			if (imm == 0)
3360 				arm_movx (code, dreg, sreg1);
3361 			else
3362 				arm_lslx (code, dreg, sreg1, imm);
3363 			break;
3364 		case OP_ISHR_IMM:
3365 			if (imm == 0)
3366 				arm_movx (code, dreg, sreg1);
3367 			else
3368 				arm_asrw (code, dreg, sreg1, imm);
3369 			break;
3370 		case OP_LSHR_IMM:
3371 		case OP_SHR_IMM:
3372 			if (imm == 0)
3373 				arm_movx (code, dreg, sreg1);
3374 			else
3375 				arm_asrx (code, dreg, sreg1, imm);
3376 			break;
3377 		case OP_ISHR_UN_IMM:
3378 			if (imm == 0)
3379 				arm_movx (code, dreg, sreg1);
3380 			else
3381 				arm_lsrw (code, dreg, sreg1, imm);
3382 			break;
3383 		case OP_SHR_UN_IMM:
3384 		case OP_LSHR_UN_IMM:
3385 			if (imm == 0)
3386 				arm_movx (code, dreg, sreg1);
3387 			else
3388 				arm_lsrx (code, dreg, sreg1, imm);
3389 			break;
3390 
3391 			/* 64BIT ALU */
3392 		case OP_SEXT_I4:
3393 			arm_sxtwx (code, dreg, sreg1);
3394 			break;
3395 		case OP_ZEXT_I4:
3396 			/* Clean out the upper word */
3397 			arm_movw (code, dreg, sreg1);
3398 			break;
3399 		case OP_SHL_IMM:
3400 			arm_lslx (code, dreg, sreg1, imm);
3401 			break;
3402 
3403 			/* MULTIPLY/DIVISION */
3404 		case OP_IDIV:
3405 		case OP_IREM:
3406 			// FIXME: Optimize this
3407 			/* Check for zero */
3408 			arm_cmpx_imm (code, sreg2, 0);
3409 			code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
3410 			/* Check for INT_MIN/-1 */
3411 			code = emit_imm (code, ARMREG_IP0, 0x80000000);
3412 			arm_cmpx (code, sreg1, ARMREG_IP0);
3413 			arm_cset (code, ARMCOND_EQ, ARMREG_IP1);
3414 			code = emit_imm (code, ARMREG_IP0, 0xffffffff);
3415 			arm_cmpx (code, sreg2, ARMREG_IP0);
3416 			arm_cset (code, ARMCOND_EQ, ARMREG_IP0);
3417 			arm_andx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
3418 			arm_cmpx_imm (code, ARMREG_IP0, 1);
3419 			code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "OverflowException");
3420 			if (ins->opcode == OP_IREM) {
3421 				arm_sdivw (code, ARMREG_LR, sreg1, sreg2);
3422 				arm_msubw (code, dreg, ARMREG_LR, sreg2, sreg1);
3423 			} else {
3424 				arm_sdivw (code, dreg, sreg1, sreg2);
3425 			}
3426 			break;
3427 		case OP_IDIV_UN:
3428 			arm_cmpx_imm (code, sreg2, 0);
3429 			code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
3430 			arm_udivw (code, dreg, sreg1, sreg2);
3431 			break;
3432 		case OP_IREM_UN:
3433 			arm_cmpx_imm (code, sreg2, 0);
3434 			code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
3435 			arm_udivw (code, ARMREG_LR, sreg1, sreg2);
3436 			arm_msubw (code, dreg, ARMREG_LR, sreg2, sreg1);
3437 			break;
3438 		case OP_LDIV:
3439 		case OP_LREM:
3440 			// FIXME: Optimize this
3441 			/* Check for zero */
3442 			arm_cmpx_imm (code, sreg2, 0);
3443 			code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
3444 			/* Check for INT64_MIN/-1 */
3445 			code = emit_imm64 (code, ARMREG_IP0, 0x8000000000000000);
3446 			arm_cmpx (code, sreg1, ARMREG_IP0);
3447 			arm_cset (code, ARMCOND_EQ, ARMREG_IP1);
3448 			code = emit_imm64 (code, ARMREG_IP0, 0xffffffffffffffff);
3449 			arm_cmpx (code, sreg2, ARMREG_IP0);
3450 			arm_cset (code, ARMCOND_EQ, ARMREG_IP0);
3451 			arm_andx (code, ARMREG_IP0, ARMREG_IP0, ARMREG_IP1);
3452 			arm_cmpx_imm (code, ARMREG_IP0, 1);
3453 			/* 64 bit uses OverflowException */
3454 			code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "OverflowException");
3455 			if (ins->opcode == OP_LREM) {
3456 				arm_sdivx (code, ARMREG_LR, sreg1, sreg2);
3457 				arm_msubx (code, dreg, ARMREG_LR, sreg2, sreg1);
3458 			} else {
3459 				arm_sdivx (code, dreg, sreg1, sreg2);
3460 			}
3461 			break;
3462 		case OP_LDIV_UN:
3463 			arm_cmpx_imm (code, sreg2, 0);
3464 			code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
3465 			arm_udivx (code, dreg, sreg1, sreg2);
3466 			break;
3467 		case OP_LREM_UN:
3468 			arm_cmpx_imm (code, sreg2, 0);
3469 			code = emit_cond_exc (cfg, code, OP_COND_EXC_IEQ, "DivideByZeroException");
3470 			arm_udivx (code, ARMREG_LR, sreg1, sreg2);
3471 			arm_msubx (code, dreg, ARMREG_LR, sreg2, sreg1);
3472 			break;
3473 		case OP_IMUL:
3474 			arm_mulw (code, dreg, sreg1, sreg2);
3475 			break;
3476 		case OP_LMUL:
3477 			arm_mulx (code, dreg, sreg1, sreg2);
3478 			break;
3479 		case OP_IMUL_IMM:
3480 			code = emit_imm (code, ARMREG_LR, imm);
3481 			arm_mulw (code, dreg, sreg1, ARMREG_LR);
3482 			break;
3483 		case OP_MUL_IMM:
3484 		case OP_LMUL_IMM:
3485 			code = emit_imm (code, ARMREG_LR, imm);
3486 			arm_mulx (code, dreg, sreg1, ARMREG_LR);
3487 			break;
3488 
3489 			/* CONVERSIONS */
3490 		case OP_ICONV_TO_I1:
3491 		case OP_LCONV_TO_I1:
3492 			arm_sxtbx (code, dreg, sreg1);
3493 			break;
3494 		case OP_ICONV_TO_I2:
3495 		case OP_LCONV_TO_I2:
3496 			arm_sxthx (code, dreg, sreg1);
3497 			break;
3498 		case OP_ICONV_TO_U1:
3499 		case OP_LCONV_TO_U1:
3500 			arm_uxtbw (code, dreg, sreg1);
3501 			break;
3502 		case OP_ICONV_TO_U2:
3503 		case OP_LCONV_TO_U2:
3504 			arm_uxthw (code, dreg, sreg1);
3505 			break;
3506 
3507 			/* CSET */
3508 		case OP_CEQ:
3509 		case OP_ICEQ:
3510 		case OP_LCEQ:
3511 		case OP_CLT:
3512 		case OP_ICLT:
3513 		case OP_LCLT:
3514 		case OP_CGT:
3515 		case OP_ICGT:
3516 		case OP_LCGT:
3517 		case OP_CLT_UN:
3518 		case OP_ICLT_UN:
3519 		case OP_LCLT_UN:
3520 		case OP_CGT_UN:
3521 		case OP_ICGT_UN:
3522 		case OP_LCGT_UN:
3523 		case OP_ICNEQ:
3524 		case OP_ICGE:
3525 		case OP_ICLE:
3526 		case OP_ICGE_UN:
3527 		case OP_ICLE_UN: {
3528 			int cond;
3529 
3530 			cond = opcode_to_armcond (ins->opcode);
3531 			arm_cset (code, cond, dreg);
3532 			break;
3533 		}
3534 		case OP_FCEQ:
3535 		case OP_FCLT:
3536 		case OP_FCLT_UN:
3537 		case OP_FCGT:
3538 		case OP_FCGT_UN:
3539 		case OP_FCNEQ:
3540 		case OP_FCLE:
3541 		case OP_FCGE: {
3542 			int cond;
3543 
3544 			cond = opcode_to_armcond (ins->opcode);
3545 			arm_fcmpd (code, sreg1, sreg2);
3546 			arm_cset (code, cond, dreg);
3547 			break;
3548 		}
3549 
3550 			/* MEMORY */
3551 		case OP_LOADI1_MEMBASE:
3552 			code = emit_ldrsbx (code, dreg, ins->inst_basereg, ins->inst_offset);
3553 			break;
3554 		case OP_LOADU1_MEMBASE:
3555 			code = emit_ldrb (code, dreg, ins->inst_basereg, ins->inst_offset);
3556 			break;
3557 		case OP_LOADI2_MEMBASE:
3558 			code = emit_ldrshx (code, dreg, ins->inst_basereg, ins->inst_offset);
3559 			break;
3560 		case OP_LOADU2_MEMBASE:
3561 			code = emit_ldrh (code, dreg, ins->inst_basereg, ins->inst_offset);
3562 			break;
3563 		case OP_LOADI4_MEMBASE:
3564 			code = emit_ldrswx (code, dreg, ins->inst_basereg, ins->inst_offset);
3565 			break;
3566 		case OP_LOADU4_MEMBASE:
3567 			code = emit_ldrw (code, dreg, ins->inst_basereg, ins->inst_offset);
3568 			break;
3569 		case OP_LOAD_MEMBASE:
3570 		case OP_LOADI8_MEMBASE:
3571 			code = emit_ldrx (code, dreg, ins->inst_basereg, ins->inst_offset);
3572 			break;
3573 		case OP_STOREI1_MEMBASE_IMM:
3574 		case OP_STOREI2_MEMBASE_IMM:
3575 		case OP_STOREI4_MEMBASE_IMM:
3576 		case OP_STORE_MEMBASE_IMM:
3577 		case OP_STOREI8_MEMBASE_IMM: {
3578 			int immreg;
3579 
3580 			if (imm != 0) {
3581 				code = emit_imm (code, ARMREG_LR, imm);
3582 				immreg = ARMREG_LR;
3583 			} else {
3584 				immreg = ARMREG_RZR;
3585 			}
3586 
3587 			switch (ins->opcode) {
3588 			case OP_STOREI1_MEMBASE_IMM:
3589 				code = emit_strb (code, immreg, ins->inst_destbasereg, ins->inst_offset);
3590 				break;
3591 			case OP_STOREI2_MEMBASE_IMM:
3592 				code = emit_strh (code, immreg, ins->inst_destbasereg, ins->inst_offset);
3593 				break;
3594 			case OP_STOREI4_MEMBASE_IMM:
3595 				code = emit_strw (code, immreg, ins->inst_destbasereg, ins->inst_offset);
3596 				break;
3597 			case OP_STORE_MEMBASE_IMM:
3598 			case OP_STOREI8_MEMBASE_IMM:
3599 				code = emit_strx (code, immreg, ins->inst_destbasereg, ins->inst_offset);
3600 				break;
3601 			default:
3602 				g_assert_not_reached ();
3603 				break;
3604 			}
3605 			break;
3606 		}
3607 		case OP_STOREI1_MEMBASE_REG:
3608 			code = emit_strb (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
3609 			break;
3610 		case OP_STOREI2_MEMBASE_REG:
3611 			code = emit_strh (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
3612 			break;
3613 		case OP_STOREI4_MEMBASE_REG:
3614 			code = emit_strw (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
3615 			break;
3616 		case OP_STORE_MEMBASE_REG:
3617 		case OP_STOREI8_MEMBASE_REG:
3618 			code = emit_strx (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
3619 			break;
3620 		case OP_TLS_GET:
3621 			code = emit_tls_get (code, dreg, ins->inst_offset);
3622 			break;
3623 		case OP_TLS_SET:
3624 			code = emit_tls_set (code, sreg1, ins->inst_offset);
3625 			break;
3626 			/* Atomic */
3627 		case OP_MEMORY_BARRIER:
3628 			arm_dmb (code, ARM_DMB_ISH);
3629 			break;
3630 		case OP_ATOMIC_ADD_I4: {
3631 			guint8 *buf [16];
3632 
3633 			buf [0] = code;
3634 			arm_ldxrw (code, ARMREG_IP0, sreg1);
3635 			arm_addx (code, ARMREG_IP0, ARMREG_IP0, sreg2);
3636 			arm_stlxrw (code, ARMREG_IP1, ARMREG_IP0, sreg1);
3637 			arm_cbnzw (code, ARMREG_IP1, buf [0]);
3638 
3639 			arm_dmb (code, ARM_DMB_ISH);
3640 			arm_movx (code, dreg, ARMREG_IP0);
3641 			break;
3642 		}
3643 		case OP_ATOMIC_ADD_I8: {
3644 			guint8 *buf [16];
3645 
3646 			buf [0] = code;
3647 			arm_ldxrx (code, ARMREG_IP0, sreg1);
3648 			arm_addx (code, ARMREG_IP0, ARMREG_IP0, sreg2);
3649 			arm_stlxrx (code, ARMREG_IP1, ARMREG_IP0, sreg1);
3650 			arm_cbnzx (code, ARMREG_IP1, buf [0]);
3651 
3652 			arm_dmb (code, ARM_DMB_ISH);
3653 			arm_movx (code, dreg, ARMREG_IP0);
3654 			break;
3655 		}
3656 		case OP_ATOMIC_EXCHANGE_I4: {
3657 			guint8 *buf [16];
3658 
3659 			buf [0] = code;
3660 			arm_ldxrw (code, ARMREG_IP0, sreg1);
3661 			arm_stlxrw (code, ARMREG_IP1, sreg2, sreg1);
3662 			arm_cbnzw (code, ARMREG_IP1, buf [0]);
3663 
3664 			arm_dmb (code, ARM_DMB_ISH);
3665 			arm_movx (code, dreg, ARMREG_IP0);
3666 			break;
3667 		}
3668 		case OP_ATOMIC_EXCHANGE_I8: {
3669 			guint8 *buf [16];
3670 
3671 			buf [0] = code;
3672 			arm_ldxrx (code, ARMREG_IP0, sreg1);
3673 			arm_stlxrx (code, ARMREG_IP1, sreg2, sreg1);
3674 			arm_cbnzw (code, ARMREG_IP1, buf [0]);
3675 
3676 			arm_dmb (code, ARM_DMB_ISH);
3677 			arm_movx (code, dreg, ARMREG_IP0);
3678 			break;
3679 		}
3680 		case OP_ATOMIC_CAS_I4: {
3681 			guint8 *buf [16];
3682 
3683 			/* sreg2 is the value, sreg3 is the comparand */
3684 			buf [0] = code;
3685 			arm_ldxrw (code, ARMREG_IP0, sreg1);
3686 			arm_cmpw (code, ARMREG_IP0, ins->sreg3);
3687 			buf [1] = code;
3688 			arm_bcc (code, ARMCOND_NE, 0);
3689 			arm_stlxrw (code, ARMREG_IP1, sreg2, sreg1);
3690 			arm_cbnzw (code, ARMREG_IP1, buf [0]);
3691 			arm_patch_rel (buf [1], code, MONO_R_ARM64_BCC);
3692 
3693 			arm_dmb (code, ARM_DMB_ISH);
3694 			arm_movx (code, dreg, ARMREG_IP0);
3695 			break;
3696 		}
3697 		case OP_ATOMIC_CAS_I8: {
3698 			guint8 *buf [16];
3699 
3700 			buf [0] = code;
3701 			arm_ldxrx (code, ARMREG_IP0, sreg1);
3702 			arm_cmpx (code, ARMREG_IP0, ins->sreg3);
3703 			buf [1] = code;
3704 			arm_bcc (code, ARMCOND_NE, 0);
3705 			arm_stlxrx (code, ARMREG_IP1, sreg2, sreg1);
3706 			arm_cbnzw (code, ARMREG_IP1, buf [0]);
3707 			arm_patch_rel (buf [1], code, MONO_R_ARM64_BCC);
3708 
3709 			arm_dmb (code, ARM_DMB_ISH);
3710 			arm_movx (code, dreg, ARMREG_IP0);
3711 			break;
3712 		}
3713 		case OP_ATOMIC_LOAD_I1: {
3714 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3715 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3716 				arm_dmb (code, ARM_DMB_ISH);
3717 			arm_ldarb (code, ins->dreg, ARMREG_LR);
3718 			arm_sxtbx (code, ins->dreg, ins->dreg);
3719 			break;
3720 		}
3721 		case OP_ATOMIC_LOAD_U1: {
3722 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3723 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3724 				arm_dmb (code, ARM_DMB_ISH);
3725 			arm_ldarb (code, ins->dreg, ARMREG_LR);
3726 			arm_uxtbx (code, ins->dreg, ins->dreg);
3727 			break;
3728 		}
3729 		case OP_ATOMIC_LOAD_I2: {
3730 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3731 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3732 				arm_dmb (code, ARM_DMB_ISH);
3733 			arm_ldarh (code, ins->dreg, ARMREG_LR);
3734 			arm_sxthx (code, ins->dreg, ins->dreg);
3735 			break;
3736 		}
3737 		case OP_ATOMIC_LOAD_U2: {
3738 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3739 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3740 				arm_dmb (code, ARM_DMB_ISH);
3741 			arm_ldarh (code, ins->dreg, ARMREG_LR);
3742 			arm_uxthx (code, ins->dreg, ins->dreg);
3743 			break;
3744 		}
3745 		case OP_ATOMIC_LOAD_I4: {
3746 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3747 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3748 				arm_dmb (code, ARM_DMB_ISH);
3749 			arm_ldarw (code, ins->dreg, ARMREG_LR);
3750 			arm_sxtwx (code, ins->dreg, ins->dreg);
3751 			break;
3752 		}
3753 		case OP_ATOMIC_LOAD_U4: {
3754 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3755 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3756 				arm_dmb (code, ARM_DMB_ISH);
3757 			arm_ldarw (code, ins->dreg, ARMREG_LR);
3758 			arm_movw (code, ins->dreg, ins->dreg); /* Clear upper half of the register. */
3759 			break;
3760 		}
3761 		case OP_ATOMIC_LOAD_I8:
3762 		case OP_ATOMIC_LOAD_U8: {
3763 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3764 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3765 				arm_dmb (code, ARM_DMB_ISH);
3766 			arm_ldarx (code, ins->dreg, ARMREG_LR);
3767 			break;
3768 		}
3769 		case OP_ATOMIC_LOAD_R4: {
3770 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3771 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3772 				arm_dmb (code, ARM_DMB_ISH);
3773 			if (cfg->r4fp) {
3774 				arm_ldarw (code, ARMREG_LR, ARMREG_LR);
3775 				arm_fmov_rx_to_double (code, ins->dreg, ARMREG_LR);
3776 			} else {
3777 				arm_ldarw (code, ARMREG_LR, ARMREG_LR);
3778 				arm_fmov_rx_to_double (code, FP_TEMP_REG, ARMREG_LR);
3779 				arm_fcvt_sd (code, ins->dreg, FP_TEMP_REG);
3780 			}
3781 			break;
3782 		}
3783 		case OP_ATOMIC_LOAD_R8: {
3784 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_basereg, ins->inst_offset);
3785 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3786 				arm_dmb (code, ARM_DMB_ISH);
3787 			arm_ldarx (code, ARMREG_LR, ARMREG_LR);
3788 			arm_fmov_rx_to_double (code, ins->dreg, ARMREG_LR);
3789 			break;
3790 		}
3791 		case OP_ATOMIC_STORE_I1:
3792 		case OP_ATOMIC_STORE_U1: {
3793 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3794 			arm_stlrb (code, ARMREG_LR, ins->sreg1);
3795 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3796 				arm_dmb (code, ARM_DMB_ISH);
3797 			break;
3798 		}
3799 		case OP_ATOMIC_STORE_I2:
3800 		case OP_ATOMIC_STORE_U2: {
3801 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3802 			arm_stlrh (code, ARMREG_LR, ins->sreg1);
3803 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3804 				arm_dmb (code, ARM_DMB_ISH);
3805 			break;
3806 		}
3807 		case OP_ATOMIC_STORE_I4:
3808 		case OP_ATOMIC_STORE_U4: {
3809 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3810 			arm_stlrw (code, ARMREG_LR, ins->sreg1);
3811 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3812 				arm_dmb (code, ARM_DMB_ISH);
3813 			break;
3814 		}
3815 		case OP_ATOMIC_STORE_I8:
3816 		case OP_ATOMIC_STORE_U8: {
3817 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3818 			arm_stlrx (code, ARMREG_LR, ins->sreg1);
3819 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3820 				arm_dmb (code, ARM_DMB_ISH);
3821 			break;
3822 		}
3823 		case OP_ATOMIC_STORE_R4: {
3824 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3825 			if (cfg->r4fp) {
3826 				arm_fmov_double_to_rx (code, ARMREG_IP0, ins->sreg1);
3827 				arm_stlrw (code, ARMREG_LR, ARMREG_IP0);
3828 			} else {
3829 				arm_fcvt_ds (code, FP_TEMP_REG, ins->sreg1);
3830 				arm_fmov_double_to_rx (code, ARMREG_IP0, FP_TEMP_REG);
3831 				arm_stlrw (code, ARMREG_LR, ARMREG_IP0);
3832 			}
3833 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3834 				arm_dmb (code, ARM_DMB_ISH);
3835 			break;
3836 		}
3837 		case OP_ATOMIC_STORE_R8: {
3838 			code = emit_addx_imm (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3839 			arm_fmov_double_to_rx (code, ARMREG_IP0, ins->sreg1);
3840 			arm_stlrx (code, ARMREG_LR, ARMREG_IP0);
3841 			if (ins->backend.memory_barrier_kind == MONO_MEMORY_BARRIER_SEQ)
3842 				arm_dmb (code, ARM_DMB_ISH);
3843 			break;
3844 		}
3845 
3846 			/* FP */
3847 		case OP_R8CONST: {
3848 			guint64 imm = *(guint64*)ins->inst_p0;
3849 
3850 			if (imm == 0) {
3851 				arm_fmov_rx_to_double (code, dreg, ARMREG_RZR);
3852 			} else {
3853 				code = emit_imm64 (code, ARMREG_LR, imm);
3854 				arm_fmov_rx_to_double (code, ins->dreg, ARMREG_LR);
3855 			}
3856 			break;
3857 		}
3858 		case OP_R4CONST: {
3859 			guint64 imm = *(guint32*)ins->inst_p0;
3860 
3861 			code = emit_imm64 (code, ARMREG_LR, imm);
3862 			if (cfg->r4fp) {
3863 				arm_fmov_rx_to_double (code, dreg, ARMREG_LR);
3864 			} else {
3865 				arm_fmov_rx_to_double (code, FP_TEMP_REG, ARMREG_LR);
3866 				arm_fcvt_sd (code, dreg, FP_TEMP_REG);
3867 			}
3868 			break;
3869 		}
3870 		case OP_LOADR8_MEMBASE:
3871 			code = emit_ldrfpx (code, dreg, ins->inst_basereg, ins->inst_offset);
3872 			break;
3873 		case OP_LOADR4_MEMBASE:
3874 			if (cfg->r4fp) {
3875 				code = emit_ldrfpw (code, dreg, ins->inst_basereg, ins->inst_offset);
3876 			} else {
3877 				code = emit_ldrfpw (code, FP_TEMP_REG, ins->inst_basereg, ins->inst_offset);
3878 				arm_fcvt_sd (code, dreg, FP_TEMP_REG);
3879 			}
3880 			break;
3881 		case OP_STORER8_MEMBASE_REG:
3882 			code = emit_strfpx (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
3883 			break;
3884 		case OP_STORER4_MEMBASE_REG:
3885 			if (cfg->r4fp) {
3886 				code = emit_strfpw (code, sreg1, ins->inst_destbasereg, ins->inst_offset);
3887 			} else {
3888 				arm_fcvt_ds (code, FP_TEMP_REG, sreg1);
3889 				code = emit_strfpw (code, FP_TEMP_REG, ins->inst_destbasereg, ins->inst_offset);
3890 			}
3891 			break;
3892 		case OP_FMOVE:
3893 			if (dreg != sreg1)
3894 				arm_fmovd (code, dreg, sreg1);
3895 			break;
3896 		case OP_RMOVE:
3897 			if (dreg != sreg1)
3898 				arm_fmovs (code, dreg, sreg1);
3899 			break;
3900 		case OP_MOVE_F_TO_I4:
3901 			if (cfg->r4fp) {
3902 				arm_fmov_double_to_rx (code, ins->dreg, ins->sreg1);
3903 			} else {
3904 				arm_fcvt_ds (code, ins->dreg, ins->sreg1);
3905 				arm_fmov_double_to_rx (code, ins->dreg, ins->dreg);
3906 			}
3907 			break;
3908 		case OP_MOVE_I4_TO_F:
3909 			if (cfg->r4fp) {
3910 				arm_fmov_rx_to_double (code, ins->dreg, ins->sreg1);
3911 			} else {
3912 				arm_fmov_rx_to_double (code, ins->dreg, ins->sreg1);
3913 				arm_fcvt_sd (code, ins->dreg, ins->dreg);
3914 			}
3915 			break;
3916 		case OP_MOVE_F_TO_I8:
3917 			arm_fmov_double_to_rx (code, ins->dreg, ins->sreg1);
3918 			break;
3919 		case OP_MOVE_I8_TO_F:
3920 			arm_fmov_rx_to_double (code, ins->dreg, ins->sreg1);
3921 			break;
3922 		case OP_FCOMPARE:
3923 			arm_fcmpd (code, sreg1, sreg2);
3924 			break;
3925 		case OP_RCOMPARE:
3926 			arm_fcmps (code, sreg1, sreg2);
3927 			break;
3928 		case OP_FCONV_TO_I1:
3929 			arm_fcvtzs_dx (code, dreg, sreg1);
3930 			arm_sxtbx (code, dreg, dreg);
3931 			break;
3932 		case OP_FCONV_TO_U1:
3933 			arm_fcvtzu_dx (code, dreg, sreg1);
3934 			arm_uxtbw (code, dreg, dreg);
3935 			break;
3936 		case OP_FCONV_TO_I2:
3937 			arm_fcvtzs_dx (code, dreg, sreg1);
3938 			arm_sxthx (code, dreg, dreg);
3939 			break;
3940 		case OP_FCONV_TO_U2:
3941 			arm_fcvtzu_dx (code, dreg, sreg1);
3942 			arm_uxthw (code, dreg, dreg);
3943 			break;
3944 		case OP_FCONV_TO_I4:
3945 			arm_fcvtzs_dx (code, dreg, sreg1);
3946 			arm_sxtwx (code, dreg, dreg);
3947 			break;
3948 		case OP_FCONV_TO_U4:
3949 			arm_fcvtzu_dx (code, dreg, sreg1);
3950 			break;
3951 		case OP_FCONV_TO_I8:
3952 			arm_fcvtzs_dx (code, dreg, sreg1);
3953 			break;
3954 		case OP_FCONV_TO_U8:
3955 			arm_fcvtzu_dx (code, dreg, sreg1);
3956 			break;
3957 		case OP_FCONV_TO_R4:
3958 			if (cfg->r4fp) {
3959 				arm_fcvt_ds (code, dreg, sreg1);
3960 			} else {
3961 				arm_fcvt_ds (code, FP_TEMP_REG, sreg1);
3962 				arm_fcvt_sd (code, dreg, FP_TEMP_REG);
3963 			}
3964 			break;
3965 		case OP_ICONV_TO_R4:
3966 			if (cfg->r4fp) {
3967 				arm_scvtf_rw_to_s (code, dreg, sreg1);
3968 			} else {
3969 				arm_scvtf_rw_to_s (code, FP_TEMP_REG, sreg1);
3970 				arm_fcvt_sd (code, dreg, FP_TEMP_REG);
3971 			}
3972 			break;
3973 		case OP_LCONV_TO_R4:
3974 			if (cfg->r4fp) {
3975 				arm_scvtf_rx_to_s (code, dreg, sreg1);
3976 			} else {
3977 				arm_scvtf_rx_to_s (code, FP_TEMP_REG, sreg1);
3978 				arm_fcvt_sd (code, dreg, FP_TEMP_REG);
3979 			}
3980 			break;
3981 		case OP_ICONV_TO_R8:
3982 			arm_scvtf_rw_to_d (code, dreg, sreg1);
3983 			break;
3984 		case OP_LCONV_TO_R8:
3985 			arm_scvtf_rx_to_d (code, dreg, sreg1);
3986 			break;
3987 		case OP_ICONV_TO_R_UN:
3988 			arm_ucvtf_rw_to_d (code, dreg, sreg1);
3989 			break;
3990 		case OP_LCONV_TO_R_UN:
3991 			arm_ucvtf_rx_to_d (code, dreg, sreg1);
3992 			break;
3993 		case OP_FADD:
3994 			arm_fadd_d (code, dreg, sreg1, sreg2);
3995 			break;
3996 		case OP_FSUB:
3997 			arm_fsub_d (code, dreg, sreg1, sreg2);
3998 			break;
3999 		case OP_FMUL:
4000 			arm_fmul_d (code, dreg, sreg1, sreg2);
4001 			break;
4002 		case OP_FDIV:
4003 			arm_fdiv_d (code, dreg, sreg1, sreg2);
4004 			break;
4005 		case OP_FREM:
4006 			/* Emulated */
4007 			g_assert_not_reached ();
4008 			break;
4009 		case OP_FNEG:
4010 			arm_fneg_d (code, dreg, sreg1);
4011 			break;
4012 		case OP_ARM_SETFREG_R4:
4013 			arm_fcvt_ds (code, dreg, sreg1);
4014 			break;
4015 		case OP_CKFINITE:
4016 			/* Check for infinity */
4017 			code = emit_imm64 (code, ARMREG_LR, 0x7fefffffffffffffLL);
4018 			arm_fmov_rx_to_double (code, FP_TEMP_REG, ARMREG_LR);
4019 			arm_fabs_d (code, FP_TEMP_REG2, sreg1);
4020 			arm_fcmpd (code, FP_TEMP_REG2, FP_TEMP_REG);
4021 			code = emit_cond_exc (cfg, code, OP_COND_EXC_GT, "ArithmeticException");
4022 			/* Check for nans */
4023 			arm_fcmpd (code, FP_TEMP_REG2, FP_TEMP_REG2);
4024 			code = emit_cond_exc (cfg, code, OP_COND_EXC_OV, "ArithmeticException");
4025 			arm_fmovd (code, dreg, sreg1);
4026 			break;
4027 
4028 			/* R4 */
4029 		case OP_RADD:
4030 			arm_fadd_s (code, dreg, sreg1, sreg2);
4031 			break;
4032 		case OP_RSUB:
4033 			arm_fsub_s (code, dreg, sreg1, sreg2);
4034 			break;
4035 		case OP_RMUL:
4036 			arm_fmul_s (code, dreg, sreg1, sreg2);
4037 			break;
4038 		case OP_RDIV:
4039 			arm_fdiv_s (code, dreg, sreg1, sreg2);
4040 			break;
4041 		case OP_RNEG:
4042 			arm_fneg_s (code, dreg, sreg1);
4043 			break;
4044 		case OP_RCONV_TO_I1:
4045 			arm_fcvtzs_sx (code, dreg, sreg1);
4046 			arm_sxtbx (code, dreg, dreg);
4047 			break;
4048 		case OP_RCONV_TO_U1:
4049 			arm_fcvtzu_sx (code, dreg, sreg1);
4050 			arm_uxtbw (code, dreg, dreg);
4051 			break;
4052 		case OP_RCONV_TO_I2:
4053 			arm_fcvtzs_sx (code, dreg, sreg1);
4054 			arm_sxthx (code, dreg, dreg);
4055 			break;
4056 		case OP_RCONV_TO_U2:
4057 			arm_fcvtzu_sx (code, dreg, sreg1);
4058 			arm_uxthw (code, dreg, dreg);
4059 			break;
4060 		case OP_RCONV_TO_I4:
4061 			arm_fcvtzs_sx (code, dreg, sreg1);
4062 			arm_sxtwx (code, dreg, dreg);
4063 			break;
4064 		case OP_RCONV_TO_U4:
4065 			arm_fcvtzu_sx (code, dreg, sreg1);
4066 			break;
4067 		case OP_RCONV_TO_I8:
4068 			arm_fcvtzs_sx (code, dreg, sreg1);
4069 			break;
4070 		case OP_RCONV_TO_U8:
4071 			arm_fcvtzu_sx (code, dreg, sreg1);
4072 			break;
4073 		case OP_RCONV_TO_R8:
4074 			arm_fcvt_sd (code, dreg, sreg1);
4075 			break;
4076 		case OP_RCONV_TO_R4:
4077 			if (dreg != sreg1)
4078 				arm_fmovs (code, dreg, sreg1);
4079 			break;
4080 		case OP_RCEQ:
4081 		case OP_RCLT:
4082 		case OP_RCLT_UN:
4083 		case OP_RCGT:
4084 		case OP_RCGT_UN:
4085 		case OP_RCNEQ:
4086 		case OP_RCLE:
4087 		case OP_RCGE: {
4088 			int cond;
4089 
4090 			cond = opcode_to_armcond (ins->opcode);
4091 			arm_fcmps (code, sreg1, sreg2);
4092 			arm_cset (code, cond, dreg);
4093 			break;
4094 		}
4095 
4096 			/* CALLS */
4097 		case OP_VOIDCALL:
4098 		case OP_CALL:
4099 		case OP_LCALL:
4100 		case OP_FCALL:
4101 		case OP_RCALL:
4102 		case OP_VCALL2:
4103 			call = (MonoCallInst*)ins;
4104 			if (ins->flags & MONO_INST_HAS_METHOD)
4105 				code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
4106 			else
4107 				code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
4108 			code = emit_move_return_value (cfg, code, ins);
4109 			break;
4110 		case OP_VOIDCALL_REG:
4111 		case OP_CALL_REG:
4112 		case OP_LCALL_REG:
4113 		case OP_FCALL_REG:
4114 		case OP_RCALL_REG:
4115 		case OP_VCALL2_REG:
4116 			arm_blrx (code, sreg1);
4117 			code = emit_move_return_value (cfg, code, ins);
4118 			break;
4119 		case OP_VOIDCALL_MEMBASE:
4120 		case OP_CALL_MEMBASE:
4121 		case OP_LCALL_MEMBASE:
4122 		case OP_FCALL_MEMBASE:
4123 		case OP_RCALL_MEMBASE:
4124 		case OP_VCALL2_MEMBASE:
4125 			code = emit_ldrx (code, ARMREG_IP0, ins->inst_basereg, ins->inst_offset);
4126 			arm_blrx (code, ARMREG_IP0);
4127 			code = emit_move_return_value (cfg, code, ins);
4128 			break;
4129 		case OP_TAILCALL: {
4130 			MonoCallInst *call = (MonoCallInst*)ins;
4131 
4132 			g_assert (!cfg->method->save_lmf);
4133 
4134 			// FIXME: Copy stack arguments
4135 
4136 			/* Restore registers */
4137 			code = emit_load_regset (code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, cfg->arch.saved_gregs_offset);
4138 
4139 			/* Destroy frame */
4140 			code = mono_arm_emit_destroy_frame (code, cfg->stack_offset, ((1 << ARMREG_IP0) | (1 << ARMREG_IP1)));
4141 
4142 			if (cfg->compile_aot) {
4143 				/* This is not a PLT patch */
4144 				code = emit_aotconst (cfg, code, ARMREG_IP0, MONO_PATCH_INFO_METHOD_JUMP, call->method);
4145 				arm_brx (code, ARMREG_IP0);
4146 			} else {
4147 				mono_add_patch_info_rel (cfg, code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, call->method, MONO_R_ARM64_B);
4148 				arm_b (code, code);
4149 				cfg->thunk_area += THUNK_SIZE;
4150 			}
4151 			ins->flags |= MONO_INST_GC_CALLSITE;
4152 			ins->backend.pc_offset = code - cfg->native_code;
4153 			break;
4154 		}
4155 		case OP_ARGLIST:
4156 			g_assert (cfg->arch.cinfo);
4157 			code = emit_addx_imm (code, ARMREG_IP0, cfg->arch.args_reg, ((CallInfo*)cfg->arch.cinfo)->sig_cookie.offset);
4158 			arm_strx (code, ARMREG_IP0, sreg1, 0);
4159 			break;
4160 		case OP_DYN_CALL: {
4161 			MonoInst *var = cfg->dyn_call_var;
4162 			guint8 *labels [16];
4163 			int i;
4164 
4165 			/*
4166 			 * sreg1 points to a DynCallArgs structure initialized by mono_arch_start_dyn_call ().
4167 			 * sreg2 is the function to call.
4168 			 */
4169 
4170 			g_assert (var->opcode == OP_REGOFFSET);
4171 
4172 			arm_movx (code, ARMREG_LR, sreg1);
4173 			arm_movx (code, ARMREG_IP1, sreg2);
4174 
4175 			/* Save args buffer */
4176 			code = emit_strx (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
4177 
4178 			/* Set fp argument regs */
4179 			code = emit_ldrw (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_fpargs));
4180 			arm_cmpw (code, ARMREG_R0, ARMREG_RZR);
4181 			labels [0] = code;
4182 			arm_bcc (code, ARMCOND_EQ, 0);
4183 			for (i = 0; i < 8; ++i)
4184 				code = emit_ldrfpx (code, ARMREG_D0 + i, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, fpregs) + (i * 8));
4185 			arm_patch_rel (labels [0], code, MONO_R_ARM64_BCC);
4186 
4187 			/* Allocate callee area */
4188 			code = emit_ldrx (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_stackargs));
4189 			arm_lslw (code, ARMREG_R0, ARMREG_R0, 3);
4190 			arm_movspx (code, ARMREG_R1, ARMREG_SP);
4191 			arm_subx (code, ARMREG_R1, ARMREG_R1, ARMREG_R0);
4192 			arm_movspx (code, ARMREG_SP, ARMREG_R1);
4193 
4194 			/* Set stack args */
4195 			/* R1 = limit */
4196 			code = emit_ldrx (code, ARMREG_R1, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_stackargs));
4197 			/* R2 = pointer into 'regs' */
4198 			code = emit_imm (code, ARMREG_R2, MONO_STRUCT_OFFSET (DynCallArgs, regs) + ((PARAM_REGS + 1) * sizeof (mgreg_t)));
4199 			arm_addx (code, ARMREG_R2, ARMREG_LR, ARMREG_R2);
4200 			/* R3 = pointer to stack */
4201 			arm_movspx (code, ARMREG_R3, ARMREG_SP);
4202 			labels [0] = code;
4203 			arm_b (code, code);
4204 			labels [1] = code;
4205 			code = emit_ldrx (code, ARMREG_R5, ARMREG_R2, 0);
4206 			code = emit_strx (code, ARMREG_R5, ARMREG_R3, 0);
4207 			code = emit_addx_imm (code, ARMREG_R2, ARMREG_R2, sizeof (mgreg_t));
4208 			code = emit_addx_imm (code, ARMREG_R3, ARMREG_R3, sizeof (mgreg_t));
4209 			code = emit_subx_imm (code, ARMREG_R1, ARMREG_R1, 1);
4210 			arm_patch_rel (labels [0], code, MONO_R_ARM64_B);
4211 			arm_cmpw (code, ARMREG_R1, ARMREG_RZR);
4212 			arm_bcc (code, ARMCOND_GT, labels [1]);
4213 
4214 			/* Set argument registers + r8 */
4215 			code = mono_arm_emit_load_regarray (code, 0x1ff, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, regs));
4216 
4217 			/* Make the call */
4218 			arm_blrx (code, ARMREG_IP1);
4219 
4220 			/* Save result */
4221 			code = emit_ldrx (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
4222 			arm_strx (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, res));
4223 			arm_strx (code, ARMREG_R1, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, res2));
4224 			/* Save fp result */
4225 			code = emit_ldrw (code, ARMREG_R0, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, n_fpret));
4226 			arm_cmpw (code, ARMREG_R0, ARMREG_RZR);
4227 			labels [1] = code;
4228 			arm_bcc (code, ARMCOND_EQ, 0);
4229 			for (i = 0; i < 8; ++i)
4230 				code = emit_strfpx (code, ARMREG_D0 + i, ARMREG_LR, MONO_STRUCT_OFFSET (DynCallArgs, fpregs) + (i * 8));
4231 			arm_patch_rel (labels [1], code, MONO_R_ARM64_BCC);
4232 			break;
4233 		}
4234 
4235 		case OP_GENERIC_CLASS_INIT: {
4236 			int byte_offset;
4237 			guint8 *jump;
4238 
4239 			byte_offset = MONO_STRUCT_OFFSET (MonoVTable, initialized);
4240 
4241 			/* Load vtable->initialized */
4242 			arm_ldrsbx (code, ARMREG_IP0, sreg1, byte_offset);
4243 			jump = code;
4244 			arm_cbnzx (code, ARMREG_IP0, 0);
4245 
4246 			/* Slowpath */
4247 			g_assert (sreg1 == ARMREG_R0);
4248 			code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
4249 							  (gpointer)"mono_generic_class_init");
4250 
4251 			mono_arm_patch (jump, code, MONO_R_ARM64_CBZ);
4252 			break;
4253 		}
4254 
4255 		case OP_CHECK_THIS:
4256 			arm_ldrx (code, ARMREG_LR, sreg1, 0);
4257 			break;
4258 		case OP_NOT_NULL:
4259 		case OP_NOT_REACHED:
4260 		case OP_DUMMY_USE:
4261 			break;
4262 		case OP_IL_SEQ_POINT:
4263 			mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
4264 			break;
4265 
4266 			/* EH */
4267 		case OP_COND_EXC_C:
4268 		case OP_COND_EXC_IC:
4269 		case OP_COND_EXC_OV:
4270 		case OP_COND_EXC_IOV:
4271 		case OP_COND_EXC_NC:
4272 		case OP_COND_EXC_INC:
4273 		case OP_COND_EXC_NO:
4274 		case OP_COND_EXC_INO:
4275 		case OP_COND_EXC_EQ:
4276 		case OP_COND_EXC_IEQ:
4277 		case OP_COND_EXC_NE_UN:
4278 		case OP_COND_EXC_INE_UN:
4279 		case OP_COND_EXC_ILT:
4280 		case OP_COND_EXC_LT:
4281 		case OP_COND_EXC_ILT_UN:
4282 		case OP_COND_EXC_LT_UN:
4283 		case OP_COND_EXC_IGT:
4284 		case OP_COND_EXC_GT:
4285 		case OP_COND_EXC_IGT_UN:
4286 		case OP_COND_EXC_GT_UN:
4287 		case OP_COND_EXC_IGE:
4288 		case OP_COND_EXC_GE:
4289 		case OP_COND_EXC_IGE_UN:
4290 		case OP_COND_EXC_GE_UN:
4291 		case OP_COND_EXC_ILE:
4292 		case OP_COND_EXC_LE:
4293 		case OP_COND_EXC_ILE_UN:
4294 		case OP_COND_EXC_LE_UN:
4295 			code = emit_cond_exc (cfg, code, ins->opcode, ins->inst_p1);
4296 			break;
4297 		case OP_THROW:
4298 			if (sreg1 != ARMREG_R0)
4299 				arm_movx (code, ARMREG_R0, sreg1);
4300 			code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
4301 							  (gpointer)"mono_arch_throw_exception");
4302 			break;
4303 		case OP_RETHROW:
4304 			if (sreg1 != ARMREG_R0)
4305 				arm_movx (code, ARMREG_R0, sreg1);
4306 			code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD,
4307 							  (gpointer)"mono_arch_rethrow_exception");
4308 			break;
4309 		case OP_CALL_HANDLER:
4310 			mono_add_patch_info_rel (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb, MONO_R_ARM64_BL);
4311 			arm_bl (code, 0);
4312 			cfg->thunk_area += THUNK_SIZE;
4313 			for (GList *tmp = ins->inst_eh_blocks; tmp != bb->clause_holes; tmp = tmp->prev)
4314 				mono_cfg_add_try_hole (cfg, (MonoExceptionClause *)tmp->data, code, bb);
4315 			break;
4316 		case OP_START_HANDLER: {
4317 			MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4318 
4319 			/* Save caller address */
4320 			code = emit_strx (code, ARMREG_LR, spvar->inst_basereg, spvar->inst_offset);
4321 
4322 			/*
4323 			 * Reserve a param area, see test_0_finally_param_area ().
4324 			 * This is needed because the param area is not set up when
4325 			 * we are called from EH code.
4326 			 */
4327 			if (cfg->param_area)
4328 				code = emit_subx_sp_imm (code, cfg->param_area);
4329 			break;
4330 		}
4331 		case OP_ENDFINALLY:
4332 		case OP_ENDFILTER: {
4333 			MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
4334 
4335 			if (cfg->param_area)
4336 				code = emit_addx_sp_imm (code, cfg->param_area);
4337 
4338 			if (ins->opcode == OP_ENDFILTER && sreg1 != ARMREG_R0)
4339 				arm_movx (code, ARMREG_R0, sreg1);
4340 
4341 			/* Return to either after the branch in OP_CALL_HANDLER, or to the EH code */
4342 			code = emit_ldrx (code, ARMREG_LR, spvar->inst_basereg, spvar->inst_offset);
4343 			arm_brx (code, ARMREG_LR);
4344 			break;
4345 		}
4346 		case OP_GET_EX_OBJ:
4347 			if (ins->dreg != ARMREG_R0)
4348 				arm_movx (code, ins->dreg, ARMREG_R0);
4349 			break;
4350 		case OP_GC_SAFE_POINT: {
4351 #if defined (USE_COOP_GC)
4352 			guint8 *buf [1];
4353 
4354 			arm_ldrx (code, ARMREG_IP1, ins->sreg1, 0);
4355 			/* Call it if it is non-null */
4356 			buf [0] = code;
4357 			arm_cbzx (code, ARMREG_IP1, 0);
4358 			code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, "mono_threads_state_poll");
4359 			mono_arm_patch (buf [0], code, MONO_R_ARM64_CBZ);
4360 #endif
4361 			break;
4362 		}
4363 		case OP_FILL_PROF_CALL_CTX:
4364 			for (int i = 0; i < MONO_MAX_IREGS; i++)
4365 				if ((MONO_ARCH_CALLEE_SAVED_REGS & (1 << i)) || i == ARMREG_SP || i == ARMREG_FP)
4366 					arm_strx (code, i, ins->sreg1, MONO_STRUCT_OFFSET (MonoContext, regs) + i * sizeof (mgreg_t));
4367 			break;
4368 		default:
4369 			g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4370 			g_assert_not_reached ();
4371 		}
4372 
4373 		if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4374 			g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4375 				   mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4376 			g_assert_not_reached ();
4377 		}
4378 	}
4379 
4380 	/*
4381 	 * If the compiled code size is larger than the bcc displacement (19 bits signed),
4382 	 * insert branch islands between/inside basic blocks.
4383 	 */
4384 	if (cfg->arch.cond_branch_islands)
4385 		code = emit_branch_island (cfg, code, start_offset);
4386 
4387 	cfg->code_len = code - cfg->native_code;
4388 }
4389 
4390 static guint8*
emit_move_args(MonoCompile * cfg,guint8 * code)4391 emit_move_args (MonoCompile *cfg, guint8 *code)
4392 {
4393 	MonoInst *ins;
4394 	CallInfo *cinfo;
4395 	ArgInfo *ainfo;
4396 	int i, part;
4397 
4398 	cinfo = cfg->arch.cinfo;
4399 	g_assert (cinfo);
4400 	for (i = 0; i < cinfo->nargs; ++i) {
4401 		ainfo = cinfo->args + i;
4402 		ins = cfg->args [i];
4403 
4404 		if (ins->opcode == OP_REGVAR) {
4405 			switch (ainfo->storage) {
4406 			case ArgInIReg:
4407 				arm_movx (code, ins->dreg, ainfo->reg);
4408 				break;
4409 			case ArgOnStack:
4410 				switch (ainfo->slot_size) {
4411 				case 1:
4412 					if (ainfo->sign)
4413 						code = emit_ldrsbx (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
4414 					else
4415 						code = emit_ldrb (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
4416 					break;
4417 				case 2:
4418 					if (ainfo->sign)
4419 						code = emit_ldrshx (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
4420 					else
4421 						code = emit_ldrh (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
4422 					break;
4423 				case 4:
4424 					if (ainfo->sign)
4425 						code = emit_ldrswx (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
4426 					else
4427 						code = emit_ldrw (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
4428 					break;
4429 				default:
4430 					code = emit_ldrx (code, ins->dreg, cfg->arch.args_reg, ainfo->offset);
4431 					break;
4432 				}
4433 				break;
4434 			default:
4435 				g_assert_not_reached ();
4436 				break;
4437 			}
4438 		} else {
4439 			if (ainfo->storage != ArgVtypeByRef && ainfo->storage != ArgVtypeByRefOnStack)
4440 				g_assert (ins->opcode == OP_REGOFFSET);
4441 
4442 			switch (ainfo->storage) {
4443 			case ArgInIReg:
4444 				/* Stack slots for arguments have size 8 */
4445 				code = emit_strx (code, ainfo->reg, ins->inst_basereg, ins->inst_offset);
4446 				break;
4447 			case ArgInFReg:
4448 				code = emit_strfpx (code, ainfo->reg, ins->inst_basereg, ins->inst_offset);
4449 				break;
4450 			case ArgInFRegR4:
4451 				code = emit_strfpw (code, ainfo->reg, ins->inst_basereg, ins->inst_offset);
4452 				break;
4453 			case ArgOnStack:
4454 			case ArgOnStackR4:
4455 			case ArgOnStackR8:
4456 			case ArgVtypeByRefOnStack:
4457 			case ArgVtypeOnStack:
4458 				break;
4459 			case ArgVtypeByRef: {
4460 				MonoInst *addr_arg = ins->inst_left;
4461 
4462 				if (ainfo->gsharedvt) {
4463 					g_assert (ins->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
4464 					arm_strx (code, ainfo->reg, ins->inst_basereg, ins->inst_offset);
4465 				} else {
4466 					g_assert (ins->opcode == OP_VTARG_ADDR);
4467 					g_assert (addr_arg->opcode == OP_REGOFFSET);
4468 					arm_strx (code, ainfo->reg, addr_arg->inst_basereg, addr_arg->inst_offset);
4469 				}
4470 				break;
4471 			}
4472 			case ArgVtypeInIRegs:
4473 				for (part = 0; part < ainfo->nregs; part ++) {
4474 					code = emit_strx (code, ainfo->reg + part, ins->inst_basereg, ins->inst_offset + (part * 8));
4475 				}
4476 				break;
4477 			case ArgHFA:
4478 				for (part = 0; part < ainfo->nregs; part ++) {
4479 					if (ainfo->esize == 4)
4480 						code = emit_strfpw (code, ainfo->reg + part, ins->inst_basereg, ins->inst_offset + ainfo->foffsets [part]);
4481 					else
4482 						code = emit_strfpx (code, ainfo->reg + part, ins->inst_basereg, ins->inst_offset + ainfo->foffsets [part]);
4483 				}
4484 				break;
4485 			default:
4486 				g_assert_not_reached ();
4487 				break;
4488 			}
4489 		}
4490 	}
4491 
4492 	return code;
4493 }
4494 
4495 /*
4496  * emit_store_regarray:
4497  *
4498  *   Emit code to store the registers in REGS into the appropriate elements of
4499  * the register array at BASEREG+OFFSET.
4500  */
4501 static __attribute__ ((__warn_unused_result__)) guint8*
emit_store_regarray(guint8 * code,guint64 regs,int basereg,int offset)4502 emit_store_regarray (guint8 *code, guint64 regs, int basereg, int offset)
4503 {
4504 	int i;
4505 
4506 	for (i = 0; i < 32; ++i) {
4507 		if (regs & (1 << i)) {
4508 			if (i + 1 < 32 && (regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
4509 				arm_stpx (code, i, i + 1, basereg, offset + (i * 8));
4510 				i++;
4511 			} else if (i == ARMREG_SP) {
4512 				arm_movspx (code, ARMREG_IP1, ARMREG_SP);
4513 				arm_strx (code, ARMREG_IP1, basereg, offset + (i * 8));
4514 			} else {
4515 				arm_strx (code, i, basereg, offset + (i * 8));
4516 			}
4517 		}
4518 	}
4519 	return code;
4520 }
4521 
4522 /*
4523  * emit_load_regarray:
4524  *
4525  *   Emit code to load the registers in REGS from the appropriate elements of
4526  * the register array at BASEREG+OFFSET.
4527  */
4528 static __attribute__ ((__warn_unused_result__)) guint8*
emit_load_regarray(guint8 * code,guint64 regs,int basereg,int offset)4529 emit_load_regarray (guint8 *code, guint64 regs, int basereg, int offset)
4530 {
4531 	int i;
4532 
4533 	for (i = 0; i < 32; ++i) {
4534 		if (regs & (1 << i)) {
4535 			if ((regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
4536 				if (offset + (i * 8) < 500)
4537 					arm_ldpx (code, i, i + 1, basereg, offset + (i * 8));
4538 				else {
4539 					code = emit_ldrx (code, i, basereg, offset + (i * 8));
4540 					code = emit_ldrx (code, i + 1, basereg, offset + ((i + 1) * 8));
4541 				}
4542 				i++;
4543 			} else if (i == ARMREG_SP) {
4544 				g_assert_not_reached ();
4545 			} else {
4546 				code = emit_ldrx (code, i, basereg, offset + (i * 8));
4547 			}
4548 		}
4549 	}
4550 	return code;
4551 }
4552 
4553 /*
4554  * emit_store_regset:
4555  *
4556  *   Emit code to store the registers in REGS into consecutive memory locations starting
4557  * at BASEREG+OFFSET.
4558  */
4559 static __attribute__ ((__warn_unused_result__)) guint8*
emit_store_regset(guint8 * code,guint64 regs,int basereg,int offset)4560 emit_store_regset (guint8 *code, guint64 regs, int basereg, int offset)
4561 {
4562 	int i, pos;
4563 
4564 	pos = 0;
4565 	for (i = 0; i < 32; ++i) {
4566 		if (regs & (1 << i)) {
4567 			if ((regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
4568 				arm_stpx (code, i, i + 1, basereg, offset + (pos * 8));
4569 				i++;
4570 				pos++;
4571 			} else if (i == ARMREG_SP) {
4572 				arm_movspx (code, ARMREG_IP1, ARMREG_SP);
4573 				arm_strx (code, ARMREG_IP1, basereg, offset + (pos * 8));
4574 			} else {
4575 				arm_strx (code, i, basereg, offset + (pos * 8));
4576 			}
4577 			pos++;
4578 		}
4579 	}
4580 	return code;
4581 }
4582 
4583 /*
4584  * emit_load_regset:
4585  *
4586  *   Emit code to load the registers in REGS from consecutive memory locations starting
4587  * at BASEREG+OFFSET.
4588  */
4589 static __attribute__ ((__warn_unused_result__)) guint8*
emit_load_regset(guint8 * code,guint64 regs,int basereg,int offset)4590 emit_load_regset (guint8 *code, guint64 regs, int basereg, int offset)
4591 {
4592 	int i, pos;
4593 
4594 	pos = 0;
4595 	for (i = 0; i < 32; ++i) {
4596 		if (regs & (1 << i)) {
4597 			if ((regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
4598 				arm_ldpx (code, i, i + 1, basereg, offset + (pos * 8));
4599 				i++;
4600 				pos++;
4601 			} else if (i == ARMREG_SP) {
4602 				g_assert_not_reached ();
4603 			} else {
4604 				arm_ldrx (code, i, basereg, offset + (pos * 8));
4605 			}
4606 			pos++;
4607 		}
4608 	}
4609 	return code;
4610 }
4611 
4612 __attribute__ ((__warn_unused_result__)) guint8*
mono_arm_emit_load_regarray(guint8 * code,guint64 regs,int basereg,int offset)4613 mono_arm_emit_load_regarray (guint8 *code, guint64 regs, int basereg, int offset)
4614 {
4615 	return emit_load_regarray (code, regs, basereg, offset);
4616 }
4617 
4618 __attribute__ ((__warn_unused_result__)) guint8*
mono_arm_emit_store_regarray(guint8 * code,guint64 regs,int basereg,int offset)4619 mono_arm_emit_store_regarray (guint8 *code, guint64 regs, int basereg, int offset)
4620 {
4621 	return emit_store_regarray (code, regs, basereg, offset);
4622 }
4623 
4624 __attribute__ ((__warn_unused_result__)) guint8*
mono_arm_emit_store_regset(guint8 * code,guint64 regs,int basereg,int offset)4625 mono_arm_emit_store_regset (guint8 *code, guint64 regs, int basereg, int offset)
4626 {
4627 	return emit_store_regset (code, regs, basereg, offset);
4628 }
4629 
4630 /* Same as emit_store_regset, but emit unwind info too */
4631 /* CFA_OFFSET is the offset between the CFA and basereg */
4632 static __attribute__ ((__warn_unused_result__)) guint8*
emit_store_regset_cfa(MonoCompile * cfg,guint8 * code,guint64 regs,int basereg,int offset,int cfa_offset,guint64 no_cfa_regset)4633 emit_store_regset_cfa (MonoCompile *cfg, guint8 *code, guint64 regs, int basereg, int offset, int cfa_offset, guint64 no_cfa_regset)
4634 {
4635 	int i, j, pos, nregs;
4636 	guint32 cfa_regset = regs & ~no_cfa_regset;
4637 
4638 	pos = 0;
4639 	for (i = 0; i < 32; ++i) {
4640 		nregs = 1;
4641 		if (regs & (1 << i)) {
4642 			if ((regs & (1 << (i + 1))) && (i + 1 != ARMREG_SP)) {
4643 				if (offset < 256) {
4644 					arm_stpx (code, i, i + 1, basereg, offset + (pos * 8));
4645 				} else {
4646 					code = emit_strx (code, i, basereg, offset + (pos * 8));
4647 					code = emit_strx (code, i + 1, basereg, offset + (pos * 8) + 8);
4648 				}
4649 				nregs = 2;
4650 			} else if (i == ARMREG_SP) {
4651 				arm_movspx (code, ARMREG_IP1, ARMREG_SP);
4652 				code = emit_strx (code, ARMREG_IP1, basereg, offset + (pos * 8));
4653 			} else {
4654 				code = emit_strx (code, i, basereg, offset + (pos * 8));
4655 			}
4656 
4657 			for (j = 0; j < nregs; ++j) {
4658 				if (cfa_regset & (1 << (i + j)))
4659 					mono_emit_unwind_op_offset (cfg, code, i + j, (- cfa_offset) + offset + ((pos + j) * 8));
4660 			}
4661 
4662 			i += nregs - 1;
4663 			pos += nregs;
4664 		}
4665 	}
4666 	return code;
4667 }
4668 
4669 /*
4670  * emit_setup_lmf:
4671  *
4672  *   Emit code to initialize an LMF structure at LMF_OFFSET.
4673  * Clobbers ip0/ip1.
4674  */
4675 static guint8*
emit_setup_lmf(MonoCompile * cfg,guint8 * code,gint32 lmf_offset,int cfa_offset)4676 emit_setup_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset, int cfa_offset)
4677 {
4678 	/*
4679 	 * The LMF should contain all the state required to be able to reconstruct the machine state
4680 	 * at the current point of execution. Since the LMF is only read during EH, only callee
4681 	 * saved etc. registers need to be saved.
4682 	 * FIXME: Save callee saved fp regs, JITted code doesn't use them, but native code does, and they
4683 	 * need to be restored during EH.
4684 	 */
4685 
4686 	/* pc */
4687 	arm_adrx (code, ARMREG_LR, code);
4688 	code = emit_strx (code, ARMREG_LR, ARMREG_FP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, pc));
4689 	/* gregs + fp + sp */
4690 	/* Don't emit unwind info for sp/fp, they are already handled in the prolog */
4691 	code = emit_store_regset_cfa (cfg, code, MONO_ARCH_LMF_REGS, ARMREG_FP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs), cfa_offset, (1 << ARMREG_FP) | (1 << ARMREG_SP));
4692 
4693 	return code;
4694 }
4695 
4696 guint8 *
mono_arch_emit_prolog(MonoCompile * cfg)4697 mono_arch_emit_prolog (MonoCompile *cfg)
4698 {
4699 	MonoMethod *method = cfg->method;
4700 	MonoMethodSignature *sig;
4701 	MonoBasicBlock *bb;
4702 	guint8 *code;
4703 	int cfa_offset, max_offset;
4704 
4705 	sig = mono_method_signature (method);
4706 	cfg->code_size = 256 + sig->param_count * 64;
4707 	code = cfg->native_code = g_malloc (cfg->code_size);
4708 
4709 	/* This can be unaligned */
4710 	cfg->stack_offset = ALIGN_TO (cfg->stack_offset, MONO_ARCH_FRAME_ALIGNMENT);
4711 
4712 	/*
4713 	 * - Setup frame
4714 	 */
4715 	cfa_offset = 0;
4716 	mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, 0);
4717 
4718 	/* Setup frame */
4719 	if (arm_is_ldpx_imm (-cfg->stack_offset)) {
4720 		arm_stpx_pre (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, -cfg->stack_offset);
4721 	} else {
4722 		/* sp -= cfg->stack_offset */
4723 		/* This clobbers ip0/ip1 */
4724 		code = emit_subx_sp_imm (code, cfg->stack_offset);
4725 		arm_stpx (code, ARMREG_FP, ARMREG_LR, ARMREG_SP, 0);
4726 	}
4727 	cfa_offset += cfg->stack_offset;
4728 	mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
4729 	mono_emit_unwind_op_offset (cfg, code, ARMREG_FP, (- cfa_offset) + 0);
4730 	mono_emit_unwind_op_offset (cfg, code, ARMREG_LR, (- cfa_offset) + 8);
4731 	arm_movspx (code, ARMREG_FP, ARMREG_SP);
4732 	mono_emit_unwind_op_def_cfa_reg (cfg, code, ARMREG_FP);
4733 	if (cfg->param_area) {
4734 		/* The param area is below the frame pointer */
4735 		code = emit_subx_sp_imm (code, cfg->param_area);
4736 	}
4737 
4738 	if (cfg->method->save_lmf) {
4739 		code = emit_setup_lmf (cfg, code, cfg->lmf_var->inst_offset, cfa_offset);
4740 	} else {
4741 		/* Save gregs */
4742 		code = emit_store_regset_cfa (cfg, code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, cfg->arch.saved_gregs_offset, cfa_offset, 0);
4743 	}
4744 
4745 	/* Setup args reg */
4746 	if (cfg->arch.args_reg) {
4747 		/* The register was already saved above */
4748 		code = emit_addx_imm (code, cfg->arch.args_reg, ARMREG_FP, cfg->stack_offset);
4749 	}
4750 
4751 	/* Save return area addr received in R8 */
4752 	if (cfg->vret_addr) {
4753 		MonoInst *ins = cfg->vret_addr;
4754 
4755 		g_assert (ins->opcode == OP_REGOFFSET);
4756 		code = emit_strx (code, ARMREG_R8, ins->inst_basereg, ins->inst_offset);
4757 	}
4758 
4759 	/* Save mrgctx received in MONO_ARCH_RGCTX_REG */
4760 	if (cfg->rgctx_var) {
4761 		MonoInst *ins = cfg->rgctx_var;
4762 
4763 		g_assert (ins->opcode == OP_REGOFFSET);
4764 
4765 		code = emit_strx (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4766 	}
4767 
4768 	/*
4769 	 * Move arguments to their registers/stack locations.
4770 	 */
4771 	code = emit_move_args (cfg, code);
4772 
4773 	/* Initialize seq_point_info_var */
4774 	if (cfg->arch.seq_point_info_var) {
4775 		MonoInst *ins = cfg->arch.seq_point_info_var;
4776 
4777 		/* Initialize the variable from a GOT slot */
4778 		code = emit_aotconst (cfg, code, ARMREG_IP0, MONO_PATCH_INFO_SEQ_POINT_INFO, cfg->method);
4779 		g_assert (ins->opcode == OP_REGOFFSET);
4780 		code = emit_strx (code, ARMREG_IP0, ins->inst_basereg, ins->inst_offset);
4781 
4782 		/* Initialize ss_tramp_var */
4783 		ins = cfg->arch.ss_tramp_var;
4784 		g_assert (ins->opcode == OP_REGOFFSET);
4785 
4786 		code = emit_ldrx (code, ARMREG_IP1, ARMREG_IP0, MONO_STRUCT_OFFSET (SeqPointInfo, ss_tramp_addr));
4787 		code = emit_strx (code, ARMREG_IP1, ins->inst_basereg, ins->inst_offset);
4788 	} else {
4789 		MonoInst *ins;
4790 
4791 		if (cfg->arch.ss_tramp_var) {
4792 			/* Initialize ss_tramp_var */
4793 			ins = cfg->arch.ss_tramp_var;
4794 			g_assert (ins->opcode == OP_REGOFFSET);
4795 
4796 			code = emit_imm64 (code, ARMREG_IP0, (guint64)&ss_trampoline);
4797 			code = emit_strx (code, ARMREG_IP0, ins->inst_basereg, ins->inst_offset);
4798 		}
4799 
4800 		if (cfg->arch.bp_tramp_var) {
4801 			/* Initialize bp_tramp_var */
4802 			ins = cfg->arch.bp_tramp_var;
4803 			g_assert (ins->opcode == OP_REGOFFSET);
4804 
4805 			code = emit_imm64 (code, ARMREG_IP0, (guint64)bp_trampoline);
4806 			code = emit_strx (code, ARMREG_IP0, ins->inst_basereg, ins->inst_offset);
4807 		}
4808 	}
4809 
4810 	max_offset = 0;
4811 	if (cfg->opt & MONO_OPT_BRANCH) {
4812 		for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4813 			MonoInst *ins;
4814 			bb->max_offset = max_offset;
4815 
4816 			MONO_BB_FOR_EACH_INS (bb, ins) {
4817 				max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4818 			}
4819 		}
4820 	}
4821 	if (max_offset > 0x3ffff * 4)
4822 		cfg->arch.cond_branch_islands = TRUE;
4823 
4824 	return code;
4825 }
4826 
4827 static guint8*
realloc_code(MonoCompile * cfg,int size)4828 realloc_code (MonoCompile *cfg, int size)
4829 {
4830 	while (cfg->code_len + size > (cfg->code_size - 16)) {
4831 		cfg->code_size *= 2;
4832 		cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4833 		cfg->stat_code_reallocs++;
4834 	}
4835 	return cfg->native_code + cfg->code_len;
4836 }
4837 
4838 void
mono_arch_emit_epilog(MonoCompile * cfg)4839 mono_arch_emit_epilog (MonoCompile *cfg)
4840 {
4841 	CallInfo *cinfo;
4842 	int max_epilog_size;
4843 	guint8 *code;
4844 	int i;
4845 
4846 	max_epilog_size = 16 + 20*4;
4847 	code = realloc_code (cfg, max_epilog_size);
4848 
4849 	if (cfg->method->save_lmf) {
4850 		code = mono_arm_emit_load_regarray (code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, cfg->lmf_var->inst_offset + MONO_STRUCT_OFFSET (MonoLMF, gregs) - (MONO_ARCH_FIRST_LMF_REG * 8));
4851 	} else {
4852 		/* Restore gregs */
4853 		code = emit_load_regset (code, MONO_ARCH_CALLEE_SAVED_REGS & cfg->used_int_regs, ARMREG_FP, cfg->arch.saved_gregs_offset);
4854 	}
4855 
4856 	/* Load returned vtypes into registers if needed */
4857 	cinfo = cfg->arch.cinfo;
4858 	switch (cinfo->ret.storage) {
4859 	case ArgVtypeInIRegs: {
4860 		MonoInst *ins = cfg->ret;
4861 
4862 		for (i = 0; i < cinfo->ret.nregs; ++i)
4863 			code = emit_ldrx (code, cinfo->ret.reg + i, ins->inst_basereg, ins->inst_offset + (i * 8));
4864 		break;
4865 	}
4866 	case ArgHFA: {
4867 		MonoInst *ins = cfg->ret;
4868 
4869 		for (i = 0; i < cinfo->ret.nregs; ++i) {
4870 			if (cinfo->ret.esize == 4)
4871 				code = emit_ldrfpw (code, cinfo->ret.reg + i, ins->inst_basereg, ins->inst_offset + cinfo->ret.foffsets [i]);
4872 			else
4873 				code = emit_ldrfpx (code, cinfo->ret.reg + i, ins->inst_basereg, ins->inst_offset + cinfo->ret.foffsets [i]);
4874 		}
4875 		break;
4876 	}
4877 	default:
4878 		break;
4879 	}
4880 
4881 	/* Destroy frame */
4882 	code = mono_arm_emit_destroy_frame (code, cfg->stack_offset, ((1 << ARMREG_IP0) | (1 << ARMREG_IP1)));
4883 
4884 	arm_retx (code, ARMREG_LR);
4885 
4886 	g_assert (code - (cfg->native_code + cfg->code_len) < max_epilog_size);
4887 
4888 	cfg->code_len = code - cfg->native_code;
4889 }
4890 
4891 void
mono_arch_emit_exceptions(MonoCompile * cfg)4892 mono_arch_emit_exceptions (MonoCompile *cfg)
4893 {
4894 	MonoJumpInfo *ji;
4895 	MonoClass *exc_class;
4896 	guint8 *code, *ip;
4897 	guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM];
4898 	guint8 exc_throw_found [MONO_EXC_INTRINS_NUM];
4899 	int i, id, size = 0;
4900 
4901 	for (i = 0; i < MONO_EXC_INTRINS_NUM; i++) {
4902 		exc_throw_pos [i] = NULL;
4903 		exc_throw_found [i] = 0;
4904 	}
4905 
4906 	for (ji = cfg->patch_info; ji; ji = ji->next) {
4907 		if (ji->type == MONO_PATCH_INFO_EXC) {
4908 			i = mini_exception_id_by_name (ji->data.target);
4909 			if (!exc_throw_found [i]) {
4910 				size += 32;
4911 				exc_throw_found [i] = TRUE;
4912 			}
4913 		}
4914 	}
4915 
4916 	code = realloc_code (cfg, size);
4917 
4918 	/* Emit code to raise corlib exceptions */
4919 	for (ji = cfg->patch_info; ji; ji = ji->next) {
4920 		if (ji->type != MONO_PATCH_INFO_EXC)
4921 			continue;
4922 
4923 		ip = cfg->native_code + ji->ip.i;
4924 
4925 		id = mini_exception_id_by_name (ji->data.target);
4926 
4927 		if (exc_throw_pos [id]) {
4928 			/* ip points to the bcc () in OP_COND_EXC_... */
4929 			arm_patch_rel (ip, exc_throw_pos [id], ji->relocation);
4930 			ji->type = MONO_PATCH_INFO_NONE;
4931 			continue;
4932 		}
4933 
4934 		exc_throw_pos [id] = code;
4935 		arm_patch_rel (ip, code, ji->relocation);
4936 
4937 		/* We are being branched to from the code generated by emit_cond_exc (), the pc is in ip1 */
4938 
4939 		/* r0 = type token */
4940 		exc_class = mono_class_load_from_name (mono_defaults.corlib, "System", ji->data.name);
4941 		code = emit_imm (code, ARMREG_R0, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
4942 		/* r1 = throw ip */
4943 		arm_movx (code, ARMREG_R1, ARMREG_IP1);
4944 		/* Branch to the corlib exception throwing trampoline */
4945 		ji->ip.i = code - cfg->native_code;
4946 		ji->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4947 		ji->data.name = "mono_arch_throw_corlib_exception";
4948 		ji->relocation = MONO_R_ARM64_BL;
4949 		arm_bl (code, 0);
4950 		cfg->thunk_area += THUNK_SIZE;
4951 	}
4952 
4953 	cfg->code_len = code - cfg->native_code;
4954 
4955 	g_assert (cfg->code_len < cfg->code_size);
4956 }
4957 
4958 MonoInst*
mono_arch_emit_inst_for_method(MonoCompile * cfg,MonoMethod * cmethod,MonoMethodSignature * fsig,MonoInst ** args)4959 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4960 {
4961 	return NULL;
4962 }
4963 
4964 guint32
mono_arch_get_patch_offset(guint8 * code)4965 mono_arch_get_patch_offset (guint8 *code)
4966 {
4967 	return 0;
4968 }
4969 
4970 gpointer
mono_arch_build_imt_trampoline(MonoVTable * vtable,MonoDomain * domain,MonoIMTCheckItem ** imt_entries,int count,gpointer fail_tramp)4971 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4972 								gpointer fail_tramp)
4973 {
4974 	int i, buf_len, imt_reg;
4975 	guint8 *buf, *code;
4976 
4977 #if DEBUG_IMT
4978 	printf ("building IMT trampoline for class %s %s entries %d code size %d code at %p end %p vtable %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable);
4979 	for (i = 0; i < count; ++i) {
4980 		MonoIMTCheckItem *item = imt_entries [i];
4981 		printf ("method %d (%p) %s vtable slot %p is_equals %d chunk size %d\n", i, item->key, item->key->name, &vtable->vtable [item->value.vtable_slot], item->is_equals, item->chunk_size);
4982 	}
4983 #endif
4984 
4985 	buf_len = 0;
4986 	for (i = 0; i < count; ++i) {
4987 		MonoIMTCheckItem *item = imt_entries [i];
4988 		if (item->is_equals) {
4989 			gboolean fail_case = !item->check_target_idx && fail_tramp;
4990 
4991 			if (item->check_target_idx || fail_case) {
4992 				if (!item->compare_done || fail_case) {
4993 					buf_len += 4 * 4 + 4;
4994 				}
4995 				buf_len += 4;
4996 				if (item->has_target_code) {
4997 					buf_len += 5 * 4;
4998 				} else {
4999 					buf_len += 6 * 4;
5000 				}
5001 				if (fail_case) {
5002 					buf_len += 5 * 4;
5003 				}
5004 			} else {
5005 				buf_len += 6 * 4;
5006 			}
5007 		} else {
5008 			buf_len += 6 * 4;
5009 		}
5010 	}
5011 
5012 	if (fail_tramp)
5013 		buf = mono_method_alloc_generic_virtual_trampoline (domain, buf_len);
5014 	else
5015 		buf = mono_domain_code_reserve (domain, buf_len);
5016 	code = buf;
5017 
5018 	/*
5019 	 * We are called by JITted code, which passes in the IMT argument in
5020 	 * MONO_ARCH_RGCTX_REG (r27). We need to preserve all caller saved regs
5021 	 * except ip0/ip1.
5022 	 */
5023 	imt_reg = MONO_ARCH_RGCTX_REG;
5024 	for (i = 0; i < count; ++i) {
5025 		MonoIMTCheckItem *item = imt_entries [i];
5026 
5027 		item->code_target = code;
5028 
5029 		if (item->is_equals) {
5030 			/*
5031 			 * Check the imt argument against item->key, if equals, jump to either
5032 			 * item->value.target_code or to vtable [item->value.vtable_slot].
5033 			 * If fail_tramp is set, jump to it if not-equals.
5034 			 */
5035 			gboolean fail_case = !item->check_target_idx && fail_tramp;
5036 
5037 			if (item->check_target_idx || fail_case) {
5038 				/* Compare imt_reg with item->key */
5039 				if (!item->compare_done || fail_case) {
5040 					// FIXME: Optimize this
5041 					code = emit_imm64 (code, ARMREG_IP0, (guint64)item->key);
5042 					arm_cmpx (code, imt_reg, ARMREG_IP0);
5043 				}
5044 				item->jmp_code = code;
5045 				arm_bcc (code, ARMCOND_NE, 0);
5046 				/* Jump to target if equals */
5047 				if (item->has_target_code) {
5048 					code = emit_imm64 (code, ARMREG_IP0, (guint64)item->value.target_code);
5049 					arm_brx (code, ARMREG_IP0);
5050 				} else {
5051 					guint64 imm = (guint64)&(vtable->vtable [item->value.vtable_slot]);
5052 
5053 					code = emit_imm64 (code, ARMREG_IP0, imm);
5054 					arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
5055 					arm_brx (code, ARMREG_IP0);
5056 				}
5057 
5058 				if (fail_case) {
5059 					arm_patch_rel (item->jmp_code, code, MONO_R_ARM64_BCC);
5060 					item->jmp_code = NULL;
5061 					code = emit_imm64 (code, ARMREG_IP0, (guint64)fail_tramp);
5062 					arm_brx (code, ARMREG_IP0);
5063 				}
5064 			} else {
5065 				guint64 imm = (guint64)&(vtable->vtable [item->value.vtable_slot]);
5066 
5067 				code = emit_imm64 (code, ARMREG_IP0, imm);
5068 				arm_ldrx (code, ARMREG_IP0, ARMREG_IP0, 0);
5069 				arm_brx (code, ARMREG_IP0);
5070 			}
5071 		} else {
5072 			code = emit_imm64 (code, ARMREG_IP0, (guint64)item->key);
5073 			arm_cmpx (code, imt_reg, ARMREG_IP0);
5074 			item->jmp_code = code;
5075 			arm_bcc (code, ARMCOND_HS, 0);
5076 		}
5077 	}
5078 	/* Patch the branches */
5079 	for (i = 0; i < count; ++i) {
5080 		MonoIMTCheckItem *item = imt_entries [i];
5081 		if (item->jmp_code && item->check_target_idx)
5082 			arm_patch_rel (item->jmp_code, imt_entries [item->check_target_idx]->code_target, MONO_R_ARM64_BCC);
5083 	}
5084 
5085 	g_assert ((code - buf) < buf_len);
5086 
5087 	mono_arch_flush_icache (buf, code - buf);
5088 
5089 	return buf;
5090 }
5091 
5092 GSList *
mono_arch_get_trampolines(gboolean aot)5093 mono_arch_get_trampolines (gboolean aot)
5094 {
5095 	return mono_arm_get_exception_trampolines (aot);
5096 }
5097 
5098 #else /* DISABLE_JIT */
5099 
5100 gpointer
mono_arch_build_imt_trampoline(MonoVTable * vtable,MonoDomain * domain,MonoIMTCheckItem ** imt_entries,int count,gpointer fail_tramp)5101 mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5102 								gpointer fail_tramp)
5103 {
5104 	g_assert_not_reached ();
5105 	return NULL;
5106 }
5107 
5108 #endif /* !DISABLE_JIT */
5109 
5110 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
5111 
5112 void
mono_arch_set_breakpoint(MonoJitInfo * ji,guint8 * ip)5113 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5114 {
5115 	guint8 *code = ip;
5116 	guint32 native_offset = ip - (guint8*)ji->code_start;
5117 
5118 	if (ji->from_aot) {
5119 		SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
5120 
5121 		g_assert (native_offset % 4 == 0);
5122 		g_assert (info->bp_addrs [native_offset / 4] == 0);
5123 		info->bp_addrs [native_offset / 4] = mini_get_breakpoint_trampoline ();
5124 	} else {
5125 		/* ip points to an ldrx */
5126 		code += 4;
5127 		arm_blrx (code, ARMREG_IP0);
5128 		mono_arch_flush_icache (ip, code - ip);
5129 	}
5130 }
5131 
5132 void
mono_arch_clear_breakpoint(MonoJitInfo * ji,guint8 * ip)5133 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5134 {
5135 	guint8 *code = ip;
5136 
5137 	if (ji->from_aot) {
5138 		guint32 native_offset = ip - (guint8*)ji->code_start;
5139 		SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
5140 
5141 		g_assert (native_offset % 4 == 0);
5142 		info->bp_addrs [native_offset / 4] = NULL;
5143 	} else {
5144 		/* ip points to an ldrx */
5145 		code += 4;
5146 		arm_nop (code);
5147 		mono_arch_flush_icache (ip, code - ip);
5148 	}
5149 }
5150 
5151 void
mono_arch_start_single_stepping(void)5152 mono_arch_start_single_stepping (void)
5153 {
5154 	ss_trampoline = mini_get_single_step_trampoline ();
5155 }
5156 
5157 void
mono_arch_stop_single_stepping(void)5158 mono_arch_stop_single_stepping (void)
5159 {
5160 	ss_trampoline = NULL;
5161 }
5162 
5163 gboolean
mono_arch_is_single_step_event(void * info,void * sigctx)5164 mono_arch_is_single_step_event (void *info, void *sigctx)
5165 {
5166 	/* We use soft breakpoints on arm64 */
5167 	return FALSE;
5168 }
5169 
5170 gboolean
mono_arch_is_breakpoint_event(void * info,void * sigctx)5171 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5172 {
5173 	/* We use soft breakpoints on arm64 */
5174 	return FALSE;
5175 }
5176 
5177 void
mono_arch_skip_breakpoint(MonoContext * ctx,MonoJitInfo * ji)5178 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
5179 {
5180 	g_assert_not_reached ();
5181 }
5182 
5183 void
mono_arch_skip_single_step(MonoContext * ctx)5184 mono_arch_skip_single_step (MonoContext *ctx)
5185 {
5186 	g_assert_not_reached ();
5187 }
5188 
5189 gpointer
mono_arch_get_seq_point_info(MonoDomain * domain,guint8 * code)5190 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5191 {
5192 	SeqPointInfo *info;
5193 	MonoJitInfo *ji;
5194 
5195 	// FIXME: Add a free function
5196 
5197 	mono_domain_lock (domain);
5198 	info = g_hash_table_lookup (domain_jit_info (domain)->arch_seq_points,
5199 								code);
5200 	mono_domain_unlock (domain);
5201 
5202 	if (!info) {
5203 		ji = mono_jit_info_table_find (domain, (char*)code);
5204 		g_assert (ji);
5205 
5206 		info = g_malloc0 (sizeof (SeqPointInfo) + (ji->code_size / 4) * sizeof(guint8*));
5207 
5208 		info->ss_tramp_addr = &ss_trampoline;
5209 
5210 		mono_domain_lock (domain);
5211 		g_hash_table_insert (domain_jit_info (domain)->arch_seq_points,
5212 							 code, info);
5213 		mono_domain_unlock (domain);
5214 	}
5215 
5216 	return info;
5217 }
5218 
5219 #endif /* MONO_ARCH_SOFT_DEBUG_SUPPORTED */
5220 
5221 gboolean
mono_arch_opcode_supported(int opcode)5222 mono_arch_opcode_supported (int opcode)
5223 {
5224 	switch (opcode) {
5225 	case OP_ATOMIC_ADD_I4:
5226 	case OP_ATOMIC_ADD_I8:
5227 	case OP_ATOMIC_EXCHANGE_I4:
5228 	case OP_ATOMIC_EXCHANGE_I8:
5229 	case OP_ATOMIC_CAS_I4:
5230 	case OP_ATOMIC_CAS_I8:
5231 	case OP_ATOMIC_LOAD_I1:
5232 	case OP_ATOMIC_LOAD_I2:
5233 	case OP_ATOMIC_LOAD_I4:
5234 	case OP_ATOMIC_LOAD_I8:
5235 	case OP_ATOMIC_LOAD_U1:
5236 	case OP_ATOMIC_LOAD_U2:
5237 	case OP_ATOMIC_LOAD_U4:
5238 	case OP_ATOMIC_LOAD_U8:
5239 	case OP_ATOMIC_LOAD_R4:
5240 	case OP_ATOMIC_LOAD_R8:
5241 	case OP_ATOMIC_STORE_I1:
5242 	case OP_ATOMIC_STORE_I2:
5243 	case OP_ATOMIC_STORE_I4:
5244 	case OP_ATOMIC_STORE_I8:
5245 	case OP_ATOMIC_STORE_U1:
5246 	case OP_ATOMIC_STORE_U2:
5247 	case OP_ATOMIC_STORE_U4:
5248 	case OP_ATOMIC_STORE_U8:
5249 	case OP_ATOMIC_STORE_R4:
5250 	case OP_ATOMIC_STORE_R8:
5251 		return TRUE;
5252 	default:
5253 		return FALSE;
5254 	}
5255 }
5256 
5257 CallInfo*
mono_arch_get_call_info(MonoMemPool * mp,MonoMethodSignature * sig)5258 mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
5259 {
5260 	return get_call_info (mp, sig);
5261 }
5262 
5263