Affix
view release on metacpan or search on metacpan
infix/src/arch/aarch64/abi_arm64.c view on Meta::CPAN
/**
* Copyright (c) 2025 Sanko Robinson
*
* This source code is dual-licensed under the Artistic License 2.0 or the MIT License.
* You may choose to use this code under the terms of either license.
*
* SPDX-License-Identifier: (Artistic-2.0 OR MIT)
*
* The documentation blocks within this file are licensed under the
* Creative Commons Attribution 4.0 International License (CC BY 4.0).
*
* SPDX-License-Identifier: CC-BY-4.0
*/
/**
* @file abi_arm64.c
* @brief Implements the FFI logic for the AArch64 (ARM64) architecture.
* @ingroup internal_abi_aarch64
*
* @internal
* This file provides the concrete implementation of the `infix_forward_abi_spec`
* and `infix_reverse_abi_spec` for the ARM64 architecture. It primarily follows
* the standard "Procedure Call Standard for the ARM 64-bit Architecture" (AAPCS64),
* but also contains critical conditional logic to handle deviations for specific
* platforms like Apple macOS and Windows on ARM.
*
* @section aapcs64_rules Key AAPCS64 Rules Implemented
*
* - **Register Usage:**
* - The first 8 integer/pointer arguments are passed in GPRs (X0-X7).
* - The first 8 floating-point/vector arguments are passed in VPRs (V0-V7).
*
* - **Homogeneous Floating-point Aggregates (HFAs):** Structs or arrays composed
* entirely of 1 to 4 identical floating-point types (`float` or `double`) are
* passed in consecutive VPRs.
*
* - **Return Values:**
* - Aggregates up to 16 bytes are returned in registers (GPRs and/or VPRs).
* - Larger aggregates are returned via a hidden pointer passed by the caller
* in the dedicated "indirect result location register", `X8`.
*
* @section platform_deviations Platform-Specific Deviations
*
* - **Variadic Calls (Apple macOS):** All variadic arguments are passed on the
* stack. Arguments smaller than 8 bytes are promoted to fill 8-byte stack slots.
*
* - **Variadic Calls (Windows on ARM):** The HFA rule is disabled for variadic
* arguments. Floating-point scalars are passed in GPRs, not VPRs.
*
* - **16-Byte Argument Alignment:**
* - **Standard/macOS:** 16-byte aggregates passed in GPRs must start in an
* even-numbered register (X0, X2, X4, X6).
* - **macOS Exception:** `__int128_t` does NOT require even-GPR alignment.
* - **Windows Exception:** Variadic 16-byte aggregates do NOT require even-GPR alignment.
* @endinternal
*/
#include "arch/aarch64/abi_arm64_common.h"
#include "arch/aarch64/abi_arm64_emitters.h"
#include "common/infix_internals.h"
#include "common/utility.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
/** @internal The General-Purpose Registers used for the first 8 integer/pointer arguments. */
static const arm64_gpr GPR_ARGS[] = {X0_REG, X1_REG, X2_REG, X3_REG, X4_REG, X5_REG, X6_REG, X7_REG};
/** @internal The SIMD/Floating-Point Registers used for the first 8 float/double/vector arguments. */
static const arm64_vpr VPR_ARGS[] = {V0_REG, V1_REG, V2_REG, V3_REG, V4_REG, V5_REG, V6_REG, V7_REG};
/** @internal The total number of GPRs available for argument passing. */
#define NUM_GPR_ARGS 8
/** @internal The total number of VPRs available for argument passing. */
#define NUM_VPR_ARGS 8
/** @internal A safe limit on the number of fields to classify to prevent DoS from exponential complexity. */
#define MAX_AGGREGATE_FIELDS_TO_CLASSIFY 32
//
static bool is_hfa(const infix_type * type, const infix_type ** base_type);
/** @internal The v-table of AArch64 functions for generating forward trampolines. */
static infix_status prepare_forward_call_frame_arm64(infix_arena_t * arena,
infix_call_frame_layout ** out_layout,
infix_type * ret_type,
infix_type ** arg_types,
size_t num_args,
size_t num_fixed_args,
void * target_fn);
static infix_status generate_forward_prologue_arm64(code_buffer * buf, infix_call_frame_layout * layout);
static infix_status generate_forward_argument_moves_arm64(code_buffer * buf,
infix_call_frame_layout * layout,
infix_type ** arg_types,
size_t num_args,
c23_maybe_unused size_t num_fixed_args);
static infix_status generate_forward_call_instruction_arm64(code_buffer *, infix_call_frame_layout *);
static infix_status generate_forward_epilogue_arm64(code_buffer * buf,
infix_call_frame_layout * layout,
infix_type * ret_type);
const infix_forward_abi_spec g_arm64_forward_spec = {
.prepare_forward_call_frame = prepare_forward_call_frame_arm64,
.generate_forward_prologue = generate_forward_prologue_arm64,
.generate_forward_argument_moves = generate_forward_argument_moves_arm64,
.generate_forward_call_instruction = generate_forward_call_instruction_arm64,
.generate_forward_epilogue = generate_forward_epilogue_arm64};
( run in 0.788 second using v1.01-cache-2.11-cpan-99c4e6809bf )