Skip to content

Commit e391603

Browse files
committed
Fix RISC-V C function ABI when passing/returning structs containing floats
1 parent 262e821 commit e391603

File tree

1 file changed

+42
-24
lines changed

1 file changed

+42
-24
lines changed

src/abi/pass_mode.rs

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,18 @@ fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiPar
4040
}
4141
}
4242

43-
fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
43+
fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2]> {
44+
if let Some(offset_from_start) = cast.rest_offset {
45+
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
46+
assert_eq!(cast.rest.unit.size, cast.rest.total);
47+
let first = cast.prefix[0].unwrap();
48+
let second = cast.rest.unit;
49+
return smallvec![
50+
(Size::ZERO, reg_to_abi_param(first)),
51+
(offset_from_start, reg_to_abi_param(second))
52+
];
53+
}
54+
4455
let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
4556
(0, 0)
4657
} else {
@@ -55,25 +66,32 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
5566
// different types in Cranelift IR. Instead a single array of primitive types is used.
5667

5768
// Create list of fields in the main structure
58-
let mut args = cast
69+
let args = cast
5970
.prefix
6071
.iter()
6172
.flatten()
6273
.map(|&reg| reg_to_abi_param(reg))
63-
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
64-
.collect::<SmallVec<_>>();
74+
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)));
75+
76+
let mut res = SmallVec::new();
77+
let mut offset = Size::ZERO;
78+
79+
for arg in args {
80+
res.push((offset, arg));
81+
offset += Size::from_bytes(arg.value_type.bytes());
82+
}
6583

6684
// Append final integer
6785
if rem_bytes != 0 {
6886
// Only integers can be really split further.
6987
assert_eq!(cast.rest.unit.kind, RegKind::Integer);
70-
args.push(reg_to_abi_param(Reg {
71-
kind: RegKind::Integer,
72-
size: Size::from_bytes(rem_bytes),
73-
}));
88+
res.push((
89+
offset,
90+
reg_to_abi_param(Reg { kind: RegKind::Integer, size: Size::from_bytes(rem_bytes) }),
91+
));
7492
}
7593

76-
args
94+
res
7795
}
7896

7997
impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
@@ -104,7 +122,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
104122
},
105123
PassMode::Cast { ref cast, pad_i32 } => {
106124
assert!(!pad_i32, "padding support not yet implemented");
107-
cast_target_to_abi_params(cast)
125+
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect()
108126
}
109127
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
110128
if on_stack {
@@ -160,9 +178,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
160178
}
161179
_ => unreachable!("{:?}", self.layout.backend_repr),
162180
},
163-
PassMode::Cast { ref cast, .. } => {
164-
(None, cast_target_to_abi_params(cast).into_iter().collect())
165-
}
181+
PassMode::Cast { ref cast, .. } => (
182+
None,
183+
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(),
184+
),
166185
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
167186
assert!(!on_stack);
168187
(
@@ -187,12 +206,14 @@ pub(super) fn to_casted_value<'tcx>(
187206
) -> SmallVec<[Value; 2]> {
188207
let (ptr, meta) = arg.force_stack(fx);
189208
assert!(meta.is_none());
190-
let mut offset = 0;
191209
cast_target_to_abi_params(cast)
192210
.into_iter()
193-
.map(|param| {
194-
let val = ptr.offset_i64(fx, offset).load(fx, param.value_type, MemFlags::new());
195-
offset += i64::from(param.value_type.bytes());
211+
.map(|(offset, param)| {
212+
let val = ptr.offset_i64(fx, offset.bytes() as i64).load(
213+
fx,
214+
param.value_type,
215+
MemFlags::new(),
216+
);
196217
val
197218
})
198219
.collect()
@@ -205,7 +226,7 @@ pub(super) fn from_casted_value<'tcx>(
205226
cast: &CastTarget,
206227
) -> CValue<'tcx> {
207228
let abi_params = cast_target_to_abi_params(cast);
208-
let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum();
229+
let abi_param_size: u32 = abi_params.iter().map(|(_, param)| param.value_type.bytes()).sum();
209230
let layout_size = u32::try_from(layout.size.bytes()).unwrap();
210231
let ptr = fx.create_stack_slot(
211232
// Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
@@ -214,16 +235,13 @@ pub(super) fn from_casted_value<'tcx>(
214235
std::cmp::max(abi_param_size, layout_size),
215236
u32::try_from(layout.align.abi.bytes()).unwrap(),
216237
);
217-
let mut offset = 0;
218238
let mut block_params_iter = block_params.iter().copied();
219-
for param in abi_params {
220-
let val = ptr.offset_i64(fx, offset).store(
239+
for (offset, _) in abi_params {
240+
ptr.offset_i64(fx, offset.bytes() as i64).store(
221241
fx,
222242
block_params_iter.next().unwrap(),
223243
MemFlags::new(),
224-
);
225-
offset += i64::from(param.value_type.bytes());
226-
val
244+
)
227245
}
228246
assert_eq!(block_params_iter.next(), None, "Leftover block param");
229247
CValue::by_ref(ptr, layout)

0 commit comments

Comments
 (0)