"Fossies" - the Fresh Open Source Software Archive

Member "mono-6.12.0.122/mono/mini/mini-arm64.c" (22 Feb 2021, 150703 Bytes) of package /linux/misc/mono-sources/mono/mono-6.12.0.122.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "mini-arm64.c": 6.10.0.104_vs_6.12.0.90.

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