2019-08-30 11:58:52 +02:00
|
|
|
use crate::prelude::*;
|
|
|
|
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) use EmptySinglePair::*;
|
|
|
|
|
2019-08-30 11:58:52 +02:00
|
|
|
#[derive(Copy, Clone, Debug)]
|
2020-03-27 12:14:45 +01:00
|
|
|
pub(super) enum PassMode {
|
2019-08-30 11:58:52 +02:00
|
|
|
NoPass,
|
|
|
|
ByVal(Type),
|
|
|
|
ByValPair(Type, Type),
|
2020-04-20 17:13:43 +02:00
|
|
|
ByRef { size: Option<Size> },
|
2019-08-30 11:58:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) enum EmptySinglePair<T> {
|
2019-08-30 11:58:52 +02:00
|
|
|
Empty,
|
|
|
|
Single(T),
|
|
|
|
Pair(T, T),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> EmptySinglePair<T> {
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) fn into_iter(self) -> EmptySinglePairIter<T> {
|
2019-08-30 11:58:52 +02:00
|
|
|
EmptySinglePairIter(self)
|
|
|
|
}
|
|
|
|
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> {
|
2019-08-30 11:58:52 +02:00
|
|
|
match self {
|
|
|
|
Empty => Empty,
|
|
|
|
Single(v) => Single(f(v)),
|
|
|
|
Pair(a, b) => Pair(f(a), f(b)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) struct EmptySinglePairIter<T>(EmptySinglePair<T>);
|
2019-08-30 11:58:52 +02:00
|
|
|
|
|
|
|
impl<T> Iterator for EmptySinglePairIter<T> {
|
|
|
|
type Item = T;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<T> {
|
|
|
|
match std::mem::replace(&mut self.0, Empty) {
|
|
|
|
Empty => None,
|
|
|
|
Single(v) => Some(v),
|
|
|
|
Pair(a, b) => {
|
|
|
|
self.0 = Single(b);
|
|
|
|
Some(a)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: std::fmt::Debug> EmptySinglePair<T> {
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) fn assert_single(self) -> T {
|
2019-08-30 11:58:52 +02:00
|
|
|
match self {
|
|
|
|
Single(v) => v,
|
2019-08-31 22:58:09 +05:30
|
|
|
_ => panic!("Called assert_single on {:?}", self),
|
2019-08-30 11:58:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) fn assert_pair(self) -> (T, T) {
|
2019-08-30 11:58:52 +02:00
|
|
|
match self {
|
|
|
|
Pair(a, b) => (a, b),
|
2019-08-31 22:58:09 +05:30
|
|
|
_ => panic!("Called assert_pair on {:?}", self),
|
2019-08-30 11:58:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PassMode {
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) fn get_param_ty(self, tcx: TyCtxt<'_>) -> EmptySinglePair<Type> {
|
2019-08-30 11:58:52 +02:00
|
|
|
match self {
|
|
|
|
PassMode::NoPass => Empty,
|
|
|
|
PassMode::ByVal(clif_type) => Single(clif_type),
|
|
|
|
PassMode::ByValPair(a, b) => Pair(a, b),
|
2020-04-20 17:13:43 +02:00
|
|
|
PassMode::ByRef { size: Some(_) } => Single(pointer_ty(tcx)),
|
|
|
|
PassMode::ByRef { size: None } => Pair(pointer_ty(tcx), pointer_ty(tcx)),
|
2019-08-30 11:58:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-30 19:00:24 +02:00
|
|
|
pub(super) fn get_pass_mode<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> PassMode {
|
2019-08-30 11:58:52 +02:00
|
|
|
if layout.is_zst() {
|
|
|
|
// WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
|
|
|
|
PassMode::NoPass
|
|
|
|
} else {
|
|
|
|
match &layout.abi {
|
2020-04-03 11:54:18 +02:00
|
|
|
Abi::Uninhabited => PassMode::NoPass,
|
2020-08-28 12:10:48 +02:00
|
|
|
Abi::Scalar(scalar) => PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone())),
|
2020-04-03 11:54:18 +02:00
|
|
|
Abi::ScalarPair(a, b) => {
|
2019-08-30 11:58:52 +02:00
|
|
|
let a = scalar_to_clif_type(tcx, a.clone());
|
|
|
|
let b = scalar_to_clif_type(tcx, b.clone());
|
|
|
|
if a == types::I128 && b == types::I128 {
|
|
|
|
// Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are
|
|
|
|
// available on x86_64. Cranelift gets confused when too many return params
|
|
|
|
// are used.
|
2020-08-28 12:10:48 +02:00
|
|
|
PassMode::ByRef {
|
|
|
|
size: Some(layout.size),
|
|
|
|
}
|
2019-08-30 11:58:52 +02:00
|
|
|
} else {
|
|
|
|
PassMode::ByValPair(a, b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME implement Vector Abi in a cg_llvm compatible way
|
2020-03-28 15:33:50 +01:00
|
|
|
Abi::Vector { .. } => {
|
|
|
|
if let Some(vector_ty) = crate::intrinsics::clif_vector_type(tcx, layout) {
|
|
|
|
PassMode::ByVal(vector_ty)
|
|
|
|
} else {
|
2020-08-28 12:10:48 +02:00
|
|
|
PassMode::ByRef {
|
|
|
|
size: Some(layout.size),
|
|
|
|
}
|
2020-03-28 15:33:50 +01:00
|
|
|
}
|
|
|
|
}
|
2019-08-30 11:58:52 +02:00
|
|
|
|
2020-08-28 12:10:48 +02:00
|
|
|
Abi::Aggregate { sized: true } => PassMode::ByRef {
|
|
|
|
size: Some(layout.size),
|
|
|
|
},
|
2020-04-20 17:13:43 +02:00
|
|
|
Abi::Aggregate { sized: false } => PassMode::ByRef { size: None },
|
2019-08-30 11:58:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) fn adjust_arg_for_abi<'tcx>(
|
2019-08-30 11:58:52 +02:00
|
|
|
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
|
|
|
arg: CValue<'tcx>,
|
|
|
|
) -> EmptySinglePair<Value> {
|
|
|
|
match get_pass_mode(fx.tcx, arg.layout()) {
|
|
|
|
PassMode::NoPass => Empty,
|
|
|
|
PassMode::ByVal(_) => Single(arg.load_scalar(fx)),
|
|
|
|
PassMode::ByValPair(_, _) => {
|
|
|
|
let (a, b) = arg.load_scalar_pair(fx);
|
|
|
|
Pair(a, b)
|
|
|
|
}
|
2020-08-28 12:10:48 +02:00
|
|
|
PassMode::ByRef { size: _ } => match arg.force_stack(fx) {
|
|
|
|
(ptr, None) => Single(ptr.get_addr(fx)),
|
|
|
|
(ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta),
|
|
|
|
},
|
2019-08-30 11:58:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-14 17:11:06 +01:00
|
|
|
pub(super) fn cvalue_for_param<'tcx>(
|
2019-08-30 11:58:52 +02:00
|
|
|
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
|
2020-02-14 18:23:29 +01:00
|
|
|
start_block: Block,
|
2020-08-28 12:10:48 +02:00
|
|
|
#[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>,
|
|
|
|
#[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>,
|
2019-08-30 11:58:52 +02:00
|
|
|
arg_ty: Ty<'tcx>,
|
|
|
|
) -> Option<CValue<'tcx>> {
|
|
|
|
let layout = fx.layout_of(arg_ty);
|
2020-01-15 13:17:09 +01:00
|
|
|
let pass_mode = get_pass_mode(fx.tcx, layout);
|
2019-08-30 11:58:52 +02:00
|
|
|
|
|
|
|
if let PassMode::NoPass = pass_mode {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2019-08-30 12:42:18 +02:00
|
|
|
let clif_types = pass_mode.get_param_ty(fx.tcx);
|
2020-02-14 18:23:29 +01:00
|
|
|
let block_params = clif_types.map(|t| fx.bcx.append_block_param(start_block, t));
|
2019-08-30 11:58:52 +02:00
|
|
|
|
|
|
|
#[cfg(debug_assertions)]
|
2019-08-30 14:21:24 +02:00
|
|
|
crate::abi::comments::add_arg_comment(
|
2019-08-30 11:58:52 +02:00
|
|
|
fx,
|
|
|
|
"arg",
|
|
|
|
local,
|
|
|
|
local_field,
|
2020-02-14 18:23:29 +01:00
|
|
|
block_params,
|
2019-08-30 11:58:52 +02:00
|
|
|
pass_mode,
|
|
|
|
arg_ty,
|
|
|
|
);
|
|
|
|
|
|
|
|
match pass_mode {
|
|
|
|
PassMode::NoPass => unreachable!(),
|
2020-02-14 18:23:29 +01:00
|
|
|
PassMode::ByVal(_) => Some(CValue::by_val(block_params.assert_single(), layout)),
|
2019-08-30 11:58:52 +02:00
|
|
|
PassMode::ByValPair(_, _) => {
|
2020-02-14 18:23:29 +01:00
|
|
|
let (a, b) = block_params.assert_pair();
|
2019-08-30 11:58:52 +02:00
|
|
|
Some(CValue::by_val_pair(a, b, layout))
|
|
|
|
}
|
2020-08-28 12:10:48 +02:00
|
|
|
PassMode::ByRef { size: Some(_) } => Some(CValue::by_ref(
|
|
|
|
Pointer::new(block_params.assert_single()),
|
|
|
|
layout,
|
|
|
|
)),
|
2020-04-20 17:13:43 +02:00
|
|
|
PassMode::ByRef { size: None } => {
|
2020-02-14 18:23:29 +01:00
|
|
|
let (ptr, meta) = block_params.assert_pair();
|
2020-01-25 16:23:54 +01:00
|
|
|
Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout))
|
|
|
|
}
|
2019-08-30 11:58:52 +02:00
|
|
|
}
|
|
|
|
}
|