From d2634478781be741c872f33c7793797c081dc16f Mon Sep 17 00:00:00 2001 From: bjorn3 <bjorn3@users.noreply.github.com> Date: Wed, 27 Jan 2021 10:24:31 +0100 Subject: [PATCH] Replace EmptySinglePair with SmallVec --- Cargo.lock | 1 + Cargo.toml | 1 + src/abi/comments.rs | 17 ++++-- src/abi/mod.rs | 7 ++- src/abi/pass_mode.rs | 128 ++++++++++++++----------------------------- src/abi/returning.rs | 12 ++-- 6 files changed, 66 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 431e8068696..5495cfa5eaa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -333,6 +333,7 @@ dependencies = [ "indexmap", "libloading", "object", + "smallvec", "target-lexicon", ] diff --git a/Cargo.toml b/Cargo.toml index 4558da2de73..3820fce6d1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ object = { version = "0.22.0", default-features = false, features = ["std", "rea ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.0.2" libloading = { version = "0.6.0", optional = true } +smallvec = "1.6.1" # Uncomment to use local checkout of cranelift #[patch."https://github.com/bytecodealliance/wasmtime/"] diff --git a/src/abi/comments.rs b/src/abi/comments.rs index 41cb4c627f8..9aab45b62e2 100644 --- a/src/abi/comments.rs +++ b/src/abi/comments.rs @@ -8,7 +8,6 @@ use rustc_target::abi::call::PassMode; use cranelift_codegen::entity::EntityRef; -use crate::abi::pass_mode::*; use crate::prelude::*; pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, impl Module>) { @@ -22,7 +21,7 @@ pub(super) fn add_arg_comment<'tcx>( kind: &str, local: Option<mir::Local>, local_field: Option<usize>, - params: EmptySinglePair<Value>, + params: &[Value], arg_abi_mode: PassMode, arg_layout: TyAndLayout<'tcx>, ) { @@ -38,9 +37,17 @@ pub(super) fn add_arg_comment<'tcx>( }; let params = match params { - Empty => Cow::Borrowed("-"), - Single(param) => Cow::Owned(format!("= {:?}", param)), - Pair(param_a, param_b) => Cow::Owned(format!("= {:?}, {:?}", param_a, param_b)), + [] => Cow::Borrowed("-"), + [param] => Cow::Owned(format!("= {:?}", param)), + [param_a, param_b] => Cow::Owned(format!("= {:?},{:?}", param_a, param_b)), + params => Cow::Owned(format!( + "= {}", + params + .iter() + .map(ToString::to_string) + .collect::<Vec<_>>() + .join(",") + )), }; let pass_mode = format!("{:?}", arg_abi_mode); diff --git a/src/abi/mod.rs b/src/abi/mod.rs index 55ebd39e3f1..bc35ca2de40 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -11,6 +11,7 @@ use rustc_target::abi::call::{Conv, FnAbi}; use rustc_target::spec::abi::Abi; use cranelift_codegen::ir::AbiParam; +use smallvec::smallvec; use self::pass_mode::*; use crate::prelude::*; @@ -534,7 +535,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( ); } let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx); - (Some(method), Single(ptr)) + (Some(method), smallvec![ptr]) } // Normal call @@ -542,7 +543,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( None, args.get(0) .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0])) - .unwrap_or(Empty), + .unwrap_or(smallvec![]), ), // Indirect call @@ -557,7 +558,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( Some(func), args.get(0) .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0])) - .unwrap_or(Empty), + .unwrap_or(smallvec![]), ) } }; diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index e2b78bfeac0..e047ddcebc9 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -5,78 +5,24 @@ use crate::value_and_place::assert_assignable; use cranelift_codegen::ir::ArgumentPurpose; use rustc_target::abi::call::{ArgAbi, PassMode}; -pub(super) use EmptySinglePair::*; - -#[derive(Copy, Clone, Debug)] -pub(super) enum EmptySinglePair<T> { - Empty, - Single(T), - Pair(T, T), -} - -impl<T> EmptySinglePair<T> { - pub(super) fn into_iter(self) -> EmptySinglePairIter<T> { - EmptySinglePairIter(self) - } - - pub(super) fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> { - match self { - Empty => Empty, - Single(v) => Single(f(v)), - Pair(a, b) => Pair(f(a), f(b)), - } - } -} - -pub(super) struct EmptySinglePairIter<T>(EmptySinglePair<T>); - -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> { - pub(super) fn assert_single(self) -> T { - match self { - Single(v) => v, - _ => panic!("Called assert_single on {:?}", self), - } - } - - pub(super) fn assert_pair(self) -> (T, T) { - match self { - Pair(a, b) => (a, b), - _ => panic!("Called assert_pair on {:?}", self), - } - } -} +use smallvec::{smallvec, SmallVec}; pub(super) trait ArgAbiExt<'tcx> { - fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> EmptySinglePair<AbiParam>; + fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>; fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>); } impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { - fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> EmptySinglePair<AbiParam> { + fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> { match self.mode { - PassMode::Ignore => EmptySinglePair::Empty, + PassMode::Ignore => smallvec![], PassMode::Direct(_) => match &self.layout.abi { Abi::Scalar(scalar) => { - EmptySinglePair::Single(AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))) + smallvec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))] } Abi::Vector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap(); - EmptySinglePair::Single(AbiParam::new(vector_ty)) + smallvec![AbiParam::new(vector_ty)] } _ => unreachable!("{:?}", self.layout.abi), }, @@ -84,11 +30,11 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { Abi::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a.clone()); let b = scalar_to_clif_type(tcx, b.clone()); - EmptySinglePair::Pair(AbiParam::new(a), AbiParam::new(b)) + smallvec![AbiParam::new(a), AbiParam::new(b)] } _ => unreachable!("{:?}", self.layout.abi), }, - PassMode::Cast(_) => EmptySinglePair::Single(AbiParam::new(pointer_ty(tcx))), + PassMode::Cast(_) => smallvec![AbiParam::new(pointer_ty(tcx))], PassMode::Indirect { attrs: _, extra_attrs: None, @@ -96,12 +42,12 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } => { if on_stack { let size = u32::try_from(self.layout.size.bytes()).unwrap(); - EmptySinglePair::Single(AbiParam::special( + smallvec![AbiParam::special( pointer_ty(tcx), ArgumentPurpose::StructArgument(size), - )) + )] } else { - EmptySinglePair::Single(AbiParam::new(pointer_ty(tcx))) + smallvec![AbiParam::new(pointer_ty(tcx))] } } PassMode::Indirect { @@ -110,10 +56,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { on_stack, } => { assert!(!on_stack); - EmptySinglePair::Pair( + smallvec![ AbiParam::new(pointer_ty(tcx)), AbiParam::new(pointer_ty(tcx)), - ) + ] } } } @@ -176,18 +122,18 @@ pub(super) fn adjust_arg_for_abi<'tcx>( fx: &mut FunctionCx<'_, 'tcx, impl Module>, arg: CValue<'tcx>, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, -) -> EmptySinglePair<Value> { +) -> SmallVec<[Value; 2]> { assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty); match arg_abi.mode { - PassMode::Ignore => Empty, - PassMode::Direct(_) => Single(arg.load_scalar(fx)), + PassMode::Ignore => smallvec![], + PassMode::Direct(_) => smallvec![arg.load_scalar(fx)], PassMode::Pair(_, _) => { let (a, b) = arg.load_scalar_pair(fx); - Pair(a, b) + smallvec![a, b] } PassMode::Cast(_) | PassMode::Indirect { .. } => match arg.force_stack(fx) { - (ptr, None) => Single(ptr.get_addr(fx)), - (ptr, Some(meta)) => Pair(ptr.get_addr(fx), meta), + (ptr, None) => smallvec![ptr.get_addr(fx)], + (ptr, Some(meta)) => smallvec![ptr.get_addr(fx), meta], }, } } @@ -202,8 +148,10 @@ pub(super) fn cvalue_for_param<'tcx>( arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, ) -> Option<CValue<'tcx>> { let clif_types = arg_abi.get_abi_param(fx.tcx); - let block_params = - clif_types.map(|abi_param| fx.bcx.append_block_param(start_block, abi_param.value_type)); + let block_params = clif_types + .into_iter() + .map(|abi_param| fx.bcx.append_block_param(start_block, abi_param.value_type)) + .collect::<SmallVec<[_; 2]>>(); #[cfg(debug_assertions)] crate::abi::comments::add_arg_comment( @@ -211,7 +159,7 @@ pub(super) fn cvalue_for_param<'tcx>( "arg", local, local_field, - block_params, + &block_params, arg_abi.mode, arg_abi.layout, ); @@ -219,30 +167,38 @@ pub(super) fn cvalue_for_param<'tcx>( match arg_abi.mode { PassMode::Ignore => None, PassMode::Direct(_) => { - Some(CValue::by_val(block_params.assert_single(), arg_abi.layout)) + assert_eq!(block_params.len(), 1, "{:?}", block_params); + Some(CValue::by_val(block_params[0], arg_abi.layout)) } PassMode::Pair(_, _) => { - let (a, b) = block_params.assert_pair(); - Some(CValue::by_val_pair(a, b, arg_abi.layout)) + assert_eq!(block_params.len(), 2, "{:?}", block_params); + Some(CValue::by_val_pair( + block_params[0], + block_params[1], + arg_abi.layout, + )) } PassMode::Cast(_) | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _, - } => Some(CValue::by_ref( - Pointer::new(block_params.assert_single()), - arg_abi.layout, - )), + } => { + assert_eq!(block_params.len(), 1, "{:?}", block_params); + Some(CValue::by_ref( + Pointer::new(block_params[0]), + arg_abi.layout, + )) + } PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _, } => { - let (ptr, meta) = block_params.assert_pair(); + assert_eq!(block_params.len(), 2, "{:?}", block_params); Some(CValue::by_ref_unsized( - Pointer::new(ptr), - meta, + Pointer::new(block_params[0]), + block_params[1], arg_abi.layout, )) } diff --git a/src/abi/returning.rs b/src/abi/returning.rs index d7a82e0c377..8376f845734 100644 --- a/src/abi/returning.rs +++ b/src/abi/returning.rs @@ -1,10 +1,10 @@ //! Return value handling -use crate::abi::pass_mode::*; use crate::prelude::*; use rustc_middle::ty::layout::FnAbiExt; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use smallvec::{SmallVec, smallvec}; /// Can the given type be returned into an ssa var or does it need to be returned on the stack. pub(crate) fn can_return_to_ssa_var<'tcx>( @@ -62,10 +62,10 @@ pub(super) fn codegen_return_param<'tcx>( ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>, start_block: Block, ) -> CPlace<'tcx> { - let (ret_place, ret_param) = match fx.fn_abi.as_ref().unwrap().ret.mode { + let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode { PassMode::Ignore => ( CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout), - Empty, + smallvec![], ), PassMode::Direct(_) | PassMode::Pair(_, _) => { let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa; @@ -76,7 +76,7 @@ pub(super) fn codegen_return_param<'tcx>( fx.fn_abi.as_ref().unwrap().ret.layout, is_ssa, ), - Empty, + smallvec![], ) } PassMode::Cast(_) @@ -91,7 +91,7 @@ pub(super) fn codegen_return_param<'tcx>( Pointer::new(ret_param), fx.fn_abi.as_ref().unwrap().ret.layout, ), - Single(ret_param), + smallvec![ret_param], ) } PassMode::Indirect { @@ -110,7 +110,7 @@ pub(super) fn codegen_return_param<'tcx>( "ret", Some(RETURN_PLACE), None, - ret_param, + &ret_param, fx.fn_abi.as_ref().unwrap().ret.mode, fx.fn_abi.as_ref().unwrap().ret.layout, );