use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
use crate::abi::{Abi, HasDataLayout, Size, TyAbiInterface};
use crate::spec::HasTargetSpec;
const NUM_ARG_GPRS: u64 = 6;
const NUM_RET_GPRS: u64 = 4;
const MAX_ARG_IN_REGS_SIZE: u64 = NUM_ARG_GPRS * 32;
const MAX_RET_IN_REGS_SIZE: u64 = NUM_RET_GPRS * 32;
fn classify_ret_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>)
where
Ty: TyAbiInterface<'a, C> + Copy,
{
if arg.is_ignore() {
return;
}
let mut arg_gprs_left = NUM_RET_GPRS;
classify_arg_ty(arg, &mut arg_gprs_left, MAX_RET_IN_REGS_SIZE);
match arg.mode {
super::PassMode::Indirect { attrs: _, meta_attrs: _, ref mut on_stack } => {
*on_stack = false;
}
_ => {}
}
}
fn classify_arg_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>, arg_gprs_left: &mut u64, max_size: u64)
where
Ty: TyAbiInterface<'a, C> + Copy,
{
assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow");
if arg.layout.is_zst() {
return;
}
let size = arg.layout.size.bits();
let needed_align = arg.layout.align.abi.bits();
let mut must_use_stack = false;
let mut needed_arg_gprs = (size + 32 - 1) / 32;
if needed_align == 64 {
needed_arg_gprs += *arg_gprs_left % 2;
}
if needed_arg_gprs > *arg_gprs_left
|| needed_align > 128
|| (*arg_gprs_left < (max_size / 32) && needed_align == 128)
{
must_use_stack = true;
needed_arg_gprs = *arg_gprs_left;
}
*arg_gprs_left -= needed_arg_gprs;
if must_use_stack {
arg.make_indirect_byval(None);
} else {
if is_xtensa_aggregate(arg) {
if size <= 32 {
arg.cast_to(Reg::i32());
} else {
let reg = if needed_align == 2 * 32 { Reg::i64() } else { Reg::i32() };
let total = Size::from_bits(((size + 32 - 1) / 32) * 32);
arg.cast_to(Uniform::new(reg, total));
}
} else {
if size < 32 {
arg.extend_integer_width_to(32);
}
}
}
}
pub fn compute_abi_info<'a, Ty, C>(_cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec,
{
if !fn_abi.ret.is_ignore() {
classify_ret_ty(&mut fn_abi.ret);
}
let mut arg_gprs_left = NUM_ARG_GPRS;
for arg in fn_abi.args.iter_mut() {
if arg.is_ignore() {
continue;
}
classify_arg_ty(arg, &mut arg_gprs_left, MAX_ARG_IN_REGS_SIZE);
}
}
fn is_xtensa_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool {
match arg.layout.abi {
Abi::Vector { .. } => true,
_ => arg.layout.is_aggregate(),
}
}