Skip to content

Commit 9cfb947

Browse files
committed
Allow unsized types as function parameters
1 parent bcb469e commit 9cfb947

File tree

5 files changed

+70
-37
lines changed

5 files changed

+70
-37
lines changed

src/abi/comments.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,21 @@ pub fn add_local_place_comments<'tcx>(
7777
("ssa", std::borrow::Cow::Borrowed(""))
7878
}
7979
CPlaceInner::NoPlace => ("zst", "".into()),
80-
CPlaceInner::Addr(ptr, None) => match ptr.base_and_offset() {
81-
(crate::pointer::PointerBase::Addr(addr), offset) => {
82-
("reuse", format!("storage={}{}", addr, offset).into())
80+
CPlaceInner::Addr(ptr, meta) => {
81+
let meta = if let Some(meta) = meta {
82+
Cow::Owned(format!(",meta={}", meta))
83+
} else {
84+
Cow::Borrowed("")
85+
};
86+
match ptr.base_and_offset() {
87+
(crate::pointer::PointerBase::Addr(addr), offset) => {
88+
("reuse", format!("storage={}{}{}", addr, offset, meta).into())
89+
}
90+
(crate::pointer::PointerBase::Stack(stack_slot), offset) => {
91+
("stack", format!("storage={}{}{}", stack_slot, offset, meta).into())
92+
}
8393
}
84-
(crate::pointer::PointerBase::Stack(stack_slot), offset) => {
85-
("stack", format!("storage={}{}", stack_slot, offset).into())
86-
}
87-
},
88-
CPlaceInner::Addr(_, Some(_)) => unreachable!(),
94+
}
8995
};
9096

9197
fx.add_global_comment(format!(

src/abi/mod.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ fn clif_sig_from_fn_sig<'tcx>(
139139
inputs.map(AbiParam::new).collect(),
140140
vec![AbiParam::new(ret_ty_a), AbiParam::new(ret_ty_b)],
141141
),
142-
PassMode::ByRef => {
142+
PassMode::ByRef { sized: true } => {
143143
(
144144
Some(pointer_ty(tcx)) // First param is place to put return val
145145
.into_iter()
@@ -149,6 +149,7 @@ fn clif_sig_from_fn_sig<'tcx>(
149149
vec![],
150150
)
151151
}
152+
PassMode::ByRef { sized: false } => todo!(),
152153
};
153154

154155
if requires_caller_location {
@@ -350,9 +351,11 @@ pub fn codegen_fn_prelude(fx: &mut FunctionCx<'_, '_, impl Backend>, start_ebb:
350351

351352
let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa;
352353

354+
// While this is normally an optimization to prevent an unnecessary copy when an argument is
355+
// not mutated by the current function, this is necessary to support unsized arguments.
353356
match arg_kind {
354357
ArgKind::Normal(Some(val)) => {
355-
if let Some(addr) = val.try_to_addr() {
358+
if let Some((addr, meta)) = val.try_to_addr() {
356359
let local_decl = &fx.mir.local_decls[local];
357360
// v this ! is important
358361
let internally_mutable = !val.layout().ty.is_freeze(
@@ -364,7 +367,11 @@ pub fn codegen_fn_prelude(fx: &mut FunctionCx<'_, '_, impl Backend>, start_ebb:
364367
// We wont mutate this argument, so it is fine to borrow the backing storage
365368
// of this argument, to prevent a copy.
366369

367-
let place = CPlace::for_ptr(Pointer::new(addr), val.layout());
370+
let place = if let Some(meta) = meta {
371+
CPlace::for_ptr_with_extra(Pointer::new(addr), meta, val.layout())
372+
} else {
373+
CPlace::for_ptr(Pointer::new(addr), val.layout())
374+
};
368375

369376
#[cfg(debug_assertions)]
370377
self::comments::add_local_place_comments(fx, place, local);

src/abi/pass_mode.rs

+17-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub enum PassMode {
77
NoPass,
88
ByVal(Type),
99
ByValPair(Type, Type),
10-
ByRef,
10+
ByRef { sized: bool },
1111
}
1212

1313
#[derive(Copy, Clone, Debug)]
@@ -70,14 +70,13 @@ impl PassMode {
7070
PassMode::NoPass => Empty,
7171
PassMode::ByVal(clif_type) => Single(clif_type),
7272
PassMode::ByValPair(a, b) => Pair(a, b),
73-
PassMode::ByRef => Single(pointer_ty(tcx)),
73+
PassMode::ByRef { sized: true } => Single(pointer_ty(tcx)),
74+
PassMode::ByRef { sized: false } => Pair(pointer_ty(tcx), pointer_ty(tcx)),
7475
}
7576
}
7677
}
7778

7879
pub fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyLayout<'tcx>) -> PassMode {
79-
assert!(!layout.is_unsized());
80-
8180
if layout.is_zst() {
8281
// WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
8382
PassMode::NoPass
@@ -94,16 +93,16 @@ pub fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyLayout<'tcx>) -> PassMod
9493
// Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are
9594
// available on x86_64. Cranelift gets confused when too many return params
9695
// are used.
97-
PassMode::ByRef
96+
PassMode::ByRef { sized: true }
9897
} else {
9998
PassMode::ByValPair(a, b)
10099
}
101100
}
102101

103102
// FIXME implement Vector Abi in a cg_llvm compatible way
104-
layout::Abi::Vector { .. } => PassMode::ByRef,
103+
layout::Abi::Vector { .. } => PassMode::ByRef { sized: true },
105104

106-
layout::Abi::Aggregate { .. } => PassMode::ByRef,
105+
&layout::Abi::Aggregate { sized } => PassMode::ByRef { sized },
107106
}
108107
}
109108
}
@@ -119,7 +118,12 @@ pub(super) fn adjust_arg_for_abi<'tcx>(
119118
let (a, b) = arg.load_scalar_pair(fx);
120119
Pair(a, b)
121120
}
122-
PassMode::ByRef => Single(arg.force_stack(fx).get_addr(fx)),
121+
PassMode::ByRef { sized: _ } => {
122+
match arg.force_stack(fx) {
123+
(ptr, None) => Single(ptr.get_addr(fx)),
124+
(ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta),
125+
}
126+
}
123127
}
124128
}
125129

@@ -158,6 +162,10 @@ pub(super) fn cvalue_for_param<'tcx>(
158162
let (a, b) = ebb_params.assert_pair();
159163
Some(CValue::by_val_pair(a, b, layout))
160164
}
161-
PassMode::ByRef => Some(CValue::by_ref(Pointer::new(ebb_params.assert_single()), layout)),
165+
PassMode::ByRef { sized: true } => Some(CValue::by_ref(Pointer::new(ebb_params.assert_single()), layout)),
166+
PassMode::ByRef { sized: false } => {
167+
let (ptr, meta) = ebb_params.assert_pair();
168+
Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout))
169+
}
162170
}
163171
}

src/abi/returning.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub fn can_return_to_ssa_var<'tcx>(tcx: TyCtxt<'tcx>, dest_layout: TyLayout<'tcx
99
match get_pass_mode(tcx, dest_layout) {
1010
PassMode::NoPass | PassMode::ByVal(_) => true,
1111
// FIXME Make it possible to return ByValPair and ByRef to an ssa var.
12-
PassMode::ByValPair(_, _) | PassMode::ByRef => false
12+
PassMode::ByValPair(_, _) | PassMode::ByRef { sized: _ } => false
1313
}
1414
}
1515

@@ -33,13 +33,14 @@ pub(super) fn codegen_return_param(
3333

3434
Empty
3535
}
36-
PassMode::ByRef => {
36+
PassMode::ByRef { sized: true } => {
3737
let ret_param = fx.bcx.append_ebb_param(start_ebb, fx.pointer_type);
3838
fx.local_map
3939
.insert(RETURN_PLACE, CPlace::for_ptr(Pointer::new(ret_param), ret_layout));
4040

4141
Single(ret_param)
4242
}
43+
PassMode::ByRef { sized: false } => todo!(),
4344
};
4445

4546
#[cfg(debug_assertions)]
@@ -65,10 +66,11 @@ pub(super) fn codegen_with_call_return_arg<'tcx, B: Backend, T>(
6566
let output_pass_mode = get_pass_mode(fx.tcx, ret_layout);
6667
let return_ptr = match output_pass_mode {
6768
PassMode::NoPass => None,
68-
PassMode::ByRef => match ret_place {
69+
PassMode::ByRef { sized: true } => match ret_place {
6970
Some(ret_place) => Some(ret_place.to_ptr(fx).get_addr(fx)),
7071
None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)),
7172
},
73+
PassMode::ByRef { sized: false } => todo!(),
7274
PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None,
7375
};
7476

@@ -89,17 +91,19 @@ pub(super) fn codegen_with_call_return_arg<'tcx, B: Backend, T>(
8991
ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout));
9092
}
9193
}
92-
PassMode::ByRef => {}
94+
PassMode::ByRef { sized: true } => {}
95+
PassMode::ByRef { sized: false } => todo!(),
9396
}
9497

9598
(call_inst, meta)
9699
}
97100

98101
pub fn codegen_return(fx: &mut FunctionCx<impl Backend>) {
99102
match get_pass_mode(fx.tcx, return_layout(fx)) {
100-
PassMode::NoPass | PassMode::ByRef => {
103+
PassMode::NoPass | PassMode::ByRef { sized: true } => {
101104
fx.bcx.ins().return_(&[]);
102105
}
106+
PassMode::ByRef { sized: false } => todo!(),
103107
PassMode::ByVal(_) => {
104108
let place = fx.get_local_place(RETURN_PLACE);
105109
let ret_val = place.to_cvalue(fx).load_scalar(fx);

src/value_and_place.rs

+20-12
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,18 @@ pub struct CValue<'tcx>(CValueInner, TyLayout<'tcx>);
6666

6767
#[derive(Debug, Copy, Clone)]
6868
enum CValueInner {
69-
ByRef(Pointer),
69+
ByRef(Pointer, Option<Value>),
7070
ByVal(Value),
7171
ByValPair(Value, Value),
7272
}
7373

7474
impl<'tcx> CValue<'tcx> {
7575
pub fn by_ref(ptr: Pointer, layout: TyLayout<'tcx>) -> CValue<'tcx> {
76-
CValue(CValueInner::ByRef(ptr), layout)
76+
CValue(CValueInner::ByRef(ptr, None), layout)
77+
}
78+
79+
pub fn by_ref_unsized(ptr: Pointer, meta: Value, layout: TyLayout<'tcx>) -> CValue<'tcx> {
80+
CValue(CValueInner::ByRef(ptr, Some(meta)), layout)
7781
}
7882

7983
pub fn by_val(value: Value, layout: TyLayout<'tcx>) -> CValue<'tcx> {
@@ -89,24 +93,24 @@ impl<'tcx> CValue<'tcx> {
8993
}
9094

9195
// FIXME remove
92-
pub fn force_stack<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> Pointer {
96+
pub fn force_stack<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> (Pointer, Option<Value>) {
9397
let layout = self.1;
9498
match self.0 {
95-
CValueInner::ByRef(ptr) => ptr,
99+
CValueInner::ByRef(ptr, meta) => (ptr, meta),
96100
CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => {
97101
let cplace = CPlace::new_stack_slot(fx, layout);
98102
cplace.write_cvalue(fx, self);
99-
cplace.to_ptr(fx)
103+
(cplace.to_ptr(fx), None)
100104
}
101105
}
102106
}
103107

104-
pub fn try_to_addr(self) -> Option<Value> {
108+
pub fn try_to_addr(self) -> Option<(Value, Option<Value>)> {
105109
match self.0 {
106-
CValueInner::ByRef(ptr) => {
110+
CValueInner::ByRef(ptr, meta) => {
107111
if let Some((base_addr, offset)) = ptr.try_get_addr_and_offset() {
108112
if offset == Offset32::new(0) {
109-
Some(base_addr)
113+
Some((base_addr, meta))
110114
} else {
111115
None
112116
}
@@ -122,7 +126,7 @@ impl<'tcx> CValue<'tcx> {
122126
pub fn load_scalar<'a>(self, fx: &mut FunctionCx<'_, 'tcx, impl Backend>) -> Value {
123127
let layout = self.1;
124128
match self.0 {
125-
CValueInner::ByRef(ptr) => {
129+
CValueInner::ByRef(ptr, None) => {
126130
let clif_ty = match layout.abi {
127131
layout::Abi::Scalar(ref scalar) => scalar_to_clif_type(fx.tcx, scalar.clone()),
128132
layout::Abi::Vector { ref element, count } => {
@@ -134,6 +138,7 @@ impl<'tcx> CValue<'tcx> {
134138
ptr.load(fx, clif_ty, MemFlags::new())
135139
}
136140
CValueInner::ByVal(value) => value,
141+
CValueInner::ByRef(_, Some(_)) => bug!("load_scalar for unsized value not allowed"),
137142
CValueInner::ByValPair(_, _) => bug!("Please use load_scalar_pair for ByValPair"),
138143
}
139144
}
@@ -145,7 +150,7 @@ impl<'tcx> CValue<'tcx> {
145150
) -> (Value, Value) {
146151
let layout = self.1;
147152
match self.0 {
148-
CValueInner::ByRef(ptr) => {
153+
CValueInner::ByRef(ptr, None) => {
149154
let (a_scalar, b_scalar) = match &layout.abi {
150155
layout::Abi::ScalarPair(a, b) => (a, b),
151156
_ => unreachable!("load_scalar_pair({:?})", self),
@@ -157,6 +162,7 @@ impl<'tcx> CValue<'tcx> {
157162
let val2 = ptr.offset(fx, b_offset).load(fx, clif_ty2, MemFlags::new());
158163
(val1, val2)
159164
}
165+
CValueInner::ByRef(_, Some(_)) => bug!("load_scalar_pair for unsized value not allowed"),
160166
CValueInner::ByVal(_) => bug!("Please use load_scalar for ByVal"),
161167
CValueInner::ByValPair(val1, val2) => (val1, val2),
162168
}
@@ -182,10 +188,11 @@ impl<'tcx> CValue<'tcx> {
182188
_ => unreachable!("value_field for ByVal with abi {:?}", layout.abi),
183189
}
184190
}
185-
CValueInner::ByRef(ptr) => {
191+
CValueInner::ByRef(ptr, None) => {
186192
let (field_ptr, field_layout) = codegen_field(fx, ptr, None, layout, field);
187193
CValue::by_ref(field_ptr, field_layout)
188194
}
195+
CValueInner::ByRef(_, Some(_)) => todo!(),
189196
_ => bug!("place_field for {:?}", self),
190197
}
191198
}
@@ -495,7 +502,7 @@ impl<'tcx> CPlace<'tcx> {
495502
dst_layout.abi
496503
);
497504
}
498-
CValueInner::ByRef(from_ptr) => {
505+
CValueInner::ByRef(from_ptr, None) => {
499506
let from_addr = from_ptr.get_addr(fx);
500507
let to_addr = to_ptr.get_addr(fx);
501508
let src_layout = from.1;
@@ -511,6 +518,7 @@ impl<'tcx> CPlace<'tcx> {
511518
src_align,
512519
);
513520
}
521+
CValueInner::ByRef(_, Some(_)) => todo!(),
514522
}
515523
}
516524

0 commit comments

Comments
 (0)