Affix

 view release on metacpan or  search on metacpan

infix/src/arch/x64/abi_sysv_x64.c  view on Meta::CPAN

                continue;
            if (classify_recursive(member->type, member_offset, classes, depth + 1, field_count, member->is_bitfield))
                return true;  // Propagate unaligned discovery
        }
        return false;
    }
    return false;
}
/**
 * @internal
 * @brief Classifies an aggregate type for argument passing according to the System V ABI.
 * @details This function implements the complete classification algorithm. An aggregate
 *          is broken down into up to two "eightbytes". Each is classified as INTEGER,
 *          SSE, or MEMORY. If the size is > 16 bytes or classification fails, it's MEMORY.
 *
 * @param type The aggregate type to classify.
 * @param[out] classes An array of two `arg_class_t` to be filled.
 * @param[out] num_classes The number of valid classes (1 or 2).
 */
static void classify_aggregate_sysv(const infix_type * type, arg_class_t classes[2], size_t * num_classes) {
    // Initialize to a clean state.
    classes[0] = NO_CLASS;
    classes[1] = NO_CLASS;
    *num_classes = 0;
    // If the size is greater than 16 bytes, it's passed in memory.
    if (type->size > 16) {
        classes[0] = MEMORY;
        *num_classes = 1;
        return;
    }
    // Run the recursive classification. If it returns true, an unaligned
    // field was found, and the class is already set to MEMORY. We can stop.
    size_t field_count = 0;                                              // Initialize the counter for this aggregate.
    if (classify_recursive(type, 0, classes, 0, &field_count, false)) {  // Pass counter to initial call
        *num_classes = 1;
        return;
    }
    // Post-processing for alignment padding.
    if (type->size > 0 && classes[0] == NO_CLASS)
        classes[0] = INTEGER;
    if (type->size > 8 && classes[1] == NO_CLASS)
        classes[1] = INTEGER;
    // Count the number of valid, classified eightbytes.
    if (classes[0] != NO_CLASS)
        (*num_classes)++;
    if (classes[1] != NO_CLASS)
        (*num_classes)++;
}
/**
 * @internal
 * @brief Stage 1 (Forward): Analyzes a signature and creates a call frame layout for System V.
 * @details This function iterates through a function's arguments, classifying each one
 *          to determine its location (GPR, XMM, or stack) according to the SysV ABI rules.
 * @param arena The temporary arena for allocations.
 * @param out_layout Receives the created layout blueprint.
 * @param ret_type The function's return type.
 * @param arg_types Array of argument types.
 * @param num_args Total number of arguments.
 * @param num_fixed_args Number of non-variadic arguments.
 * @param target_fn The target function address.
 * @return `INFIX_SUCCESS` on success, or an error code on failure.
 */
static infix_status prepare_forward_call_frame_sysv_x64(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) {
    if (out_layout == nullptr)
        return INFIX_ERROR_INVALID_ARGUMENT;
    // Allocate the layout struct that will hold our results.
    infix_call_frame_layout * layout =
        infix_arena_calloc(arena, 1, sizeof(infix_call_frame_layout), _Alignof(infix_call_frame_layout));
    if (layout == nullptr) {
        *out_layout = nullptr;
        return INFIX_ERROR_ALLOCATION_FAILED;
    }
    layout->is_variadic = num_args > num_fixed_args;
    layout->target_fn = target_fn;
    layout->arg_locations =
        infix_arena_calloc(arena, num_args, sizeof(infix_arg_location), _Alignof(infix_arg_location));
    if (layout->arg_locations == nullptr && num_args > 0) {
        *out_layout = nullptr;
        return INFIX_ERROR_ALLOCATION_FAILED;
    }
    // gpr_count and xmm_count track the next available GPR and XMM argument registers.
    // current_stack_offset tracks the next available stack slot for arguments.
    size_t gpr_count = 0, xmm_count = 0, current_stack_offset = 0;
    // Determine if the return value requires a hidden pointer argument passed in RDI.
    bool ret_is_aggregate = (ret_type->category == INFIX_TYPE_STRUCT || ret_type->category == INFIX_TYPE_UNION ||
                             ret_type->category == INFIX_TYPE_ARRAY || ret_type->category == INFIX_TYPE_COMPLEX);
    // Rule 1: Aggregates larger than 16 bytes are always returned via hidden pointer.
    // Exception: 256/512-bit vectors are returned in YMM0/ZMM0.
    layout->return_value_in_memory =
        (ret_is_aggregate && ret_type->category != INFIX_TYPE_VECTOR && ret_type->size > 16);
    // Rule 2: Small aggregates (<= 16 bytes) must also be returned via hidden pointer
    // if their classification is MEMORY. This is critical for types like packed structs
    // with unaligned members.
    if (ret_is_aggregate && !layout->return_value_in_memory) {
        arg_class_t ret_classes[2];
        size_t num_ret_classes;
        classify_aggregate_sysv(ret_type, ret_classes, &num_ret_classes);
        if (num_ret_classes > 0 && ret_classes[0] == MEMORY)
            layout->return_value_in_memory = true;
    }
    // Exception: `long double` is a special case and is always returned on the x87
    // FPU stack, never via a hidden pointer.
    if (is_long_double(ret_type))
        layout->return_value_in_memory = false;
    // If a hidden pointer is used, it consumes the first GPR (RDI).
    if (layout->return_value_in_memory)
        gpr_count++;
    layout->num_stack_args = 0;
    // Main Argument Classification Loop
    for (size_t i = 0; i < num_args; ++i) {
        infix_type * type = arg_types[i];
        // Security: Reject excessively large types before they reach the code generator.
        if (type->size > INFIX_MAX_ARG_SIZE) {
            *out_layout = nullptr;
            return INFIX_ERROR_LAYOUT_FAILED;



( run in 0.628 second using v1.01-cache-2.11-cpan-39bf76dae61 )