Skip to content

Commit

Permalink
Refactor call ABI.
Browse files Browse the repository at this point in the history
  • Loading branch information
reitermarkus committed Jun 15, 2020
1 parent 112ee62 commit 10a7543
Showing 1 changed file with 50 additions and 43 deletions.
93 changes: 50 additions & 43 deletions src/librustc_target/abi/call/xtensa.rs
Original file line number Diff line number Diff line change
@@ -1,69 +1,81 @@
// reference: https://github.com/espressif/clang-xtensa/commit/6fb488d2553f06029e6611cf81c6efbd45b56e47#diff-aa74ae1e1ab6b7149789237edb78e688R8450

use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
use crate::abi::{Abi, Size};

const NUM_ARG_GPR: u64 = 6;
const NUM_ARG_GPRS: u64 = 6;
const MAX_ARG_IN_REGS_SIZE: u64 = 4 * 32;
// const MAX_ARG_DIRECT_SIZE: u64 = MAX_ARG_IN_REGS_SIZE;
const MAX_RET_IN_REGS_SIZE: u64 = 2 * 32;

fn classify_ret_ty<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) {
// The rules for return and argument types are the same, so defer to
// classify_arg_ty.
let mut remaining_gpr = 2;
if arg.is_ignore() {
return;
}

// The rules for return and argument types are the same,
// so defer to `classify_arg_ty`.
let mut arg_gprs_left = 2;
let fixed = true;
classify_arg_ty(arg, xlen, fixed, &mut remaining_gpr);
classify_arg_ty(arg, xlen, fixed, &mut arg_gprs_left);
}

fn classify_arg_ty<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64, fixed: bool, remaining_gpr: &mut u64) {
assert!(*remaining_gpr <= NUM_ARG_GPR, "Arg GPR tracking underflow");
fn classify_arg_ty<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64, fixed: bool, arg_gprs_left: &mut u64) {
assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow");

let arg_size = arg.layout.size;
let alignment = arg.layout.align.abi;
// Ignore empty structs/unions.
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;

// Determine the number of GPRs needed to pass the current argument
// according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
// register pairs, so may consume 3 registers.
let mut required_gpr = 1u64;
let mut needed_arg_gprs = 1u64;

if !fixed && alignment.bits() == 2 * xlen {
required_gpr = 2 + (*remaining_gpr % 2);
} else if arg_size.bits() > xlen && arg_size.bits() <= MAX_ARG_IN_REGS_SIZE {
required_gpr = (arg_size.bits() + xlen - 1) / xlen;
if !fixed && needed_align == 2 * xlen {
needed_arg_gprs = 2 + (*arg_gprs_left % 2);
} else if size > xlen && size <= MAX_ARG_IN_REGS_SIZE {
needed_arg_gprs = (size + xlen - 1) / xlen;
}

let mut stack_required = false;
if required_gpr > *remaining_gpr {
stack_required = true;
required_gpr = *remaining_gpr;
if needed_arg_gprs > *arg_gprs_left {
must_use_stack = true;
needed_arg_gprs = *arg_gprs_left;
}
*remaining_gpr -= required_gpr;
*arg_gprs_left -= needed_arg_gprs;

if !arg.layout.is_aggregate() {
// All integral types are promoted to XLen width, unless passed on the
// stack.
if arg_size.bits() < xlen && !stack_required {
if !arg.layout.is_aggregate() && !matches!(arg.layout.abi, Abi::Vector { .. }) {
// All integral types are promoted to `xlen`
// width, unless passed on the stack.
if size < xlen && !must_use_stack {
arg.extend_integer_width_to(xlen);
return;
}

return;
}

// Aggregates which are <= 4 * 32 will be passed in registers if possible,
// so coerce to integers.
if arg_size.bits() as u64 <= MAX_ARG_IN_REGS_SIZE {
// Use a single XLen int if possible, 2*XLen if 2*XLen alignment is
// required, and a 2-element XLen array if only XLen alignment is
// Aggregates which are <= 4 * 32 will be passed in
// registers if possible, so coerce to integers.
if size as u64 <= MAX_ARG_IN_REGS_SIZE {
let alignment = arg.layout.align.abi.bits();

// Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment
// is required, and a 2-element `xlen` array if only `xlen` alignment is
// required.
if arg_size.bits() <= xlen {
arg.cast_to(Uniform { unit: Reg::i32(), total: arg_size });
if size <= xlen {
arg.cast_to(Reg::i32());
return;
} else if alignment.bits() == 2 * xlen {
arg.cast_to(Uniform { unit: Reg::i64(), total: arg_size });
} else if alignment == 2 * xlen {
arg.cast_to(Reg::i64());
return;
} else {
arg.extend_integer_width_to((arg_size.bits() + xlen - 1) / xlen);
let total = Size::from_bits(((size + xlen - 1) / xlen) * xlen);
arg.cast_to(Uniform { unit: Reg::i32(), total });
return;
}
}
Expand All @@ -72,20 +84,15 @@ fn classify_arg_ty<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64, fixed: bool, remaini
}

pub fn compute_abi_info<Ty>(fty: &mut FnAbi<'_, Ty>, xlen: u64) {
if !fty.ret.is_ignore() {
classify_ret_ty(&mut fty.ret, xlen);
}
classify_ret_ty(&mut fty.ret, xlen);

let return_indirect =
let is_ret_indirect =
fty.ret.is_indirect() || fty.ret.layout.size.bits() > MAX_RET_IN_REGS_SIZE;

let mut remaining_gpr = if return_indirect { NUM_ARG_GPR - 1 } else { NUM_ARG_GPR };
let mut arg_gprs_left = if is_ret_indirect { NUM_ARG_GPRS - 1 } else { NUM_ARG_GPRS };

for arg in &mut fty.args {
if arg.is_ignore() {
continue;
}
let fixed = true;
classify_arg_ty(arg, xlen, fixed, &mut remaining_gpr);
classify_arg_ty(arg, xlen, fixed, &mut arg_gprs_left);
}
}

0 comments on commit 10a7543

Please sign in to comment.