5 pub(super) use EmptySinglePair::*;
7 #[derive(Copy, Clone, Debug)]
8 pub(super) enum PassMode {
11 ByValPair(Type, Type),
12 ByRef { size: Option<Size> },
15 #[derive(Copy, Clone, Debug)]
16 pub(super) enum EmptySinglePair<T> {
22 impl<T> EmptySinglePair<T> {
23 pub(super) fn into_iter(self) -> EmptySinglePairIter<T> {
24 EmptySinglePairIter(self)
27 pub(super) fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> {
30 Single(v) => Single(f(v)),
31 Pair(a, b) => Pair(f(a), f(b)),
36 pub(super) struct EmptySinglePairIter<T>(EmptySinglePair<T>);
38 impl<T> Iterator for EmptySinglePairIter<T> {
41 fn next(&mut self) -> Option<T> {
42 match std::mem::replace(&mut self.0, Empty) {
53 impl<T: std::fmt::Debug> EmptySinglePair<T> {
54 pub(super) fn assert_single(self) -> T {
57 _ => panic!("Called assert_single on {:?}", self),
61 pub(super) fn assert_pair(self) -> (T, T) {
64 _ => panic!("Called assert_pair on {:?}", self),
70 pub(super) fn get_param_ty(self, tcx: TyCtxt<'_>) -> EmptySinglePair<Type> {
72 PassMode::NoPass => Empty,
73 PassMode::ByVal(clif_type) => Single(clif_type),
74 PassMode::ByValPair(a, b) => Pair(a, b),
75 PassMode::ByRef { size: Some(_) } => Single(pointer_ty(tcx)),
76 PassMode::ByRef { size: None } => Pair(pointer_ty(tcx), pointer_ty(tcx)),
81 pub(super) fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> PassMode {
83 // WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
87 Abi::Uninhabited => PassMode::NoPass,
88 Abi::Scalar(scalar) => PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone())),
89 Abi::ScalarPair(a, b) => {
90 let a = scalar_to_clif_type(tcx, a.clone());
91 let b = scalar_to_clif_type(tcx, b.clone());
92 if a == types::I128 && b == types::I128 {
93 // Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are
94 // available on x86_64. Cranelift gets confused when too many return params
97 size: Some(layout.size),
100 PassMode::ByValPair(a, b)
104 // FIXME implement Vector Abi in a cg_llvm compatible way
105 Abi::Vector { .. } => {
106 if let Some(vector_ty) = crate::intrinsics::clif_vector_type(tcx, layout) {
107 PassMode::ByVal(vector_ty)
110 size: Some(layout.size),
115 Abi::Aggregate { sized: true } => PassMode::ByRef {
116 size: Some(layout.size),
118 Abi::Aggregate { sized: false } => PassMode::ByRef { size: None },
123 /// Get a set of values to be passed as function arguments.
124 pub(super) fn adjust_arg_for_abi<'tcx>(
125 fx: &mut FunctionCx<'_, 'tcx, impl Module>,
127 ) -> EmptySinglePair<Value> {
128 match get_pass_mode(fx.tcx, arg.layout()) {
129 PassMode::NoPass => Empty,
130 PassMode::ByVal(_) => Single(arg.load_scalar(fx)),
131 PassMode::ByValPair(_, _) => {
132 let (a, b) = arg.load_scalar_pair(fx);
135 PassMode::ByRef { size: _ } => match arg.force_stack(fx) {
136 (ptr, None) => Single(ptr.get_addr(fx)),
137 (ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta),
142 /// Create a [`CValue`] containing the value of a function parameter adding clif function parameters
144 pub(super) fn cvalue_for_param<'tcx>(
145 fx: &mut FunctionCx<'_, 'tcx, impl Module>,
147 #[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>,
148 #[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>,
150 ) -> Option<CValue<'tcx>> {
151 let layout = fx.layout_of(arg_ty);
152 let pass_mode = get_pass_mode(fx.tcx, layout);
154 if let PassMode::NoPass = pass_mode {
158 let clif_types = pass_mode.get_param_ty(fx.tcx);
159 let block_params = clif_types.map(|t| fx.bcx.append_block_param(start_block, t));
161 #[cfg(debug_assertions)]
162 crate::abi::comments::add_arg_comment(
173 PassMode::NoPass => unreachable!(),
174 PassMode::ByVal(_) => Some(CValue::by_val(block_params.assert_single(), layout)),
175 PassMode::ByValPair(_, _) => {
176 let (a, b) = block_params.assert_pair();
177 Some(CValue::by_val_pair(a, b, layout))
179 PassMode::ByRef { size: Some(_) } => Some(CValue::by_ref(
180 Pointer::new(block_params.assert_single()),
183 PassMode::ByRef { size: None } => {
184 let (ptr, meta) = block_params.assert_pair();
185 Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout))