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 )