diff options
| author | bjorn3 <bjorn3@users.noreply.github.com> | 2021-01-26 21:41:20 +0100 |
|---|---|---|
| committer | bjorn3 <bjorn3@users.noreply.github.com> | 2021-01-26 21:41:20 +0100 |
| commit | fc595f1a555d7f43802679511e9fdf1f64f2c49a (patch) | |
| tree | e4301fadd2021859eeda2cd2f024750dafb62e85 | |
| parent | 4555737152c0f68df5596b16d6e996d19caf2a6a (diff) | |
| download | rust-fc595f1a555d7f43802679511e9fdf1f64f2c49a.tar.gz rust-fc595f1a555d7f43802679511e9fdf1f64f2c49a.zip | |
[WIP] Use FnAbi everywhere instead of our own abi calculations
| -rw-r--r-- | src/abi/comments.rs | 9 | ||||
| -rw-r--r-- | src/abi/mod.rs | 227 | ||||
| -rw-r--r-- | src/abi/pass_mode.rs | 113 | ||||
| -rw-r--r-- | src/abi/returning.rs | 138 | ||||
| -rw-r--r-- | src/analyze.rs | 6 | ||||
| -rw-r--r-- | src/base.rs | 3 | ||||
| -rw-r--r-- | src/common.rs | 57 | ||||
| -rw-r--r-- | src/lib.rs | 2 | ||||
| -rw-r--r-- | src/value_and_place.rs | 117 |
9 files changed, 355 insertions, 317 deletions
diff --git a/src/abi/comments.rs b/src/abi/comments.rs index 4847b007a36..41cb4c627f8 100644 --- a/src/abi/comments.rs +++ b/src/abi/comments.rs @@ -4,7 +4,7 @@ use std::borrow::Cow; use rustc_middle::mir; -use rustc_target::abi::call::ArgAbi; +use rustc_target::abi::call::PassMode; use cranelift_codegen::entity::EntityRef; @@ -23,7 +23,8 @@ pub(super) fn add_arg_comment<'tcx>( local: Option<mir::Local>, local_field: Option<usize>, params: EmptySinglePair<Value>, - arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, + arg_abi_mode: PassMode, + arg_layout: TyAndLayout<'tcx>, ) { let local = if let Some(local) = local { Cow::Owned(format!("{:?}", local)) @@ -42,7 +43,7 @@ pub(super) fn add_arg_comment<'tcx>( Pair(param_a, param_b) => Cow::Owned(format!("= {:?}, {:?}", param_a, param_b)), }; - let pass_mode = format!("{:?}", arg_abi.mode); + let pass_mode = format!("{:?}", arg_abi_mode); fx.add_global_comment(format!( "{kind:5}{local:>3}{local_field:<5} {params:10} {pass_mode:36} {ty:?}", kind = kind, @@ -50,7 +51,7 @@ pub(super) fn add_arg_comment<'tcx>( local_field = local_field, params = params, pass_mode = pass_mode, - ty = arg_abi.layout.ty, + ty = arg_layout.ty, )); } diff --git a/src/abi/mod.rs b/src/abi/mod.rs index bc2111726d2..55ebd39e3f1 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -6,7 +6,8 @@ mod pass_mode; mod returning; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_target::abi::call::PassMode as RustcPassMode; +use rustc_middle::ty::layout::FnAbiExt; +use rustc_target::abi::call::{Conv, FnAbi}; use rustc_target::spec::abi::Abi; use cranelift_codegen::ir::AbiParam; @@ -16,6 +17,7 @@ use crate::prelude::*; pub(crate) use self::returning::{can_return_to_ssa_var, codegen_return}; +// FIXME remove // Copied from https://github.com/rust-lang/rust/blob/f52c72948aa1dd718cc1f168d21c91c584c0a662/src/librustc_middle/ty/layout.rs#L2301 #[rustfmt::skip] pub(crate) fn fn_sig_for_fn_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::PolyFnSig<'tcx> { @@ -93,84 +95,38 @@ pub(crate) fn fn_sig_for_fn_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx } } -fn clif_sig_from_fn_sig<'tcx>( +fn clif_sig_from_fn_abi<'tcx>( tcx: TyCtxt<'tcx>, triple: &target_lexicon::Triple, - sig: FnSig<'tcx>, - is_vtable_fn: bool, - requires_caller_location: bool, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> Signature { - let abi = match sig.abi { - Abi::System => Abi::C, - abi => abi, - }; - let (call_conv, inputs, output): (CallConv, Vec<Ty<'tcx>>, Ty<'tcx>) = match abi { - Abi::Rust => ( - CallConv::triple_default(triple), - sig.inputs().to_vec(), - sig.output(), - ), - Abi::C | Abi::Unadjusted => ( - CallConv::triple_default(triple), - sig.inputs().to_vec(), - sig.output(), - ), - Abi::SysV64 => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()), - Abi::RustCall => { - assert_eq!(sig.inputs().len(), 2); - let extra_args = match sig.inputs().last().unwrap().kind() { - ty::Tuple(ref tupled_arguments) => tupled_arguments, - _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"), - }; - let mut inputs: Vec<Ty<'tcx>> = vec![sig.inputs()[0]]; - inputs.extend(extra_args.types()); - (CallConv::triple_default(triple), inputs, sig.output()) + let call_conv = match fn_abi.conv { + Conv::Rust | Conv::C => CallConv::triple_default(triple), + Conv::X86_64SysV => CallConv::SystemV, + Conv::X86_64Win64 => CallConv::WindowsFastcall, + Conv::ArmAapcs + | Conv::Msp430Intr + | Conv::PtxKernel + | Conv::X86Fastcall + | Conv::X86Intr + | Conv::X86Stdcall + | Conv::X86ThisCall + | Conv::X86VectorCall + | Conv::AmdGpuKernel + | Conv::AvrInterrupt + | Conv::AvrNonBlockingInterrupt => { + todo!("{:?}", fn_abi.conv) } - Abi::System => unreachable!(), - Abi::RustIntrinsic => ( - CallConv::triple_default(triple), - sig.inputs().to_vec(), - sig.output(), - ), - _ => unimplemented!("unsupported abi {:?}", sig.abi), }; - - let inputs = inputs - .into_iter() - .enumerate() - .map(|(i, ty)| { - let mut layout = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap(); - if i == 0 && is_vtable_fn { - // Virtual calls turn their self param into a thin pointer. - // See https://github.com/rust-lang/rust/blob/37b6a5e5e82497caf5353d9d856e4eb5d14cbe06/src/librustc/ty/layout.rs#L2519-L2572 for more info - layout = tcx - .layout_of(ParamEnv::reveal_all().and(tcx.mk_mut_ptr(tcx.mk_unit()))) - .unwrap(); - } - let mut arg_abi = get_arg_abi(tcx, layout); - if abi != Abi::Rust && abi != Abi::RustCall && abi != Abi::RustIntrinsic { - match arg_abi.mode { - RustcPassMode::Indirect { - ref mut on_stack, .. - } => *on_stack = true, - _ => {} - } - } - arg_abi.get_abi_param(tcx).into_iter() - }) + let inputs = fn_abi + .args + .iter() + .map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()) .flatten(); - let return_arg_abi = get_arg_abi( - tcx, - tcx.layout_of(ParamEnv::reveal_all().and(output)).unwrap(), - ); - let (return_ptr, returns) = return_arg_abi.get_abi_return(tcx); + let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx); // Sometimes the first param is an pointer to the place where the return value needs to be stored. - let mut params: Vec<_> = return_ptr.into_iter().chain(inputs).collect(); - - if requires_caller_location { - params.push(AbiParam::new(pointer_ty(tcx))); - } + let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect(); Signature { params, @@ -194,12 +150,11 @@ pub(crate) fn get_function_sig<'tcx>( "Variadic function definitions are not yet supported", ); } - clif_sig_from_fn_sig( + + clif_sig_from_fn_abi( tcx, triple, - fn_sig, - false, - inst.def.requires_caller_location(tcx), + &FnAbi::of_instance(&RevealAllLayoutCx(tcx), inst, &[]), ) } @@ -337,6 +292,9 @@ pub(crate) fn codegen_fn_prelude<'tcx>( Spread(Vec<Option<CValue<'tcx>>>), } + let fn_abi = fx.fn_abi.take().unwrap(); + let mut arg_abis_iter = fn_abi.args.iter(); + let func_params = fx .mir .args_iter() @@ -356,14 +314,16 @@ pub(crate) fn codegen_fn_prelude<'tcx>( }; let mut params = Vec::new(); - for (i, arg_ty) in tupled_arg_tys.types().enumerate() { - let param = cvalue_for_param(fx, start_block, Some(local), Some(i), arg_ty); + for (i, _arg_ty) in tupled_arg_tys.types().enumerate() { + let arg_abi = arg_abis_iter.next().unwrap(); + let param = cvalue_for_param(fx, start_block, Some(local), Some(i), arg_abi); params.push(param); } (local, ArgKind::Spread(params), arg_ty) } else { - let param = cvalue_for_param(fx, start_block, Some(local), None, arg_ty); + let arg_abi = arg_abis_iter.next().unwrap(); + let param = cvalue_for_param(fx, start_block, Some(local), None, arg_abi); (local, ArgKind::Normal(param), arg_ty) } }) @@ -372,11 +332,13 @@ pub(crate) fn codegen_fn_prelude<'tcx>( assert!(fx.caller_location.is_none()); if fx.instance.def.requires_caller_location(fx.tcx) { // Store caller location for `#[track_caller]`. - fx.caller_location = Some( - cvalue_for_param(fx, start_block, None, None, fx.tcx.caller_location_ty()).unwrap(), - ); + let arg_abi = arg_abis_iter.next().unwrap(); + fx.caller_location = Some(cvalue_for_param(fx, start_block, None, None, arg_abi).unwrap()); } + assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind"); + fx.fn_abi = Some(fn_abi); + fx.bcx.switch_to_block(start_block); fx.bcx.ins().nop(); @@ -504,6 +466,21 @@ pub(crate) fn codegen_terminator_call<'tcx>( None }; + let extra_args = &args[fn_sig.inputs().len()..]; + let extra_args = extra_args + .iter() + .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))) + .collect::<Vec<_>>(); + let fn_abi = if let Some(instance) = instance { + FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args) + } else { + FnAbi::of_fn_ptr( + &RevealAllLayoutCx(fx.tcx), + fn_ty.fn_sig(fx.tcx), + &extra_args, + ) + }; + let is_cold = instance .map(|inst| { fx.tcx @@ -541,8 +518,8 @@ pub(crate) fn codegen_terminator_call<'tcx>( // | indirect call target // | | the first argument to be passed - // v v v virtual calls are special cased below - let (func_ref, first_arg, is_virtual_call) = match instance { + // v v + let (func_ref, first_arg) = match instance { // Trait object call Some(Instance { def: InstanceDef::Virtual(_, idx), @@ -553,23 +530,19 @@ pub(crate) fn codegen_terminator_call<'tcx>( let nop_inst = fx.bcx.ins().nop(); fx.add_comment( nop_inst, - format!( - "virtual call; self arg pass mode: {:?}", - get_arg_abi(fx.tcx, args[0].layout()).mode, - ), + format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0],), ); } let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx); - (Some(method), Single(ptr), true) + (Some(method), Single(ptr)) } // Normal call Some(_) => ( None, args.get(0) - .map(|arg| adjust_arg_for_abi(fx, *arg)) + .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0])) .unwrap_or(Empty), - false, ), // Indirect call @@ -583,23 +556,27 @@ pub(crate) fn codegen_terminator_call<'tcx>( ( Some(func), args.get(0) - .map(|arg| adjust_arg_for_abi(fx, *arg)) + .map(|arg| adjust_arg_for_abi(fx, *arg, &fn_abi.args[0])) .unwrap_or(Empty), - false, ) } }; let ret_place = destination.map(|(place, _)| place); - let (call_inst, call_args) = - self::returning::codegen_with_call_return_arg(fx, fn_sig, ret_place, |fx, return_ptr| { + let (call_inst, call_args) = self::returning::codegen_with_call_return_arg( + fx, + &fn_abi.ret, + ret_place, + |fx, return_ptr| { + let regular_args_count = args.len(); let mut call_args: Vec<Value> = return_ptr .into_iter() .chain(first_arg.into_iter()) .chain( args.into_iter() + .enumerate() .skip(1) - .map(|arg| adjust_arg_for_abi(fx, arg).into_iter()) + .map(|(i, arg)| adjust_arg_for_abi(fx, arg, &fn_abi.args[i]).into_iter()) .flatten(), ) .collect::<Vec<_>>(); @@ -610,17 +587,17 @@ pub(crate) fn codegen_terminator_call<'tcx>( { // Pass the caller location for `#[track_caller]`. let caller_location = fx.get_caller_location(span); - call_args.extend(adjust_arg_for_abi(fx, caller_location).into_iter()); + call_args.extend( + adjust_arg_for_abi(fx, caller_location, &fn_abi.args[regular_args_count]) + .into_iter(), + ); + assert_eq!(fn_abi.args.len(), regular_args_count + 1); + } else { + assert_eq!(fn_abi.args.len(), regular_args_count); } let call_inst = if let Some(func_ref) = func_ref { - let sig = clif_sig_from_fn_sig( - fx.tcx, - fx.triple(), - fn_sig, - is_virtual_call, - false, // calls through function pointers never pass the caller location - ); + let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi); let sig = fx.bcx.import_signature(sig); fx.bcx.ins().call_indirect(sig, func_ref, &call_args) } else { @@ -630,7 +607,8 @@ pub(crate) fn codegen_terminator_call<'tcx>( }; (call_inst, call_args) - }); + }, + ); // FIXME find a cleaner way to support varargs if fn_sig.c_variadic { @@ -671,36 +649,33 @@ pub(crate) fn codegen_drop<'tcx>( drop_place: CPlace<'tcx>, ) { let ty = drop_place.layout().ty; - let drop_fn = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); + let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); - if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { + if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def { // we don't actually need to drop anything } else { - let drop_fn_ty = drop_fn.ty(fx.tcx, ParamEnv::reveal_all()); - let fn_sig = fx.tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - drop_fn_ty.fn_sig(fx.tcx), - ); - assert_eq!(fn_sig.output(), fx.tcx.mk_unit()); - match ty.kind() { ty::Dynamic(..) => { let (ptr, vtable) = drop_place.to_ptr_maybe_unsized(); let ptr = ptr.get_addr(fx); let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap()); - let sig = clif_sig_from_fn_sig( - fx.tcx, - fx.triple(), - fn_sig, - true, - false, // `drop_in_place` is never `#[track_caller]` - ); + // FIXME(eddyb) perhaps move some of this logic into + // `Instance::resolve_drop_in_place`? + let virtual_drop = Instance { + def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), + substs: drop_instance.substs, + }; + let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), virtual_drop, &[]); + + let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi); let sig = fx.bcx.import_signature(sig); fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]); } _ => { - assert!(!matches!(drop_fn.def, InstanceDef::Virtual(_, _))); + assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _))); + + let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), drop_instance, &[]); let arg_value = drop_place.place_ref( fx, @@ -712,17 +687,19 @@ pub(crate) fn codegen_drop<'tcx>( }, )), ); - let arg_value = adjust_arg_for_abi(fx, arg_value); + let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0]); let mut call_args: Vec<Value> = arg_value.into_iter().collect::<Vec<_>>(); - if drop_fn.def.requires_caller_location(fx.tcx) { + if drop_instance.def.requires_caller_location(fx.tcx) { // Pass the caller location for `#[track_caller]`. let caller_location = fx.get_caller_location(span); - call_args.extend(adjust_arg_for_abi(fx, caller_location).into_iter()); + call_args.extend( + adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1]).into_iter(), + ); } - let func_ref = fx.get_function_ref(drop_fn); + let func_ref = fx.get_function_ref(drop_instance); fx.bcx.ins().call(func_ref, &call_args); } } diff --git a/src/abi/pass_mode.rs b/src/abi/pass_mode.rs index aec321bd4a0..e2b78bfeac0 100644 --- a/src/abi/pass_mode.rs +++ b/src/abi/pass_mode.rs @@ -1,9 +1,10 @@ //! Argument passing use crate::prelude::*; +use crate::value_and_place::assert_assignable; use cranelift_codegen::ir::ArgumentPurpose; -use rustc_target::abi::call::{ArgAbi, ArgAttributes, PassMode as RustcPassMode}; +use rustc_target::abi::call::{ArgAbi, PassMode}; pub(super) use EmptySinglePair::*; #[derive(Copy, Clone, Debug)] @@ -68,8 +69,8 @@ pub(super) trait ArgAbiExt<'tcx> { impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> EmptySinglePair<AbiParam> { match self.mode { - RustcPassMode::Ignore => EmptySinglePair::Empty, - RustcPassMode::Direct(_) => match &self.layout.abi { + PassMode::Ignore => EmptySinglePair::Empty, + PassMode::Direct(_) => match &self.layout.abi { Abi::Scalar(scalar) => { EmptySinglePair::Single(AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))) } @@ -79,7 +80,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.abi), }, - RustcPassMode::Pair(_, _) => match &self.layout.abi { + PassMode::Pair(_, _) => match &self.layout.abi { Abi::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a.clone()); let b = scalar_to_clif_type(tcx, b.clone()); @@ -87,8 +88,8 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.abi), }, - RustcPassMode::Cast(_) => EmptySinglePair::Single(AbiParam::new(pointer_ty(tcx))), - RustcPassMode::Indirect { + PassMode::Cast(_) => EmptySinglePair::Single(AbiParam::new(pointer_ty(tcx))), + PassMode::Indirect { attrs: _, extra_attrs: None, on_stack, @@ -103,7 +104,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { EmptySinglePair::Single(AbiParam::new(pointer_ty(tcx))) } } - RustcPassMode::Indirect { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack, @@ -119,8 +120,8 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) { match self.mode { - RustcPassMode::Ignore => (None, vec![]), - RustcPassMode::Direct(_) => match &self.layout.abi { + PassMode::Ignore => (None, vec![]), + PassMode::Direct(_) => match &self.layout.abi { Abi::Scalar(scalar) => ( None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))], @@ -132,7 +133,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.abi), }, - RustcPassMode::Pair(_, _) => match &self.layout.abi { + PassMode::Pair(_, _) => match &self.layout.abi { Abi::ScalarPair(a, b) => { let a = scalar_to_clif_type(tcx, a.clone()); let b = scalar_to_clif_type(tcx, b.clone()); @@ -140,14 +141,14 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } _ => unreachable!("{:?}", self.layout.abi), }, - RustcPassMode::Cast(_) => ( + PassMode::Cast(_) => ( Some(AbiParam::special( pointer_ty(tcx), ArgumentPurpose::StructReturn, )), vec![], ), - RustcPassMode::Indirect { + PassMode::Indirect { attrs: _, extra_attrs: None, on_stack, @@ -161,7 +162,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { vec![], ) } - RustcPassMode::Indirect { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _, @@ -170,56 +171,21 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { } } -pub(super) fn get_arg_abi<'tcx>( - tcx: TyCtxt<'tcx>, - layout: TyAndLayout<'tcx>, -) -> ArgAbi<'tcx, Ty<'tcx>> { - let mut arg_abi = ArgAbi::new(&tcx, layout, |_, _, _| ArgAttributes::new()); - if layout.is_zst() { - // WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer - arg_abi.mode = RustcPassMode::Ignore; - } - match arg_abi.mode { - RustcPassMode::Ignore => {} - RustcPassMode::Direct(_) => match &arg_abi.layout.abi { - Abi::Scalar(_) => {} - // FIXME implement Vector Abi in a cg_llvm compatible way - Abi::Vector { .. } => { - if crate::intrinsics::clif_vector_type(tcx, arg_abi.layout).is_none() { - arg_abi.make_indirect(); - } - } - _ => unreachable!("{:?}", arg_abi.layout.abi), - }, - RustcPassMode::Pair(_, _) => match &arg_abi.layout.abi { - Abi::ScalarPair(a, b) => { - 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 { - arg_abi.make_indirect(); - } - } - _ => unreachable!("{:?}", arg_abi.layout.abi), - }, - _ => {} - } - arg_abi -} - /// Get a set of values to be passed as function arguments. 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> { - let arg_abi = get_arg_abi(fx.tcx, arg.layout()); + assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty); match arg_abi.mode { - RustcPassMode::Ignore => Empty, - RustcPassMode::Direct(_) => Single(arg.load_scalar(fx)), - RustcPassMode::Pair(_, _) => { + PassMode::Ignore => Empty, + PassMode::Direct(_) => Single(arg.load_scalar(fx)), + PassMode::Pair(_, _) => { let (a, b) = arg.load_scalar_pair(fx); Pair(a, b) } - RustcPassMode::Cast(_) | RustcPassMode::Indirect { .. } => match arg.force_stack(fx) { + 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), }, @@ -233,41 +199,52 @@ pub(super) fn cvalue_for_param<'tcx>( start_block: Block, #[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>, #[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>, - arg_ty: Ty<'tcx>, + arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, ) -> Option<CValue<'tcx>> { - let layout = fx.layout_of(arg_ty); - let arg_abi = get_arg_abi(fx.tcx, layout); - 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)); #[cfg(debug_assertions)] - crate::abi::comments::add_arg_comment(fx, "arg", local, local_field, block_params, &arg_abi); + crate::abi::comments::add_arg_comment( + fx, + "arg", + local, + local_field, + block_params, + arg_abi.mode, + arg_abi.layout, + ); match arg_abi.mode { - RustcPassMode::Ignore => None, - RustcPassMode::Direct(_) => Some(CValue::by_val(block_params.assert_single(), layout)), - RustcPassMode::Pair(_, _) => { + PassMode::Ignore => None, + PassMode::Direct(_) => { + Some(CValue::by_val(block_params.assert_single(), arg_abi.layout)) + } + PassMode::Pair(_, _) => { let (a, b) = block_params.assert_pair(); - Some(CValue::by_val_pair(a, b, layout)) + Some(CValue::by_val_pair(a, b, arg_abi.layout)) } - RustcPassMode::Cast(_) - | RustcPassMode::Indirect { + PassMode::Cast(_) + | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _, } => Some(CValue::by_ref( Pointer::new(block_params.assert_single()), - layout, + arg_abi.layout, )), - RustcPassMode::Indirect { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _, } => { let (ptr, meta) = block_params.assert_pair(); - Some(CValue::by_ref_unsized(Pointer::new(ptr), meta, layout)) + Some(CValue::by_ref_unsized( + Pointer::new(ptr), + meta, + arg_abi.layout, + )) } } } diff --git a/src/abi/returning.rs b/src/abi/returning.rs index 3a5f61315f8..d7a82e0c377 100644 --- a/src/abi/returning.rs +++ b/src/abi/returning.rs @@ -3,21 +3,55 @@ use crate::abi::pass_mode::*; use crate::prelude::*; -use rustc_target::abi::call::PassMode as RustcPassMode; - -fn return_layout<'a, 'tcx>(fx: &mut FunctionCx<'a, 'tcx, impl Module>) -> TyAndLayout<'tcx> { - fx.layout_of(fx.monomorphize(&fx.mir.local_decls[RETURN_PLACE].ty)) -} +use rustc_middle::ty::layout::FnAbiExt; +use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; /// 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>( - tcx: TyCtxt<'tcx>, - dest_layout: TyAndLayout<'tcx>, + fx: &FunctionCx<'_, 'tcx, impl Module>, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], ) -> bool { - match get_arg_abi(tcx, dest_layout).mode { - RustcPassMode::Ignore | RustcPassMode::Direct(_) | RustcPassMode::Pair(_, _) => true, + let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx)); + let fn_sig = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx)); + + // Handle special calls like instrinsics and empty drop glue. + let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() { + let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs) + .unwrap() + .unwrap() + .polymorphize(fx.tcx); + + match instance.def { + InstanceDef::Intrinsic(_) | InstanceDef::DropGlue(_, _) => { + return true; + } + _ => Some(instance), + } + } else { + None + }; + + let extra_args = &args[fn_sig.inputs().len()..]; + let extra_args = extra_args + .iter() + .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))) + .collect::<Vec<_>>(); + let fn_abi = if let Some(instance) = instance { + FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args) + } else { + FnAbi::of_fn_ptr( + &RevealAllLayoutCx(fx.tcx), + fn_ty.fn_sig(fx.tcx), + &extra_args, + ) + }; + match fn_abi.ret.mode { + PassMode::Ignore | PassMode::Direct(_) | PassMode::Pair(_, _) => true, // FIXME Make it possible to return Cast and Indirect to an ssa var. - RustcPassMode::Cast(_) | RustcPassMode::Indirect { .. } => false, + PassMode::Cast(_) | PassMode::Indirect { .. } => false, } } @@ -28,30 +62,39 @@ pub(super) fn codegen_return_param<'tcx>( ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>, start_block: Block, ) -> CPlace<'tcx> { - let ret_layout = return_layout(fx); - let ret_arg_abi = get_arg_abi(fx.tcx, ret_layout); - let (ret_place, ret_param) = match ret_arg_abi.mode { - RustcPassMode::Ignore => (CPlace::no_place(ret_layout), Empty), - RustcPassMode::Direct(_) | RustcPassMode::Pair(_, _) => { + let (ret_place, ret_param) = match fx.fn_abi.as_ref().unwrap().ret.mode { + PassMode::Ignore => ( + CPlace::no_place(fx.fn_abi.as_ref().unwrap().ret.layout), + Empty, + ), + PassMode::Direct(_) | PassMode::Pair(_, _) => { let is_ssa = ssa_analyzed[RETURN_PLACE] == crate::analyze::SsaKind::Ssa; ( - super::make_local_place(fx, RETURN_PLACE, ret_layout, is_ssa), + super::make_local_place( + fx, + RETURN_PLACE, + fx.fn_abi.as_ref().unwrap().ret.layout, + is_ssa, + ), Empty, ) } - RustcPassMode::Cast(_) - | RustcPassMode::Indirect { + PassMode::Cast(_) + | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _, } => { let ret_param = fx.bcx.append_block_param(start_block, fx.pointer_type); ( - CPlace::for_ptr(Pointer::new(ret_param), ret_layout), + CPlace::for_ptr( + Pointer::new(ret_param), + fx.fn_abi.as_ref().unwrap().ret.layout, + ), Single(ret_param), ) } - RustcPassMode::Indirect { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _, @@ -68,7 +111,8 @@ pub(super) fn codegen_return_param<'tcx>( Some(RETURN_PLACE), None, ret_param, - &ret_arg_abi, + fx.fn_abi.as_ref().unwrap().ret.mode, + fx.fn_abi.as_ref().unwrap().ret.layout, ); ret_place @@ -78,17 +122,14 @@ pub(super) fn codegen_return_param<'tcx>( /// returns the call return value(s) if any are written to the correct place. pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>( fx: &mut FunctionCx<'_, 'tcx, M>, - fn_sig: FnSig<'tcx>, + ret_arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, ret_place: Option<CPlace<'tcx>>, f: impl FnOnce(&mut FunctionCx<'_, 'tcx, M>, Option<Value>) -> (Inst, T), ) -> (Inst, T) { - let ret_layout = fx.layout_of(fn_sig.output()); - - let output_arg_abi = get_arg_abi(fx.tcx, ret_layout); - let return_ptr = match output_arg_abi.mode { - RustcPassMode::Ignore => None, - RustcPassMode::Cast(_) - | RustcPassMode::Indirect { + let return_ptr = match ret_arg_abi.mode { + PassMode::Ignore => None, + PassMode::Cast(_) + | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _, @@ -96,38 +137,41 @@ pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>( Some(ret_place) => Some(ret_place.to_ptr().get_addr(fx)), None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)), // FIXME allocate temp stack slot }, - RustcPassMode::Indirect { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _, } => unreachable!("unsized return value"), - RustcPassMode::Direct(_) | RustcPassMode::Pair(_, _) => None, + PassMode::Direct(_) | PassMode::Pair(_, _) => None, }; let (call_inst, meta) = f(fx, return_ptr); - match output_arg_abi.mode { - RustcPassMode::Ignore => {} - RustcPassMode::Direct(_) => { + match ret_arg_abi.mode { + PassMode::Ignore => {} + PassMode::Direct(_) => { if let Some(ret_place) = ret_place { let ret_val = fx.bcx.inst_results(call_inst)[0]; - ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_layout)); + ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_arg_abi.layout)); } } - RustcPassMode::Pair(_, _) => { + PassMode::Pair(_, _) => { if let Some(ret_place) = ret_place { let ret_val_a = fx.bcx.inst_results(call_inst)[0]; let ret_val_b = fx.bcx.inst_results(call_inst)[1]; - ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout)); + ret_place.write_cvalue( + fx, + CValue::by_val_pair(ret_val_a, ret_val_b, ret_arg_abi.layout), + ); } } - RustcPassMode::Cast(_) - | RustcPassMode::Indirect { + PassMode::Cast(_) + | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _, } => {} - RustcPassMode::Indirect { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _, @@ -139,27 +183,27 @@ pub(super) fn codegen_with_call_return_arg<'tcx, M: Module, T>( /// Codegen a return instruction with the right return value(s) if any. pub(crate) fn codegen_return(fx: &mut FunctionCx<'_, '_, impl Module>) { - match get_arg_abi(fx.tcx, return_layout(fx)).mode { - RustcPassMode::Ignore - | RustcPassMode::Cast(_) - | RustcPassMode::Indirect { + match fx.fn_abi.as_ref().unwrap().ret.mode { + PassMode::Ignore + | PassMode::Cast(_) + | PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _, } => { fx.bcx.ins().return_(&[]); } - RustcPassMode::Indirect { + PassMode::Indirect { attrs: _, extra_attrs: Some(_), on_stack: _, } => unreachable!("unsized return value"), - RustcPassMode::Direct(_) => { + PassMode::Direct(_) => { let place = fx.get_local_place(RETURN_PLACE); let ret_val = place.to_cvalue(fx).load_scalar(fx); fx.bcx.ins().return_(&[ret_val]); } - RustcPassMode::Pair(_, _) => { + PassMode::Pair(_, _) => { let place = fx.get_local_place(RETURN_PLACE); let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx); fx.bcx.ins().return_(&[ret_val_a, ret_val_b]); diff --git a/src/analyze.rs b/src/analyze.rs index adf5c7ac4fe..dc5e8a7e304 100644 --- a/src/analyze.rs +++ b/src/analyze.rs @@ -40,11 +40,9 @@ pub(crate) fn analyze(fx: &FunctionCx<'_, '_, impl Module>) -> IndexVec<Local, S } match &bb.terminator().kind { - TerminatorKind::Call { destination, .. } => { + TerminatorKind::Call { destination, func, args, .. } => { if let Some((dest_place, _dest_bb)) = destination { - let dest_layout = fx - .layout_of(fx.monomorphize(&dest_place.ty(&fx.mir.local_decls, fx.tcx).ty)); - if !crate::abi::can_return_to_ssa_var(fx.tcx, dest_layout) { + if !crate::abi::can_return_to_ssa_var(fx, func, args) { not_ssa(&mut flag_map, dest_place.local) } } diff --git a/src/base.rs b/src/base.rs index 1fafc121597..1eff0d4f516 100644 --- a/src/base.rs +++ b/src/base.rs @@ -2,6 +2,8 @@ use rustc_index::vec::IndexVec; use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::layout::FnAbiExt; +use rustc_target::abi::call::FnAbi; use crate::prelude::*; @@ -51,6 +53,7 @@ pub(crate) fn codegen_fn<'tcx>( instance, mir, + fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])), bcx, block_map, diff --git a/src/common.rs b/src/common.rs index 1485d4451b8..fbee84e09f7 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,4 +1,5 @@ use rustc_index::vec::IndexVec; +use rustc_target::abi::call::FnAbi; use rustc_target::abi::{Integer, Primitive}; use rustc_target::spec::{HasTargetSpec, Target}; @@ -294,6 +295,7 @@ pub(crate) struct FunctionCx<'clif, 'tcx, M: Module> { pub(crate) instance: Instance<'tcx>, pub(crate) mir: &'tcx Body<'tcx>, + pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>, pub(crate) bcx: FunctionBuilder<'clif>, pub(crate) block_map: IndexVec<BasicBlock, Block>, @@ -319,16 +321,7 @@ impl<'tcx, M: Module> LayoutOf for FunctionCx<'_, 'tcx, M> { type TyAndLayout = TyAndLayout<'tcx>; fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { - assert!(!ty.still_further_specializable()); - self.tcx - .layout_of(ParamEnv::reveal_all().and(&ty)) - .unwrap_or_else(|e| { - if let layout::LayoutError::SizeOverflow(_) = e { - self.tcx.sess.fatal(&e.to_string()) - } else { - bug!("failed to get layout for `{}`: {}", ty, e) - } - }) + RevealAllLayoutCx(self.tcx).layout_of(ty) } } @@ -442,3 +435,47 @@ impl<'tcx, M: Module> FunctionCx<'_, 'tcx, M> { self.bcx.ins().global_value(self.pointer_type, local_msg_id) } } + +pub(crate) struct RevealAllLayoutCx<'tcx>(pub(crate) TyCtxt<'tcx>); + +impl<'tcx> LayoutOf for RevealAllLayoutCx<'tcx> { + type Ty = Ty<'tcx>; + type TyAndLayout = TyAndLayout<'tcx>; + + fn layout_of(&self, ty: Ty<'tcx>) -> TyAndLayout<'tcx> { + assert!(!ty.still_further_specializable()); + self.0 + .layout_of(ParamEnv::reveal_all().and(&ty)) + .unwrap_or_else(|e| { + if let layout::LayoutError::SizeOverflow(_) = e { + self.0.sess.fatal(&e.to_string()) + } else { + bug!("failed to get layout for `{}`: {}", ty, e) + } + }) + } +} + +impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.0 + } +} + +impl<'tcx> rustc_target::abi::HasDataLayout for RevealAllLayoutCx<'tcx> { + fn data_layout(&self) -> &rustc_target::abi::TargetDataLayout { + &self.0.data_layout + } +} + +impl<'tcx> layout::HasParamEnv<'tcx> for RevealAllLayoutCx<'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + ParamEnv::reveal_all() + } +} + +impl<'tcx> HasTargetSpec for RevealAllLayoutCx<'tcx> { + fn target_spec(&self) -> &Target { + &self.0.sess.target + } +} diff --git a/src/lib.rs b/src/lib.rs index 9b5b7d8051c..ed7ee3b5365 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,7 +90,7 @@ mod prelude { pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{self, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FnSig, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable, + self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt, TypeAndMut, TypeFoldable, }; pub(crate) use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx}; diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 5bcb11fd515..17cb09d5587 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -450,64 +450,6 @@ impl<'tcx> CPlace<'tcx> { fx: &mut FunctionCx<'_, 'tcx, impl Module>, from: CValue<'tcx>, ) { - fn assert_assignable<'tcx>( - fx: &FunctionCx<'_, 'tcx, impl Module>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, - ) { - match (from_ty.kind(), to_ty.kind()) { - (ty::Ref(_, a, _), ty::Ref(_, b, _)) - | ( - ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), - ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }), - ) => { - assert_assignable(fx, a, b); - } - (ty::FnPtr(_), ty::FnPtr(_)) => { - let from_sig = fx.tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - from_ty.fn_sig(fx.tcx), - ); - let to_sig = fx.tcx.normalize_erasing_late_bound_regions( - ParamEnv::reveal_all(), - to_ty.fn_sig(fx.tcx), - ); - assert_eq!( - from_sig, to_sig, - "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}", - from_sig, to_sig, fx, - ); - // fn(&T) -> for<'l> fn(&'l T) is allowed - } - (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { - for (from, to) in from_traits.iter().zip(to_traits) { - let from = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); - let to = fx - .tcx - .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); - assert_eq!( - from, to, - "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", - from_traits, to_traits, fx, - ); - } - // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed - } - _ => { - assert_eq!( - from_ty, - to_ty, - "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}", - from_ty, - to_ty, - fx, - ); - } - } - } - assert_assignable(fx, from.layout().ty, self.layout().ty); self.write_cvalue_maybe_transmute(fx, from, "write_cvalue"); @@ -794,3 +736,62 @@ impl<'tcx> CPlace<'tcx> { } } } + +#[track_caller] +pub(crate) fn assert_assignable<'tcx>( + fx: &FunctionCx<'_, 'tcx, impl Module>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) { + match (from_ty.kind(), to_ty.kind()) { + (ty::Ref(_, a, _), ty::Ref(_, b, _)) + | ( + ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), + ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }), + ) => { + assert_assignable(fx, a, b); + } + (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ })) + | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => { + assert_assignable(fx, a, b); + } + (ty::FnPtr(_), ty::FnPtr(_)) => { + let from_sig = fx.tcx.normalize_erasing_late_bound_regions( + ParamEnv::reveal_all(), + from_ty.fn_sig(fx.tcx), + ); + let to_sig = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to_ty.fn_sig(fx.tcx)); + assert_eq!( + from_sig, to_sig, + "Can't write fn ptr with incompatible sig {:?} to place with sig {:?}\n\n{:#?}", + from_sig, to_sig, fx, + ); + // fn(&T) -> for<'l> fn(&'l T) is allowed + } + (&ty::Dynamic(from_traits, _), &ty::Dynamic(to_traits, _)) => { + for (from, to) in from_traits.iter().zip(to_traits) { + let from = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), from); + let to = fx + .tcx + .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), to); + assert_eq!( + from, to, + "Can't write trait object of incompatible traits {:?} to place with traits {:?}\n\n{:#?}", + from_traits, to_traits, fx, + ); + } + // dyn for<'r> Trait<'r> -> dyn Trait<'_> is allowed + } + _ => { + assert_eq!( + from_ty, to_ty, + "Can't write value with incompatible type {:?} to place with type {:?}\n\n{:#?}", + from_ty, to_ty, fx, + ); + } + } +} |
