Skip to content

Commit 564a0ce

Browse files
committed
fix the Xtensa ABI implementation
1 parent 8b15aaa commit 564a0ce

File tree

1 file changed

+62
-41
lines changed

1 file changed

+62
-41
lines changed
+62-41
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// 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
22

33
use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
4-
use crate::abi::{Abi, HasDataLayout, Size, TyAbiInterface};
4+
use crate::abi::{Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface};
55
use crate::spec::HasTargetSpec;
66

77
const NUM_ARG_GPRS: u64 = 6;
@@ -12,27 +12,41 @@ where
1212
Ty: TyAbiInterface<'a, C> + Copy,
1313
{
1414
let mut arg_gprs_left = NUM_RET_ARG_GPRS;
15-
classify_arg_ty(arg, &mut arg_gprs_left, NUM_RET_ARG_GPRS);
16-
17-
// classify_arg_ty can make the arg indirect by value which is not valid for ret args
18-
match arg.mode {
19-
super::PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => *on_stack = false,
20-
_ => {}
15+
16+
let size = arg.layout.size.align_to(Align::from_bits(32).unwrap());
17+
18+
// The rules for return and argument with type size more then 4 bytes
19+
// are the same, so defer to classifyArgumentType.
20+
if size.bits() > 32 {
21+
classify_arg_ty(arg, &mut arg_gprs_left, NUM_RET_ARG_GPRS);
22+
23+
// classify_arg_ty can make the arg indirect by value which is not valid for ret args
24+
match arg.mode {
25+
super::PassMode::Indirect { attrs: _, extra_attrs: _, ref mut on_stack } => {
26+
*on_stack = false
27+
}
28+
_ => {}
29+
}
30+
} else {
31+
// LLVM DefaultABIInfo::classifyReturnType
32+
if arg.layout.is_aggregate() {
33+
arg.make_indirect()
34+
} else {
35+
arg.extend_integer_width_to(32)
36+
}
2137
}
2238
}
2339

2440
fn classify_arg_ty<'a, Ty, C>(arg: &mut ArgAbi<'_, Ty>, arg_gprs_left: &mut u64, num_gprs: u64)
2541
where
2642
Ty: TyAbiInterface<'a, C> + Copy,
2743
{
28-
assert!(*arg_gprs_left <= num_gprs, "Arg GPR tracking underflow");
44+
assert!(*arg_gprs_left <= num_gprs, "GPR tracking underflow");
2945

3046
if arg.layout.is_zst() {
3147
return; // ignore args that take no size
3248
}
3349

34-
// TODO check is arg has non-trvial constructor
35-
3650
let size = arg.layout.size.bits();
3751
let align = arg.layout.align.abi.bits();
3852
let mut must_use_stack = false;
@@ -43,40 +57,51 @@ where
4357
required_gprs += *arg_gprs_left % 2;
4458
}
4559

46-
// Put on stack objects which are not fit to 6 registers,
60+
// Put on stack objects which are not fit to num_gprs registers,
4761
// also on stack object which alignment more then 16 bytes and
4862
// object with 16-byte alignment if it isn't the first argument.
49-
if required_gprs > *arg_gprs_left || align > 128 || *arg_gprs_left < 6 && align == 128 {
63+
if required_gprs > *arg_gprs_left || align > 128 || *arg_gprs_left < num_gprs && align == 128 {
5064
must_use_stack = true;
5165
required_gprs = *arg_gprs_left;
5266
}
5367
*arg_gprs_left -= required_gprs;
5468

55-
if arg.layout.is_aggregate() && !matches!(arg.layout.abi, Abi::Vector { element: _ , count: _ }) && !must_use_stack {
56-
if size < 32 && !must_use_stack {
57-
arg.extend_integer_width_to(32);
58-
} else if size == 64 {
59-
arg.cast_to(Reg::i64());
69+
if must_use_stack {
70+
arg.make_indirect_byval();
71+
} else {
72+
if arg.layout.is_aggregate()
73+
&& !matches!(arg.layout.abi, Abi::Vector { element: _, count: _ })
74+
{
75+
if size < 32 && matches!(arg.layout.fields, FieldsShape::Primitive) {
76+
arg.extend_integer_width_to(32);
77+
} else if size == 64 {
78+
arg.cast_to(Reg::i64());
79+
} else {
80+
arg.cast_to(Uniform {
81+
unit: Reg::i32(),
82+
total: Size::from_bits(required_gprs * 32),
83+
});
84+
}
85+
} else if size <= num_gprs * 32 {
86+
// Aggregates which are <= num_gprs*32 will be passed in registers if possible,
87+
// so coerce to integers.
88+
if size <= 32 {
89+
arg.cast_to(Reg::i32())
90+
} else if align == 64 {
91+
arg.cast_to(Uniform {
92+
unit: Reg::i64(),
93+
total: Size::from_bits((required_gprs / 2) * 32),
94+
});
95+
} else {
96+
arg.cast_to(Uniform {
97+
unit: Reg::i32(),
98+
total: Size::from_bits(required_gprs * 32),
99+
});
100+
}
60101
} else {
61-
arg.cast_to(Reg::i32());
102+
panic!("unhandled GPR")
62103
}
63-
return;
64104
}
65-
66-
// Aggregates which are <= 6*32 will be passed in registers if possible,
67-
// so coerce to integers.
68-
if size <= (num_gprs * 32) && !must_use_stack {
69-
if size <= 32 {
70-
arg.cast_to(Reg::i32())
71-
} else if align == 64 {
72-
arg.cast_to(Uniform { unit: Reg::i64(), total: Size::from_bits((required_gprs / 2) * 32) });
73-
} else {
74-
arg.cast_to(Uniform { unit: Reg::i32(), total: Size::from_bits(required_gprs * 32) });
75-
}
76-
return;
77-
}
78-
79-
arg.make_indirect_byval()
80105
}
81106

82107
pub fn compute_abi_info<'a, Ty, C>(_cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
@@ -87,17 +112,13 @@ where
87112
if !fn_abi.ret.is_ignore() {
88113
classify_ret_ty(&mut fn_abi.ret);
89114
}
90-
115+
91116
let mut avail_gprs = NUM_ARG_GPRS;
92117

93-
for arg in fn_abi.args.iter_mut(){
118+
for arg in fn_abi.args.iter_mut() {
94119
if arg.is_ignore() {
95120
continue;
96121
}
97-
classify_arg_ty(
98-
arg,
99-
&mut avail_gprs,
100-
NUM_ARG_GPRS
101-
);
122+
classify_arg_ty(arg, &mut avail_gprs, NUM_ARG_GPRS);
102123
}
103124
}

0 commit comments

Comments
 (0)