Skip to content

Commit 0c11a48

Browse files
MabezDevkelnos
authored andcommitted
Teach rustc about the Xtensa call ABI.
1 parent e05a6bc commit 0c11a48

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

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

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod amdgpu;
77
mod arm;
88
mod avr;
99
mod hexagon;
10+
mod xtensa;
1011
mod mips;
1112
mod mips64;
1213
mod msp430;
@@ -604,6 +605,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
604605
"nvptx" => nvptx::compute_abi_info(self),
605606
"nvptx64" => nvptx64::compute_abi_info(self),
606607
"hexagon" => hexagon::compute_abi_info(self),
608+
"xtensa" => xtensa::compute_abi_info(cx, self),
607609
"riscv32" | "riscv64" => riscv::compute_abi_info(cx, self),
608610
"wasm32" if cx.target_spec().os != "emscripten" => {
609611
wasm32_bindgen_compat::compute_abi_info(self)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// reference: https://github.com/MabezDev/llvm-project/blob/xtensa_release_9.0.1_with_rust_patches-31-05-2020-cherry-pick/clang/lib/CodeGen/TargetInfo.cpp#L9668-L9767
2+
3+
use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
4+
use crate::abi::{HasDataLayout, LayoutOf, TyAndLayout, TyAndLayoutMethods,Abi, Size};
5+
use crate::spec::HasTargetSpec;
6+
7+
const NUM_ARG_GPRS: u64 = 6;
8+
const MAX_ARG_IN_REGS_SIZE: u64 = 4 * 32;
9+
const MAX_RET_IN_REGS_SIZE: u64 = 2 * 32;
10+
11+
fn classify_ret_ty<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) {
12+
if arg.is_ignore() {
13+
return;
14+
}
15+
16+
// The rules for return and argument types are the same,
17+
// so defer to `classify_arg_ty`.
18+
let mut arg_gprs_left = 2;
19+
let fixed = true;
20+
classify_arg_ty(arg, xlen, fixed, &mut arg_gprs_left);
21+
}
22+
23+
fn classify_arg_ty<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64, fixed: bool, arg_gprs_left: &mut u64) {
24+
assert!(*arg_gprs_left <= NUM_ARG_GPRS, "Arg GPR tracking underflow");
25+
26+
// Ignore empty structs/unions.
27+
if arg.layout.is_zst() {
28+
return;
29+
}
30+
31+
let size = arg.layout.size.bits();
32+
let needed_align = arg.layout.align.abi.bits();
33+
let mut must_use_stack = false;
34+
35+
// Determine the number of GPRs needed to pass the current argument
36+
// according to the ABI. 2*XLen-aligned varargs are passed in "aligned"
37+
// register pairs, so may consume 3 registers.
38+
let mut needed_arg_gprs = 1u64;
39+
40+
if !fixed && needed_align == 2 * xlen {
41+
needed_arg_gprs = 2 + (*arg_gprs_left % 2);
42+
} else if size > xlen && size <= MAX_ARG_IN_REGS_SIZE {
43+
needed_arg_gprs = (size + xlen - 1) / xlen;
44+
}
45+
46+
if needed_arg_gprs > *arg_gprs_left {
47+
must_use_stack = true;
48+
needed_arg_gprs = *arg_gprs_left;
49+
}
50+
*arg_gprs_left -= needed_arg_gprs;
51+
52+
if !arg.layout.is_aggregate() && !matches!(arg.layout.abi, Abi::Vector { .. }) {
53+
// All integral types are promoted to `xlen`
54+
// width, unless passed on the stack.
55+
if size < xlen && !must_use_stack {
56+
arg.extend_integer_width_to(xlen);
57+
return;
58+
}
59+
60+
return;
61+
}
62+
63+
// Aggregates which are <= 4 * 32 will be passed in
64+
// registers if possible, so coerce to integers.
65+
if size as u64 <= MAX_ARG_IN_REGS_SIZE {
66+
let alignment = arg.layout.align.abi.bits();
67+
68+
// Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment
69+
// is required, and a 2-element `xlen` array if only `xlen` alignment is
70+
// required.
71+
if size <= xlen {
72+
arg.cast_to(Reg::i32());
73+
return;
74+
} else if alignment == 2 * xlen {
75+
arg.cast_to(Reg::i64());
76+
return;
77+
} else {
78+
let total = Size::from_bits(((size + xlen - 1) / xlen) * xlen);
79+
arg.cast_to(Uniform { unit: Reg::i32(), total });
80+
return;
81+
}
82+
}
83+
84+
arg.make_indirect();
85+
}
86+
87+
pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
88+
where
89+
Ty: TyAndLayoutMethods<'a, C> + Copy,
90+
C: LayoutOf<Ty = Ty, TyAndLayout = TyAndLayout<'a, Ty>> + HasDataLayout + HasTargetSpec,
91+
{
92+
let xlen = cx.data_layout().pointer_size.bits();
93+
94+
if !fn_abi.ret.is_ignore() {
95+
classify_ret_ty(&mut fn_abi.ret, xlen);
96+
}
97+
98+
let is_ret_indirect =
99+
fn_abi.ret.is_indirect() || fn_abi.ret.layout.size.bits() > MAX_RET_IN_REGS_SIZE;
100+
101+
let mut arg_gprs_left = if is_ret_indirect { NUM_ARG_GPRS - 1 } else { NUM_ARG_GPRS };
102+
103+
for arg in &mut fn_abi.args {
104+
if arg.is_ignore() {
105+
continue;
106+
}
107+
let fixed = true;
108+
classify_arg_ty(arg, xlen, fixed, &mut arg_gprs_left);
109+
}
110+
}

0 commit comments

Comments
 (0)