Affix
view release on metacpan or search on metacpan
infix/src/arch/riscv/abi_riscv64.c view on Meta::CPAN
}
return cls;
}
if (type->size > 8) {
if (is_variadic_arg) {
// Variadic 2xXLEN: an aligned (even) register pair when the type's
// alignment is 2xXLEN bits, a plain pair otherwise; never split.
bool needs_even = (type->alignment >= 16);
if ((*gpr_count + 1 >= RV_NUM_GPR_ARGS) || (needs_even && (*gpr_count % 2 != 0))) {
*variadic_stack_mode = true;
cls.type = ARG_LOCATION_STACK;
cls.stack_offset = rv64_stack_place(stack_offset, type);
return cls;
}
cls.type = ARG_LOCATION_GPR_PAIR;
cls.reg_index = (uint8_t)*gpr_count;
*gpr_count += 2;
return cls;
}
// Named: exactly one GPR left -> low half in that register, high half on the stack.
if (*gpr_count == RV_NUM_GPR_ARGS - 1) {
cls.type = ARG_LOCATION_GPR_STACK_SPLIT;
cls.reg_index = (uint8_t)(*gpr_count)++;
uint32_t off = (uint32_t)((*stack_offset + 7) & ~7);
cls.stack_offset = off;
*stack_offset = off + 8;
return cls;
}
if (*gpr_count + 1 < RV_NUM_GPR_ARGS) {
cls.type = ARG_LOCATION_GPR_PAIR;
cls.reg_index = (uint8_t)*gpr_count;
*gpr_count += 2;
}
else {
cls.type = ARG_LOCATION_STACK;
cls.stack_offset = rv64_stack_place(stack_offset, type);
}
return cls;
}
if (*gpr_count < RV_NUM_GPR_ARGS) {
cls.type = ARG_LOCATION_GPR;
cls.reg_index = (uint8_t)(*gpr_count)++;
}
else {
if (is_variadic_arg)
*variadic_stack_mode = true;
cls.type = ARG_LOCATION_STACK;
cls.stack_offset = rv64_stack_place(stack_offset, type);
}
return cls;
}
/**
* @internal
* @brief Classify a single argument into its physical ABI location.
* @param type The argument's type.
* @param is_variadic_arg `true` for arguments beyond `num_fixed_args`.
* @param gpr_count The running GPR index (starts at 1 if a0 holds the sret pointer).
* @param vpr_count The running FPR index.
* @param stack_offset The running outgoing/caller stack offset.
* @param variadic_stack_mode Sticky flag: once set, all variadic args go on the stack.
*/
static rv64_arg_class rv64_classify_arg(infix_type * type,
bool is_variadic_arg,
size_t * gpr_count,
size_t * vpr_count,
uint32_t * stack_offset,
bool * variadic_stack_mode) {
rv64_arg_class cls = {.type = ARG_LOCATION_STACK, .num_regs = 1};
// Arrays decay to pointers and are always passed as 8-byte values.
if (type->category == INFIX_TYPE_ARRAY) {
if (!*variadic_stack_mode && *gpr_count < RV_NUM_GPR_ARGS) {
cls.type = ARG_LOCATION_GPR;
cls.reg_index = (uint8_t)(*gpr_count)++;
}
else {
if (is_variadic_arg)
*variadic_stack_mode = true;
cls.type = ARG_LOCATION_STACK;
*stack_offset = (*stack_offset + 7) & ~7;
cls.stack_offset = *stack_offset;
*stack_offset += 8;
}
return cls;
}
// Once any variadic argument has been placed on the stack, all the rest are too.
if (is_variadic_arg && *variadic_stack_mode) {
cls.type = ARG_LOCATION_STACK;
cls.stack_offset = rv64_stack_place(stack_offset, type);
return cls;
}
// Variadic arguments use the integer calling convention (GPRs).
if (is_variadic_arg)
return rv64_classify_integer(type, true, gpr_count, stack_offset, variadic_stack_mode);
// Named single-precision / double-precision scalars.
if (is_float(type) || is_double(type)) {
if (*vpr_count < RV_NUM_FPR_ARGS) {
cls.type = ARG_LOCATION_VPR;
cls.reg_index = (uint8_t)(*vpr_count)++;
cls.num_regs = 1;
}
else {
// FPRs are exhausted: the psABI spills FP reals into the integer
// argument registers (a0-a7) before they go on the stack.
return rv64_classify_integer(type, false, gpr_count, stack_offset, variadic_stack_mode);
}
return cls;
}
// Aggregates: > 16 bytes pass by reference; the psABI hardware FP rules apply
// to aggregates of at most 2xXLEN bytes with at most two FP members.
bool is_aggregate = (type->category == INFIX_TYPE_STRUCT || type->category == INFIX_TYPE_UNION ||
type->category == INFIX_TYPE_COMPLEX);
if (is_aggregate) {
if (type->size > 16) {
if (!*variadic_stack_mode && *gpr_count < RV_NUM_GPR_ARGS) {
cls.type = ARG_LOCATION_GPR_REFERENCE;
( run in 0.538 second using v1.01-cache-2.11-cpan-a49fcb8fa48 )