Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit e8f48e4

Browse files
committed
[WIP] Implement PassMode::Cast
1 parent 268d7bc commit e8f48e4

File tree

3 files changed

+191
-34
lines changed

3 files changed

+191
-34
lines changed

src/abi/mod.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,24 @@ pub(crate) fn codegen_fn_prelude<'tcx>(
191191
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
192192
start_block: Block,
193193
) {
194+
fx.bcx.append_block_params_for_function_params(start_block);
195+
196+
fx.bcx.switch_to_block(start_block);
197+
fx.bcx.ins().nop();
198+
194199
let ssa_analyzed = crate::analyze::analyze(fx);
195200

196201
#[cfg(debug_assertions)]
197202
self::comments::add_args_header_comment(fx);
198203

199-
let ret_place = self::returning::codegen_return_param(fx, &ssa_analyzed, start_block);
204+
let mut block_params_iter = fx
205+
.bcx
206+
.func
207+
.dfg
208+
.block_params(start_block)
209+
.to_vec()
210+
.into_iter();
211+
let ret_place = self::returning::codegen_return_param(fx, &ssa_analyzed, &mut block_params_iter);
200212
assert_eq!(fx.local_map.push(ret_place), RETURN_PLACE);
201213

202214
// None means pass_mode == NoPass
@@ -229,14 +241,14 @@ pub(crate) fn codegen_fn_prelude<'tcx>(
229241
let mut params = Vec::new();
230242
for (i, _arg_ty) in tupled_arg_tys.types().enumerate() {
231243
let arg_abi = arg_abis_iter.next().unwrap();
232-
let param = cvalue_for_param(fx, start_block, Some(local), Some(i), arg_abi);
244+
let param = cvalue_for_param(fx, Some(local), Some(i), arg_abi, &mut block_params_iter);
233245
params.push(param);
234246
}
235247

236248
(local, ArgKind::Spread(params), arg_ty)
237249
} else {
238250
let arg_abi = arg_abis_iter.next().unwrap();
239-
let param = cvalue_for_param(fx, start_block, Some(local), None, arg_abi);
251+
let param = cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter);
240252
(local, ArgKind::Normal(param), arg_ty)
241253
}
242254
})
@@ -246,14 +258,13 @@ pub(crate) fn codegen_fn_prelude<'tcx>(
246258
if fx.instance.def.requires_caller_location(fx.tcx) {
247259
// Store caller location for `#[track_caller]`.
248260
let arg_abi = arg_abis_iter.next().unwrap();
249-
fx.caller_location = Some(cvalue_for_param(fx, start_block, None, None, arg_abi).unwrap());
261+
fx.caller_location =
262+
Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap());
250263
}
251264

252265
assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind");
253266
fx.fn_abi = Some(fn_abi);
254-
255-
fx.bcx.switch_to_block(start_block);
256-
fx.bcx.ins().nop();
267+
assert!(block_params_iter.next().is_none(), "arg_value left behind");
257268

258269
#[cfg(debug_assertions)]
259270
self::comments::add_locals_header_comment(fx);

src/abi/pass_mode.rs

Lines changed: 146 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,86 @@ use crate::prelude::*;
44
use crate::value_and_place::assert_assignable;
55

66
use cranelift_codegen::ir::ArgumentPurpose;
7-
use rustc_target::abi::call::{ArgAbi, PassMode};
7+
use rustc_target::abi::call::{ArgAbi, CastTarget, PassMode, Reg, RegKind};
88
use smallvec::{smallvec, SmallVec};
99

1010
pub(super) trait ArgAbiExt<'tcx> {
1111
fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>;
1212
fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>);
1313
}
1414

15+
fn reg_to_abi_param(reg: Reg) -> AbiParam {
16+
let clif_ty = match (reg.kind, reg.size.bytes()) {
17+
(RegKind::Integer, 1) => types::I8,
18+
(RegKind::Integer, 2) => types::I16,
19+
(RegKind::Integer, 4) => types::I32,
20+
(RegKind::Integer, 8) => types::I64,
21+
(RegKind::Integer, 16) => types::I128,
22+
(RegKind::Float, 4) => types::F32,
23+
(RegKind::Float, 8) => types::F64,
24+
(RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
25+
_ => unreachable!("{:?}", reg),
26+
};
27+
AbiParam::new(clif_ty)
28+
}
29+
30+
fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> {
31+
let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
32+
(0, 0)
33+
} else {
34+
(
35+
cast.rest.total.bytes() / cast.rest.unit.size.bytes(),
36+
cast.rest.total.bytes() % cast.rest.unit.size.bytes(),
37+
)
38+
};
39+
40+
if cast.prefix.iter().all(|x| x.is_none()) {
41+
// Simplify to a single unit when there is no prefix and size <= unit size
42+
if cast.rest.total <= cast.rest.unit.size {
43+
let clif_ty = match (cast.rest.unit.kind, cast.rest.unit.size.bytes()) {
44+
(RegKind::Integer, 1) => types::I8,
45+
(RegKind::Integer, 2) => types::I16,
46+
(RegKind::Integer, 3..=4) => types::I32,
47+
(RegKind::Integer, 5..=8) => types::I64,
48+
(RegKind::Integer, 9..=16) => types::I128,
49+
(RegKind::Float, 4) => types::F32,
50+
(RegKind::Float, 8) => types::F64,
51+
(RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
52+
_ => unreachable!("{:?}", cast.rest.unit),
53+
};
54+
return smallvec![AbiParam::new(clif_ty)];
55+
}
56+
}
57+
58+
// Create list of fields in the main structure
59+
let mut args = cast
60+
.prefix
61+
.iter()
62+
.flatten()
63+
.map(|&kind| {
64+
reg_to_abi_param(Reg {
65+
kind,
66+
size: cast.prefix_chunk_size,
67+
})
68+
})
69+
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
70+
.collect::<SmallVec<_>>();
71+
72+
// Append final integer
73+
if rem_bytes != 0 {
74+
// Only integers can be really split further.
75+
assert_eq!(cast.rest.unit.kind, RegKind::Integer);
76+
args.push(reg_to_abi_param(Reg {
77+
kind: RegKind::Integer,
78+
size: Size::from_bytes(rem_bytes),
79+
}));
80+
}
81+
82+
args
83+
}
84+
85+
// FIXME respect argument extension mode
86+
1587
impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
1688
fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> {
1789
match self.mode {
@@ -34,7 +106,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
34106
}
35107
_ => unreachable!("{:?}", self.layout.abi),
36108
},
37-
PassMode::Cast(_) => smallvec![AbiParam::new(pointer_ty(tcx))],
109+
PassMode::Cast(cast) => cast_target_to_abi_params(cast),
38110
PassMode::Indirect {
39111
attrs: _,
40112
extra_attrs: None,
@@ -87,13 +159,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
87159
}
88160
_ => unreachable!("{:?}", self.layout.abi),
89161
},
90-
PassMode::Cast(_) => (
91-
Some(AbiParam::special(
92-
pointer_ty(tcx),
93-
ArgumentPurpose::StructReturn,
94-
)),
95-
vec![],
96-
),
162+
PassMode::Cast(cast) => (None, cast_target_to_abi_params(cast).into_iter().collect()),
97163
PassMode::Indirect {
98164
attrs: _,
99165
extra_attrs: None,
@@ -117,6 +183,60 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
117183
}
118184
}
119185

186+
pub(super) fn to_casted_value<'tcx>(
187+
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
188+
arg: CValue<'tcx>,
189+
cast: CastTarget,
190+
) -> SmallVec<[Value; 2]> {
191+
let (ptr, meta) = arg.force_stack(fx);
192+
assert!(meta.is_none());
193+
let mut offset = 0;
194+
cast_target_to_abi_params(cast)
195+
.into_iter()
196+
.map(|param| {
197+
let val = ptr
198+
.offset_i64(fx, offset)
199+
.load(fx, param.value_type, MemFlags::new());
200+
offset += i64::from(param.value_type.bytes());
201+
val
202+
})
203+
.collect()
204+
}
205+
206+
pub(super) fn from_casted_value<'tcx>(
207+
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
208+
block_params: &[Value],
209+
layout: TyAndLayout<'tcx>,
210+
cast: CastTarget,
211+
) -> CValue<'tcx> {
212+
let abi_params = cast_target_to_abi_params(cast);
213+
let size = abi_params
214+
.iter()
215+
.map(|param| param.value_type.bytes())
216+
.sum();
217+
// Stack slot size may be bigger for for example `[u8; 3]` which is packed into an `i32`.
218+
assert!(u64::from(size) >= layout.size.bytes());
219+
let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
220+
kind: StackSlotKind::ExplicitSlot,
221+
size,
222+
offset: None,
223+
});
224+
let ptr = Pointer::new(fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0));
225+
let mut offset = 0;
226+
let mut block_params_iter = block_params.into_iter().copied();
227+
for param in abi_params {
228+
let val = ptr.offset_i64(fx, offset).store(
229+
fx,
230+
block_params_iter.next().unwrap(),
231+
MemFlags::new(),
232+
);
233+
offset += i64::from(param.value_type.bytes());
234+
val
235+
}
236+
assert_eq!(block_params_iter.next(), None, "Leftover block param");
237+
CValue::by_ref(ptr, layout)
238+
}
239+
120240
/// Get a set of values to be passed as function arguments.
121241
pub(super) fn adjust_arg_for_abi<'tcx>(
122242
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
@@ -131,7 +251,8 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
131251
let (a, b) = arg.load_scalar_pair(fx);
132252
smallvec![a, b]
133253
}
134-
PassMode::Cast(_) | PassMode::Indirect { .. } => match arg.force_stack(fx) {
254+
PassMode::Cast(cast) => to_casted_value(fx, arg, cast),
255+
PassMode::Indirect { .. } => match arg.force_stack(fx) {
135256
(ptr, None) => smallvec![ptr.get_addr(fx)],
136257
(ptr, Some(meta)) => smallvec![ptr.get_addr(fx), meta],
137258
},
@@ -142,15 +263,22 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
142263
/// as necessary.
143264
pub(super) fn cvalue_for_param<'tcx>(
144265
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
145-
start_block: Block,
146266
#[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>,
147267
#[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>,
148268
arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
269+
block_params_iter: &mut impl Iterator<Item = Value>,
149270
) -> Option<CValue<'tcx>> {
150-
let clif_types = arg_abi.get_abi_param(fx.tcx);
151-
let block_params = clif_types
271+
let block_params = arg_abi
272+
.get_abi_param(fx.tcx)
152273
.into_iter()
153-
.map(|abi_param| fx.bcx.append_block_param(start_block, abi_param.value_type))
274+
.map(|abi_param| {
275+
let block_param = block_params_iter.next().unwrap();
276+
assert_eq!(
277+
fx.bcx.func.dfg.value_type(block_param),
278+
abi_param.value_type
279+
);
280+
block_param
281+
})
154282
.collect::<SmallVec<[_; 2]>>();
155283

156284
#[cfg(debug_assertions)]
@@ -178,8 +306,10 @@ pub(super) fn cvalue_for_param<'tcx>(
178306
arg_abi.layout,
179307
))
180308
}
181-
PassMode::Cast(_)
182-
| PassMode::Indirect {
309+
PassMode::Cast(cast) => {
310+
Some(from_casted_value(fx, &block_params, arg_abi.layout, cast))
311+
}
312+
PassMode::Indirect {
183313
attrs: _,
184314
extra_attrs: None,
185315
on_stack: _,

src/abi/returning.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ pub(crate) fn can_return_to_ssa_var<'tcx>(
6060
pub(super) fn codegen_return_param<'tcx>(
6161
fx: &mut FunctionCx<'_, 'tcx, impl Module>,
6262
ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
63-
start_block: Block,
63+
block_params_iter: &mut impl Iterator<Item = Value>,
6464
) -> CPlace<'tcx> {
6565
let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
6666
PassMode::Ignore => (
6767
CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout),
6868
smallvec![],
6969
),
70-
PassMode::Direct(_) | PassMode::Pair(_, _) => {
70+
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => {
7171
let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa;
7272
(
7373
super::make_local_place(
@@ -79,13 +79,13 @@ pub(super) fn codegen_return_param<'tcx>(
7979
smallvec![],
8080
)
8181
}
82-
PassMode::Cast(_)
83-
| PassMode::Indirect {
82+
PassMode::Indirect {
8483
attrs: _,
8584
extra_attrs: None,
8685
on_stack: _,
8786
} => {
88-
let ret_param = fx.bcx.append_block_param(start_block, fx.pointer_type);
87+
let ret_param = block_params_iter.next().unwrap();
88+
assert_eq!(fx.bcx.func.dfg.value_type(ret_param), pointer_ty(fx.tcx));
8989
(
9090
CPlace::for_ptr(
9191
Pointer::new(ret_param),
@@ -128,8 +128,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>(
128128
) -> (Inst, T) {
129129
let return_ptr = match ret_arg_abi.mode {
130130
PassMode::Ignore => None,
131-
PassMode::Cast(_)
132-
| PassMode::Indirect {
131+
PassMode::Indirect {
133132
attrs: _,
134133
extra_attrs: None,
135134
on_stack: _,
@@ -142,7 +141,7 @@ pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>(
142141
extra_attrs: Some(_),
143142
on_stack: _,
144143
} => unreachable!("unsized return value"),
145-
PassMode::Direct(_) | PassMode::Pair(_, _) => None,
144+
PassMode::Direct(_) | PassMode::Pair(_, _) | PassMode::Cast(_) => None,
146145
};
147146

148147
let (call_inst, meta) = f(fx, return_ptr);
@@ -165,8 +164,20 @@ pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>(
165164
);
166165
}
167166
}
168-
PassMode::Cast(_)
169-
| PassMode::Indirect {
167+
PassMode::Cast(cast) => {
168+
if let Some(ret_place) = ret_place {
169+
let results = fx
170+
.bcx
171+
.inst_results(call_inst)
172+
.into_iter()
173+
.copied()
174+
.collect::<SmallVec<[Value; 2]>>();
175+
let result =
176+
super::pass_mode::from_casted_value(fx, &results, ret_place.layout(), cast);
177+
ret_place.write_cvalue(fx, result);
178+
}
179+
}
180+
PassMode::Indirect {
170181
attrs: _,
171182
extra_attrs: None,
172183
on_stack: _,
@@ -185,7 +196,6 @@ pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>(
185196
pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, impl Module>) {
186197
match fx.fn_abi.as_ref().unwrap().ret.mode {
187198
PassMode::Ignore
188-
| PassMode::Cast(_)
189199
| PassMode::Indirect {
190200
attrs: _,
191201
extra_attrs: None,
@@ -208,5 +218,11 @@ pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, impl Module>) {
208218
let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
209219
fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
210220
}
221+
PassMode::Cast(cast) => {
222+
let place = fx.get_local_place(RETURN_PLACE);
223+
let ret_val = place.to_cvalue(fx);
224+
let ret_vals = super::pass_mode::to_casted_value(fx, ret_val, cast);
225+
fx.bcx.ins().return_(&ret_vals);
226+
}
211227
}
212228
}

0 commit comments

Comments
 (0)