Affix

 view release on metacpan or  search on metacpan

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

        size_t end_offset = start_offset + type->size - 1;
        size_t start_eightbyte = start_offset / 8;
        size_t end_eightbyte = end_offset / 8;
        arg_class_t new_class = (is_float16(type) || is_float(type) || is_double(type)) ? SSE : INTEGER;
        for (size_t index = start_eightbyte; index <= end_eightbyte && index < 2; ++index) {
            // Merge the new class with the existing class for this eightbyte.
            // The rule is: if an eightbyte contains both SSE and INTEGER parts, it is classified as INTEGER.
            if (classes[index] != new_class)
                classes[index] = (classes[index] == NO_CLASS) ? new_class : INTEGER;
        }
        return false;
    }
    if (type->category == INFIX_TYPE_POINTER) {
        (*field_count)++;
        size_t index = offset / 8;
        if (index < 2 && classes[index] != INTEGER)
            classes[index] = INTEGER;  // Pointers are always INTEGER class. Merge with existing class.
        return false;
    }
    if (type->category == INFIX_TYPE_ARRAY) {
        if (type->meta.array_info.element_type == nullptr)
            return false;
        // If the array elements have no size, iterating over them is pointless
        // and can cause a timeout if num_elements is large, as the offset never advances.
        // We only need to classify the element type once at the starting offset.
        if (type->meta.array_info.element_type->size == 0) {
            if (type->meta.array_info.num_elements > 0)
                // Classify the zero-sized element just once.
                return classify_recursive(
                    type->meta.array_info.element_type, offset, classes, depth + 1, field_count, false);
            return false;  // An empty array of zero-sized structs has no effect on classification.
        }
        for (size_t i = 0; i < type->meta.array_info.num_elements; ++i) {
            // Check count *before* each recursive call inside the loop.
            if (*field_count > MAX_AGGREGATE_FIELDS_TO_CLASSIFY) {
                classes[0] = MEMORY;
                return true;
            }
            size_t element_offset = offset + i * type->meta.array_info.element_type->size;
            // If we are already past the 16-byte boundary relevant for
            // register passing, there is no need to classify further. This prunes
            // the recursion tree for large arrays.
            if (element_offset >= 16)
                break;
            if (classify_recursive(
                    type->meta.array_info.element_type, element_offset, classes, depth + 1, field_count, false))
                return true;  // Propagate unaligned discovery up the call stack
        }
        return false;
    }
    if (type->category == INFIX_TYPE_COMPLEX) {
        infix_type * base = type->meta.complex_info.base_type;
        // A zero-sized base type would cause infinite recursion.
        // Treat this as a malformed type and stop classification.
        if (base == nullptr || base->size == 0)
            return false;
        // A complex number is just like a struct { base_type real; base_type imag; }
        // So we classify the first element at offset 0.
        if (classify_recursive(base, offset, classes, depth + 1, field_count, false))
            return true;  // Propagate unaligned discovery
        // And the second element at offset + size of the base.
        if (classify_recursive(base, offset + base->size, classes, depth + 1, field_count, false))
            return true;  // Propagate unaligned discovery
        return false;
    }
    if (type->category == INFIX_TYPE_VECTOR) {
        (*field_count)++;
        size_t num_eightbytes = (type->size + 7) / 8;
        for (size_t i = 0; i < num_eightbytes && (offset / 8 + i) < 2; ++i) {
            // Merging rule: if an eightbyte contains both SSE and INTEGER parts, it is INTEGER.
            // If it's NO_CLASS, it becomes SSE.
            if (classes[offset / 8 + i] == NO_CLASS)
                classes[offset / 8 + i] = SSE;
        }
        return false;
    }
    if (type->category == INFIX_TYPE_STRUCT || type->category == INFIX_TYPE_UNION) {
        // A generated type can have num_members > 0 but a NULL members pointer.
        // This is invalid and must be passed in memory.
        if (type->meta.aggregate_info.members == nullptr) {
            classes[0] = MEMORY;
            return true;
        }
        // Recursively classify each member of the struct/union.
        for (size_t i = 0; i < type->meta.aggregate_info.num_members; ++i) {
            // Check count *before* each recursive call inside the loop.
            if (*field_count > MAX_AGGREGATE_FIELDS_TO_CLASSIFY) {
                classes[0] = MEMORY;
                return true;
            }
            infix_struct_member * member = &type->meta.aggregate_info.members[i];
            // A generated type can have a NULL member type.
            // This is invalid, and the aggregate must be passed in memory.
            if (member->type == nullptr) {
                classes[0] = MEMORY;
                return true;
            }
            size_t member_offset = offset + member->offset;
            // If this member starts at or after the 16-byte boundary,
            // it cannot influence register classification, so we can skip it.
            if (member_offset >= 16)
                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) {



( run in 0.756 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )