Skip to content

Commit edda7e9

Browse files
committed
Auto merge of #94216 - psumbera:sparc64-abi-fix2, r=nagisa
more complete sparc64 ABI fix for aggregates with floating point members Previous fix didn't handle nested structures at all.
2 parents 48132ca + 992c27c commit edda7e9

File tree

2 files changed

+196
-100
lines changed

2 files changed

+196
-100
lines changed

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

+176-100
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,212 @@
11
// FIXME: This needs an audit for correctness and completeness.
22

33
use crate::abi::call::{
4-
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Reg, RegKind, Uniform,
4+
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Reg, Uniform,
55
};
6-
use crate::abi::{self, HasDataLayout, Size, TyAbiInterface};
6+
use crate::abi::{self, HasDataLayout, Scalar, Size, TyAbiInterface, TyAndLayout};
7+
8+
#[derive(Clone, Debug)]
9+
pub struct Sdata {
10+
pub prefix: [Option<Reg>; 8],
11+
pub prefix_index: usize,
12+
pub last_offset: Size,
13+
pub has_float: bool,
14+
pub arg_attribute: ArgAttribute,
15+
}
716

8-
fn is_homogeneous_aggregate<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>) -> Option<Uniform>
17+
fn arg_scalar<C>(cx: &C, scalar: &Scalar, offset: Size, mut data: Sdata) -> Sdata
918
where
10-
Ty: TyAbiInterface<'a, C> + Copy,
1119
C: HasDataLayout,
1220
{
13-
arg.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()).and_then(|unit| {
14-
// Ensure we have at most eight uniquely addressable members.
15-
if arg.layout.size > unit.size.checked_mul(8, cx).unwrap() {
16-
return None;
21+
let dl = cx.data_layout();
22+
23+
if scalar.value != abi::F32 && scalar.value != abi::F64 {
24+
return data;
25+
}
26+
27+
data.has_float = true;
28+
29+
if !data.last_offset.is_aligned(dl.f64_align.abi) && data.last_offset < offset {
30+
if data.prefix_index == data.prefix.len() {
31+
return data;
1732
}
33+
data.prefix[data.prefix_index] = Some(Reg::i32());
34+
data.prefix_index += 1;
35+
data.last_offset = data.last_offset + Reg::i32().size;
36+
}
1837

19-
let valid_unit = match unit.kind {
20-
RegKind::Integer => false,
21-
RegKind::Float => false,
22-
RegKind::Vector => arg.layout.size.bits() == 128,
23-
};
38+
for _ in 0..((offset - data.last_offset).bits() / 64)
39+
.min((data.prefix.len() - data.prefix_index) as u64)
40+
{
41+
data.prefix[data.prefix_index] = Some(Reg::i64());
42+
data.prefix_index += 1;
43+
data.last_offset = data.last_offset + Reg::i64().size;
44+
}
2445

25-
valid_unit.then_some(Uniform { unit, total: arg.layout.size })
26-
})
46+
if data.last_offset < offset {
47+
if data.prefix_index == data.prefix.len() {
48+
return data;
49+
}
50+
data.prefix[data.prefix_index] = Some(Reg::i32());
51+
data.prefix_index += 1;
52+
data.last_offset = data.last_offset + Reg::i32().size;
53+
}
54+
55+
if data.prefix_index == data.prefix.len() {
56+
return data;
57+
}
58+
59+
if scalar.value == abi::F32 {
60+
data.arg_attribute = ArgAttribute::InReg;
61+
data.prefix[data.prefix_index] = Some(Reg::f32());
62+
data.last_offset = offset + Reg::f32().size;
63+
} else {
64+
data.prefix[data.prefix_index] = Some(Reg::f64());
65+
data.last_offset = offset + Reg::f64().size;
66+
}
67+
data.prefix_index += 1;
68+
return data;
2769
}
2870

29-
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, in_registers_max: Size)
71+
fn arg_scalar_pair<C>(
72+
cx: &C,
73+
scalar1: &Scalar,
74+
scalar2: &Scalar,
75+
mut offset: Size,
76+
mut data: Sdata,
77+
) -> Sdata
3078
where
31-
Ty: TyAbiInterface<'a, C> + Copy,
3279
C: HasDataLayout,
3380
{
34-
if !arg.layout.is_aggregate() {
35-
arg.extend_integer_width_to(64);
36-
return;
81+
data = arg_scalar(cx, &scalar1, offset, data);
82+
if scalar1.value == abi::F32 {
83+
offset += Reg::f32().size;
84+
} else if scalar2.value == abi::F64 {
85+
offset += Reg::f64().size;
86+
} else if let abi::Int(i, _signed) = scalar1.value {
87+
offset += i.size();
88+
} else if scalar1.value == abi::Pointer {
89+
offset = offset + Reg::i64().size;
3790
}
3891

39-
// This doesn't intentionally handle structures with floats which needs
40-
// special care below.
41-
if let Some(uniform) = is_homogeneous_aggregate(cx, arg) {
42-
arg.cast_to(uniform);
43-
return;
92+
if (offset.raw % 4) != 0 && (scalar2.value == abi::F32 || scalar2.value == abi::F64) {
93+
offset.raw += 4 - (offset.raw % 4);
94+
}
95+
data = arg_scalar(cx, &scalar2, offset, data);
96+
return data;
97+
}
98+
99+
fn parse_structure<'a, Ty, C>(
100+
cx: &C,
101+
layout: TyAndLayout<'a, Ty>,
102+
mut data: Sdata,
103+
mut offset: Size,
104+
) -> Sdata
105+
where
106+
Ty: TyAbiInterface<'a, C> + Copy,
107+
C: HasDataLayout,
108+
{
109+
if let abi::FieldsShape::Union(_) = layout.fields {
110+
return data;
44111
}
45112

46-
if let abi::FieldsShape::Arbitrary { .. } = arg.layout.fields {
47-
let dl = cx.data_layout();
48-
let size = arg.layout.size;
49-
let mut prefix = [None; 8];
50-
let mut prefix_index = 0;
51-
let mut last_offset = Size::ZERO;
52-
let mut has_float = false;
53-
let mut arg_attribute = ArgAttribute::default();
54-
55-
for i in 0..arg.layout.fields.count() {
56-
let field = arg.layout.field(cx, i);
57-
let offset = arg.layout.fields.offset(i);
58-
59-
if let abi::Abi::Scalar(scalar) = &field.abi {
60-
if scalar.value == abi::F32 || scalar.value == abi::F64 {
61-
has_float = true;
62-
63-
if !last_offset.is_aligned(dl.f64_align.abi) && last_offset < offset {
64-
if prefix_index == prefix.len() {
65-
break;
66-
}
67-
prefix[prefix_index] = Some(Reg::i32());
68-
prefix_index += 1;
69-
last_offset = last_offset + Reg::i32().size;
70-
}
71-
72-
for _ in 0..((offset - last_offset).bits() / 64)
73-
.min((prefix.len() - prefix_index) as u64)
74-
{
75-
prefix[prefix_index] = Some(Reg::i64());
76-
prefix_index += 1;
77-
last_offset = last_offset + Reg::i64().size;
78-
}
79-
80-
if last_offset < offset {
81-
if prefix_index == prefix.len() {
82-
break;
83-
}
84-
prefix[prefix_index] = Some(Reg::i32());
85-
prefix_index += 1;
86-
last_offset = last_offset + Reg::i32().size;
87-
}
88-
89-
if prefix_index == prefix.len() {
90-
break;
91-
}
92-
93-
if scalar.value == abi::F32 {
94-
arg_attribute = ArgAttribute::InReg;
95-
prefix[prefix_index] = Some(Reg::f32());
96-
last_offset = offset + Reg::f32().size;
97-
} else {
98-
prefix[prefix_index] = Some(Reg::f64());
99-
last_offset = offset + Reg::f64().size;
100-
}
101-
prefix_index += 1;
113+
match layout.abi {
114+
abi::Abi::Scalar(scalar) => {
115+
data = arg_scalar(cx, &scalar, offset, data);
116+
}
117+
abi::Abi::Aggregate { .. } => {
118+
for i in 0..layout.fields.count().clone() {
119+
if offset < layout.fields.offset(i) {
120+
offset = layout.fields.offset(i);
102121
}
122+
data = parse_structure(cx, layout.field(cx, i).clone(), data.clone(), offset);
103123
}
104124
}
105-
106-
if has_float && arg.layout.size <= in_registers_max {
107-
let mut rest_size = size - last_offset;
108-
109-
if (rest_size.raw % 8) != 0 && prefix_index < prefix.len() {
110-
prefix[prefix_index] = Some(Reg::i32());
111-
rest_size = rest_size - Reg::i32().size;
125+
_ => {
126+
if let abi::Abi::ScalarPair(scalar1, scalar2) = &layout.abi {
127+
data = arg_scalar_pair(cx, scalar1, scalar2, offset, data);
112128
}
113-
114-
arg.cast_to(CastTarget {
115-
prefix,
116-
rest: Uniform { unit: Reg::i64(), total: rest_size },
117-
attrs: ArgAttributes {
118-
regular: arg_attribute,
119-
arg_ext: ArgExtension::None,
120-
pointee_size: Size::ZERO,
121-
pointee_align: None,
122-
},
123-
});
124-
return;
125129
}
126130
}
127131

132+
return data;
133+
}
134+
135+
fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>, in_registers_max: Size)
136+
where
137+
Ty: TyAbiInterface<'a, C> + Copy,
138+
C: HasDataLayout,
139+
{
140+
if !arg.layout.is_aggregate() {
141+
arg.extend_integer_width_to(64);
142+
return;
143+
}
144+
128145
let total = arg.layout.size;
129146
if total > in_registers_max {
130147
arg.make_indirect();
131148
return;
132149
}
133150

151+
match arg.layout.fields {
152+
abi::FieldsShape::Primitive => unreachable!(),
153+
abi::FieldsShape::Array { .. } => {
154+
// Arrays are passed indirectly
155+
arg.make_indirect();
156+
return;
157+
}
158+
abi::FieldsShape::Union(_) => {
159+
// Unions and are always treated as a series of 64-bit integer chunks
160+
}
161+
abi::FieldsShape::Arbitrary { .. } => {
162+
// Stuctures with floating point numbers need special care.
163+
164+
let mut data = parse_structure(
165+
cx,
166+
arg.layout.clone(),
167+
Sdata {
168+
prefix: [None; 8],
169+
prefix_index: 0,
170+
last_offset: Size::ZERO,
171+
has_float: false,
172+
arg_attribute: ArgAttribute::default(),
173+
},
174+
Size { raw: 0 },
175+
);
176+
177+
if data.has_float {
178+
// Structure { float, int, int } doesn't like to be handled like
179+
// { float, long int }. Other way around it doesn't mind.
180+
if data.last_offset < arg.layout.size
181+
&& (data.last_offset.raw % 8) != 0
182+
&& data.prefix_index < data.prefix.len()
183+
{
184+
data.prefix[data.prefix_index] = Some(Reg::i32());
185+
data.prefix_index += 1;
186+
data.last_offset += Reg::i32().size;
187+
}
188+
189+
let mut rest_size = arg.layout.size - data.last_offset;
190+
if (rest_size.raw % 8) != 0 && data.prefix_index < data.prefix.len() {
191+
data.prefix[data.prefix_index] = Some(Reg::i32());
192+
rest_size = rest_size - Reg::i32().size;
193+
}
194+
195+
arg.cast_to(CastTarget {
196+
prefix: data.prefix,
197+
rest: Uniform { unit: Reg::i64(), total: rest_size },
198+
attrs: ArgAttributes {
199+
regular: data.arg_attribute,
200+
arg_ext: ArgExtension::None,
201+
pointee_size: Size::ZERO,
202+
pointee_align: None,
203+
},
204+
});
205+
return;
206+
}
207+
}
208+
}
209+
134210
arg.cast_to(Uniform { unit: Reg::i64(), total });
135211
}
136212

src/test/codegen/sparc-struct-abi.rs

+20
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,23 @@ pub struct FloatLongFloat {
8181
pub extern "C" fn structfloatlongfloat() -> FloatLongFloat {
8282
FloatLongFloat { f: 0.1, i: 123, g: 3.14 }
8383
}
84+
85+
#[repr(C)]
86+
pub struct FloatFloat {
87+
f: f32,
88+
g: f32,
89+
}
90+
91+
#[repr(C)]
92+
pub struct NestedStructs {
93+
a: FloatFloat,
94+
b: FloatFloat,
95+
}
96+
97+
// CHECK: define inreg { float, float, float, float } @structnestestructs()
98+
// CHECK-NEXT: start:
99+
// CHECK-NEXT: ret { float, float, float, float } { float 0x3FB99999A0000000, float 0x3FF19999A0000000, float 0x40019999A0000000, float 0x400A666660000000 }
100+
#[no_mangle]
101+
pub extern "C" fn structnestestructs() -> NestedStructs {
102+
NestedStructs { a: FloatFloat { f: 0.1, g: 1.1 }, b: FloatFloat { f: 2.2, g: 3.3 } }
103+
}

0 commit comments

Comments
 (0)