Skip to content

Commit e823288

Browse files
committed
Teach rustc about the Xtensa call ABI.
1 parent b37a448 commit e823288

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed

compiler/rustc_target/src/abi/call/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ mod wasm;
2929
mod x86;
3030
mod x86_64;
3131
mod x86_win64;
32+
mod xtensa;
3233

3334
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
3435
pub enum PassMode {
@@ -903,6 +904,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
903904
}
904905
}
905906
"hexagon" => hexagon::compute_abi_info(self),
907+
"xtensa" => xtensa::compute_abi_info(cx, self),
906908
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
907909
"wasm32" | "wasm64" => {
908910
if cx.target_spec().adjust_abi(cx, abi, self.c_variadic) == spec::abi::Abi::Wasm {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//! The Xtensa ABI implementation
2+
//!
3+
//! This ABI implementation is based on the following sources:
4+
//!
5+
//! Section 8.1.4 & 8.1.5 of the Xtensa ISA reference manual, as well as snippets from
6+
//! Section 2.3 from the Xtensa programmers guide.
7+
8+
use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
9+
use crate::abi::{Abi, HasDataLayout, Size, TyAbiInterface};
10+
use crate::spec::HasTargetSpec;
11+
12+
const NUM_ARG_GPRS: u64 = 6;
13+
const NUM_RET_GPRS: u64 = 4;
14+
const MAX_ARG_IN_REGS_SIZE: u64 = NUM_ARG_GPRS * 32;
15+
const MAX_RET_IN_REGS_SIZE: u64 = NUM_RET_GPRS * 32;
16+
17+
fn classify_ret_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>)
18+
where
19+
Ty: TyAbiInterface<'a, C> + Copy,
20+
{
21+
if arg.is_ignore() {
22+
return;
23+
}
24+
25+
// The rules for return and argument types are the same,
26+
// so defer to `classify_arg_ty`.
27+
let mut arg_gprs_left = NUM_RET_GPRS;
28+
classify_arg_ty(arg, &mut arg_gprs_left, MAX_RET_IN_REGS_SIZE);
29+
// Ret args cannot be passed via stack, we lower to indirect and let the backend handle the invisble reference
30+
match arg.mode {
31+
super::PassMode::Indirect { attrs: _, meta_attrs: _, ref mut on_stack } => {
32+
*on_stack = false;
33+
}
34+
_ => {}
35+
}
36+
}
37+
38+
fn classify_arg_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>, arg_gprs_left: &mut u64, max_size: u64)
39+
where
40+
Ty: TyAbiInterface<'a, C> + Copy,
41+
{
42+
assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow");
43+
44+
// Ignore empty structs/unions.
45+
if arg.layout.is_zst() {
46+
return;
47+
}
48+
49+
let size = arg.layout.size.bits();
50+
let needed_align = arg.layout.align.abi.bits();
51+
let mut must_use_stack = false;
52+
53+
// Determine the number of GPRs needed to pass the current argument
54+
// according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
55+
// register pairs, so may consume 3 registers.
56+
let mut needed_arg_gprs = (size + 32 - 1) / 32;
57+
if needed_align == 64 {
58+
needed_arg_gprs += *arg_gprs_left % 2;
59+
}
60+
61+
if needed_arg_gprs > *arg_gprs_left
62+
|| needed_align > 128
63+
|| (*arg_gprs_left < (max_size / 32) && needed_align == 128)
64+
{
65+
must_use_stack = true;
66+
needed_arg_gprs = *arg_gprs_left;
67+
}
68+
*arg_gprs_left -= needed_arg_gprs;
69+
70+
if must_use_stack {
71+
arg.make_indirect_byval(None);
72+
} else {
73+
if is_xtensa_aggregate(arg) {
74+
// Aggregates which are <= max_size will be passed in
75+
// registers if possible, so coerce to integers.
76+
77+
// Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment
78+
// is required, and a 2-element `xlen` array if only `xlen` alignment is
79+
// required.
80+
if size <= 32 {
81+
arg.cast_to(Reg::i32());
82+
} else {
83+
let reg = if needed_align == 2 * 32 { Reg::i64() } else { Reg::i32() };
84+
let total = Size::from_bits(((size + 32 - 1) / 32) * 32);
85+
arg.cast_to(Uniform::new(reg, total));
86+
}
87+
} else {
88+
// All integral types are promoted to `xlen`
89+
// width.
90+
//
91+
// We let the LLVM backend handle integral types >= xlen.
92+
if size < 32 {
93+
arg.extend_integer_width_to(32);
94+
}
95+
}
96+
}
97+
}
98+
99+
pub fn compute_abi_info<'a, Ty, C>(_cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
100+
where
101+
Ty: TyAbiInterface<'a, C> + Copy,
102+
C: HasDataLayout + HasTargetSpec,
103+
{
104+
if !fn_abi.ret.is_ignore() {
105+
classify_ret_ty(&mut fn_abi.ret);
106+
}
107+
108+
let mut arg_gprs_left = NUM_ARG_GPRS;
109+
110+
for arg in fn_abi.args.iter_mut() {
111+
if arg.is_ignore() {
112+
continue;
113+
}
114+
classify_arg_ty(arg, &mut arg_gprs_left, MAX_ARG_IN_REGS_SIZE);
115+
}
116+
}
117+
118+
fn is_xtensa_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool {
119+
match arg.layout.abi {
120+
Abi::Vector { .. } => true,
121+
_ => arg.layout.is_aggregate(),
122+
}
123+
}

0 commit comments

Comments
 (0)