Skip to content

Commit c8ed51a

Browse files
Kuhai9801Kuhai9801
authored andcommitted
Fix PassMode::Cast ABI argument lowering
1 parent b798116 commit c8ed51a

1 file changed

Lines changed: 164 additions & 43 deletions

File tree

src/abi/pass_mode.rs

Lines changed: 164 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam {
2727
(RegKind::Float, 4) => types::F32,
2828
(RegKind::Float, 8) => types::F64,
2929
(RegKind::Float, 16) => types::F128,
30-
(RegKind::Vector { hint_vector_elem: _ }, size) => {
31-
types::I8.by(u32::try_from(size).unwrap()).unwrap()
32-
}
30+
(
31+
RegKind::Vector {
32+
hint_vector_elem: _,
33+
},
34+
size,
35+
) => types::I8.by(u32::try_from(size).unwrap()).unwrap(),
3336
_ => unreachable!("{:?}", reg),
3437
};
3538
AbiParam::new(clif_ty)
@@ -55,13 +58,21 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2
5558
];
5659
}
5760

58-
let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
59-
(0, 0)
61+
let rest_count = if cast.rest.total == Size::ZERO {
62+
0
6063
} else {
61-
(
62-
cast.rest.total.bytes() / cast.rest.unit.size.bytes(),
63-
cast.rest.total.bytes() % cast.rest.unit.size.bytes(),
64-
)
64+
assert_ne!(cast.rest.unit.size, Size::ZERO);
65+
if cast.rest.total.bytes() % cast.rest.unit.size.bytes() != 0 {
66+
assert_eq!(
67+
cast.rest.unit.kind,
68+
RegKind::Integer,
69+
"only int regs can be split"
70+
);
71+
}
72+
cast.rest
73+
.total
74+
.bytes()
75+
.div_ceil(cast.rest.unit.size.bytes())
6576
};
6677

6778
// Note: Unlike the LLVM equivalent of this code we don't have separate branches for when there
@@ -83,18 +94,39 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2
8394
res.push((offset, arg));
8495
offset += Size::from_bytes(arg.value_type.bytes());
8596
}
97+
res
98+
}
8699

87-
// Append final integer
88-
if rem_bytes != 0 {
89-
// Only integers can be really split further.
90-
assert_eq!(cast.rest.unit.kind, RegKind::Integer);
91-
res.push((
92-
offset,
93-
reg_to_abi_param(Reg { kind: RegKind::Integer, size: Size::from_bytes(rem_bytes) }),
94-
));
95-
}
100+
fn abi_params_size(params: &[(Size, AbiParam)]) -> u64 {
101+
params
102+
.iter()
103+
.map(|(offset, param)| offset.bytes() + u64::from(param.value_type.bytes()))
104+
.max()
105+
.unwrap_or(0)
106+
}
96107

97-
res
108+
#[cfg(test)]
109+
mod tests {
110+
use rustc_target::callconv::Uniform;
111+
112+
use super::*;
113+
114+
#[test]
115+
fn cast_target_rounds_integer_rest_to_unit_size() {
116+
let reg = Reg {
117+
kind: RegKind::Integer,
118+
size: Size::from_bytes(8),
119+
};
120+
let cast = CastTarget::from(Uniform::new(reg, Size::from_bytes(10)));
121+
122+
let params = cast_target_to_abi_params(&cast);
123+
124+
assert_eq!(params.len(), 2);
125+
assert_eq!(params[0].0, Size::ZERO);
126+
assert_eq!(params[0].1.value_type, types::I64);
127+
assert_eq!(params[1].0, Size::from_bytes(8));
128+
assert_eq!(params[1].1.value_type, types::I64);
129+
}
98130
}
99131

100132
impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
@@ -125,22 +157,39 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
125157
},
126158
PassMode::Cast { ref cast, pad_i32 } => {
127159
assert!(!pad_i32, "padding support not yet implemented");
128-
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect()
160+
cast_target_to_abi_params(cast)
161+
.into_iter()
162+
.map(|(_, param)| param)
163+
.collect()
129164
}
130-
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
165+
PassMode::Indirect {
166+
attrs,
167+
meta_attrs: None,
168+
on_stack,
169+
} => {
131170
if on_stack {
132171
// Abi requires aligning struct size to pointer size
133-
let size = self.layout.size.align_to(tcx.data_layout.pointer_align().abi);
172+
let size = self
173+
.layout
174+
.size
175+
.align_to(tcx.data_layout.pointer_align().abi);
134176
let size = u32::try_from(size.bytes()).unwrap();
135177
smallvec![apply_attrs_to_abi_param(
136178
AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),),
137179
attrs
138180
)]
139181
} else {
140-
smallvec![apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
182+
smallvec![apply_attrs_to_abi_param(
183+
AbiParam::new(pointer_ty(tcx)),
184+
attrs
185+
)]
141186
}
142187
}
143-
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
188+
PassMode::Indirect {
189+
attrs,
190+
meta_attrs: Some(meta_attrs),
191+
on_stack,
192+
} => {
144193
assert!(!on_stack);
145194
smallvec![
146195
apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
@@ -163,7 +212,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
163212
),
164213
BackendRepr::SimdVector { .. } => {
165214
let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout);
166-
(None, vec![apply_attrs_to_abi_param(AbiParam::new(vector_ty), attrs)])
215+
(
216+
None,
217+
vec![apply_attrs_to_abi_param(AbiParam::new(vector_ty), attrs)],
218+
)
167219
}
168220
_ => unreachable!("{:?}", self.layout.backend_repr),
169221
},
@@ -183,9 +235,16 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
183235
},
184236
PassMode::Cast { ref cast, .. } => (
185237
None,
186-
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(),
238+
cast_target_to_abi_params(cast)
239+
.into_iter()
240+
.map(|(_, param)| param)
241+
.collect(),
187242
),
188-
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
243+
PassMode::Indirect {
244+
attrs,
245+
meta_attrs: None,
246+
on_stack,
247+
} => {
189248
assert!(!on_stack);
190249
(
191250
Some(apply_attrs_to_abi_param(
@@ -195,7 +254,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
195254
vec![],
196255
)
197256
}
198-
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
257+
PassMode::Indirect {
258+
attrs: _,
259+
meta_attrs: Some(_),
260+
on_stack: _,
261+
} => {
199262
unreachable!("unsized return value")
200263
}
201264
}
@@ -207,12 +270,51 @@ pub(super) fn to_casted_value<'tcx>(
207270
arg: CValue<'tcx>,
208271
cast: &CastTarget,
209272
) -> SmallVec<[Value; 2]> {
273+
let layout = arg.layout();
210274
let (ptr, meta) = arg.force_stack(fx);
211275
assert!(meta.is_none());
212-
cast_target_to_abi_params(cast)
213-
.into_iter()
276+
let abi_params = cast_target_to_abi_params(cast);
277+
let abi_param_size = abi_params_size(&abi_params);
278+
let cast_align = cast.align(fx).bytes();
279+
let layout_align = layout.align.bytes();
280+
let slot_align = cast_align.max(layout_align);
281+
let slot_size = abi_param_size
282+
.max(layout.size.bytes())
283+
.next_multiple_of(slot_align);
284+
let scratch = fx.create_stack_slot(
285+
u32::try_from(slot_size).unwrap(),
286+
u32::try_from(slot_align).unwrap(),
287+
);
288+
let zero = fx.bcx.ins().iconst(types::I8, 0);
289+
for offset in 0..slot_size {
290+
scratch
291+
.offset_i64(fx, offset as i64)
292+
.store(fx, zero, MemFlags::new());
293+
}
294+
295+
let copy_bytes = abi_param_size.min(layout.size.bytes());
296+
if copy_bytes != 0 {
297+
let from_addr = ptr.get_addr(fx);
298+
let to_addr = scratch.get_addr(fx);
299+
fx.bcx.emit_small_memory_copy(
300+
fx.target_config,
301+
to_addr,
302+
from_addr,
303+
copy_bytes,
304+
slot_align.try_into().unwrap_or(128),
305+
layout.align.bytes().try_into().unwrap_or(128),
306+
true,
307+
MemFlags::new(),
308+
);
309+
}
310+
abi_params
311+
.iter()
214312
.map(|(offset, param)| {
215-
ptr.offset_i64(fx, offset.bytes() as i64).load(fx, param.value_type, MemFlags::new())
313+
scratch.offset_i64(fx, offset.bytes() as i64).load(
314+
fx,
315+
param.value_type,
316+
MemFlags::new(),
317+
)
216318
})
217319
.collect()
218320
}
@@ -224,14 +326,15 @@ pub(super) fn from_casted_value<'tcx>(
224326
cast: &CastTarget,
225327
) -> CValue<'tcx> {
226328
let abi_params = cast_target_to_abi_params(cast);
227-
let abi_param_size: u32 = abi_params.iter().map(|(_, param)| param.value_type.bytes()).sum();
228-
let layout_size = u32::try_from(layout.size.bytes()).unwrap();
329+
let abi_param_size = abi_params_size(&abi_params);
330+
let cast_align = cast.align(fx).bytes();
331+
let layout_size = layout.size.bytes();
332+
let layout_align = layout.align.bytes();
333+
let slot_align = cast_align.max(layout_align);
334+
let slot_size = abi_param_size.max(layout_size).next_multiple_of(slot_align);
229335
let ptr = fx.create_stack_slot(
230-
// Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
231-
// It may also be smaller for example when the type is a wrapper around an integer with a
232-
// larger alignment than the integer.
233-
std::cmp::max(abi_param_size, layout_size),
234-
u32::try_from(layout.align.bytes()).unwrap(),
336+
u32::try_from(slot_size).unwrap(),
337+
u32::try_from(slot_align).unwrap(),
235338
);
236339
let mut block_params_iter = block_params.iter().copied();
237340
for (offset, _) in abi_params {
@@ -293,7 +396,10 @@ pub(super) fn cvalue_for_param<'tcx>(
293396
.into_iter()
294397
.map(|abi_param| {
295398
let block_param = block_params_iter.next().unwrap();
296-
assert_eq!(fx.bcx.func.dfg.value_type(block_param), abi_param.value_type);
399+
assert_eq!(
400+
fx.bcx.func.dfg.value_type(block_param),
401+
abi_param.value_type
402+
);
297403
block_param
298404
})
299405
.collect::<SmallVec<[_; 2]>>();
@@ -321,7 +427,11 @@ pub(super) fn cvalue_for_param<'tcx>(
321427
PassMode::Cast { ref cast, .. } => {
322428
from_casted_value(fx, &block_params, arg_abi.layout, cast)
323429
}
324-
PassMode::Indirect { attrs, meta_attrs: None, on_stack: _ } => {
430+
PassMode::Indirect {
431+
attrs,
432+
meta_attrs: None,
433+
on_stack: _,
434+
} => {
325435
assert_eq!(block_params.len(), 1, "{:?}", block_params);
326436
if let Some(pointee_align) = attrs.pointee_align
327437
&& pointee_align < arg_abi.layout.align.abi
@@ -339,11 +449,22 @@ pub(super) fn cvalue_for_param<'tcx>(
339449
CValue::by_ref(Pointer::new(block_params[0]), arg_abi.layout)
340450
}
341451
}
342-
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
452+
PassMode::Indirect {
453+
attrs: _,
454+
meta_attrs: Some(_),
455+
on_stack: _,
456+
} => {
343457
assert_eq!(block_params.len(), 2, "{:?}", block_params);
344-
CValue::by_ref_unsized(Pointer::new(block_params[0]), block_params[1], arg_abi.layout)
458+
CValue::by_ref_unsized(
459+
Pointer::new(block_params[0]),
460+
block_params[1],
461+
arg_abi.layout,
462+
)
345463
}
346464
};
347465

348-
Some(ArgValue { value, is_underaligned_pointee: false })
466+
Some(ArgValue {
467+
value,
468+
is_underaligned_pointee: false,
469+
})
349470
}

0 commit comments

Comments
 (0)