Skip to content

Commit 10a7543

Browse files
committed
Refactor call ABI.
1 parent 112ee62 commit 10a7543

File tree

1 file changed

+50
-43
lines changed

1 file changed

+50
-43
lines changed
+50-43
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,81 @@
11
// reference: https://github.com/espressif/clang-xtensa/commit/6fb488d2553f06029e6611cf81c6efbd45b56e47#diff-aa74ae1e1ab6b7149789237edb78e688R8450
22

33
use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
4+
use crate::abi::{Abi, Size};
45

5-
const NUM_ARG_GPR: u64 = 6;
6+
const NUM_ARG_GPRS: u64 = 6;
67
const MAX_ARG_IN_REGS_SIZE: u64 = 4 * 32;
7-
// const MAX_ARG_DIRECT_SIZE: u64 = MAX_ARG_IN_REGS_SIZE;
88
const MAX_RET_IN_REGS_SIZE: u64 = 2 * 32;
99

1010
fn classify_ret_ty<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64) {
11-
// The rules for return and argument types are the same, so defer to
12-
// classify_arg_ty.
13-
let mut remaining_gpr = 2;
11+
if arg.is_ignore() {
12+
return;
13+
}
14+
15+
// The rules for return and argument types are the same,
16+
// so defer to `classify_arg_ty`.
17+
let mut arg_gprs_left = 2;
1418
let fixed = true;
15-
classify_arg_ty(arg, xlen, fixed, &mut remaining_gpr);
19+
classify_arg_ty(arg, xlen, fixed, &mut arg_gprs_left);
1620
}
1721

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

21-
let arg_size = arg.layout.size;
22-
let alignment = arg.layout.align.abi;
25+
// Ignore empty structs/unions.
26+
if arg.layout.is_zst() {
27+
return;
28+
}
29+
30+
let size = arg.layout.size.bits();
31+
let needed_align = arg.layout.align.abi.bits();
32+
let mut must_use_stack = false;
2333

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

29-
if !fixed && alignment.bits() == 2 * xlen {
30-
required_gpr = 2 + (*remaining_gpr % 2);
31-
} else if arg_size.bits() > xlen && arg_size.bits() <= MAX_ARG_IN_REGS_SIZE {
32-
required_gpr = (arg_size.bits() + xlen - 1) / xlen;
39+
if !fixed && needed_align == 2 * xlen {
40+
needed_arg_gprs = 2 + (*arg_gprs_left % 2);
41+
} else if size > xlen && size <= MAX_ARG_IN_REGS_SIZE {
42+
needed_arg_gprs = (size + xlen - 1) / xlen;
3343
}
3444

35-
let mut stack_required = false;
36-
if required_gpr > *remaining_gpr {
37-
stack_required = true;
38-
required_gpr = *remaining_gpr;
45+
if needed_arg_gprs > *arg_gprs_left {
46+
must_use_stack = true;
47+
needed_arg_gprs = *arg_gprs_left;
3948
}
40-
*remaining_gpr -= required_gpr;
49+
*arg_gprs_left -= needed_arg_gprs;
4150

42-
if !arg.layout.is_aggregate() {
43-
// All integral types are promoted to XLen width, unless passed on the
44-
// stack.
45-
if arg_size.bits() < xlen && !stack_required {
51+
if !arg.layout.is_aggregate() && !matches!(arg.layout.abi, Abi::Vector { .. }) {
52+
// All integral types are promoted to `xlen`
53+
// width, unless passed on the stack.
54+
if size < xlen && !must_use_stack {
4655
arg.extend_integer_width_to(xlen);
4756
return;
4857
}
4958

5059
return;
5160
}
5261

53-
// Aggregates which are <= 4 * 32 will be passed in registers if possible,
54-
// so coerce to integers.
55-
if arg_size.bits() as u64 <= MAX_ARG_IN_REGS_SIZE {
56-
// Use a single XLen int if possible, 2*XLen if 2*XLen alignment is
57-
// required, and a 2-element XLen array if only XLen alignment is
62+
// Aggregates which are <= 4 * 32 will be passed in
63+
// registers if possible, so coerce to integers.
64+
if size as u64 <= MAX_ARG_IN_REGS_SIZE {
65+
let alignment = arg.layout.align.abi.bits();
66+
67+
// Use a single `xlen` int if possible, 2 * `xlen` if 2 * `xlen` alignment
68+
// is required, and a 2-element `xlen` array if only `xlen` alignment is
5869
// required.
59-
if arg_size.bits() <= xlen {
60-
arg.cast_to(Uniform { unit: Reg::i32(), total: arg_size });
70+
if size <= xlen {
71+
arg.cast_to(Reg::i32());
6172
return;
62-
} else if alignment.bits() == 2 * xlen {
63-
arg.cast_to(Uniform { unit: Reg::i64(), total: arg_size });
73+
} else if alignment == 2 * xlen {
74+
arg.cast_to(Reg::i64());
6475
return;
6576
} else {
66-
arg.extend_integer_width_to((arg_size.bits() + xlen - 1) / xlen);
77+
let total = Size::from_bits(((size + xlen - 1) / xlen) * xlen);
78+
arg.cast_to(Uniform { unit: Reg::i32(), total });
6779
return;
6880
}
6981
}
@@ -72,20 +84,15 @@ fn classify_arg_ty<Ty>(arg: &mut ArgAbi<'_, Ty>, xlen: u64, fixed: bool, remaini
7284
}
7385

7486
pub fn compute_abi_info<Ty>(fty: &mut FnAbi<'_, Ty>, xlen: u64) {
75-
if !fty.ret.is_ignore() {
76-
classify_ret_ty(&mut fty.ret, xlen);
77-
}
87+
classify_ret_ty(&mut fty.ret, xlen);
7888

79-
let return_indirect =
89+
let is_ret_indirect =
8090
fty.ret.is_indirect() || fty.ret.layout.size.bits() > MAX_RET_IN_REGS_SIZE;
8191

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

8494
for arg in &mut fty.args {
85-
if arg.is_ignore() {
86-
continue;
87-
}
8895
let fixed = true;
89-
classify_arg_ty(arg, xlen, fixed, &mut remaining_gpr);
96+
classify_arg_ty(arg, xlen, fixed, &mut arg_gprs_left);
9097
}
9198
}

0 commit comments

Comments
 (0)