Auto merge of #88575 - eddyb:fn-abi-queries, r=nagisa

Querify `FnAbi::of_{fn_ptr,instance}` as `fn_abi_of_{fn_ptr,instance}`.

*Note: opening this PR as draft because it's based on #88499*

This more or less replicates the `LayoutOf::layout_of` setup from #88499, to replace `FnAbi::of_{fn_ptr,instance}` with `FnAbiOf::fn_abi_of_{fn_ptr,instance}`, and also route them through queries (which `layout_of` has used for a while).

The two changes at the use sites (other than the names) are:
* return type is now wrapped in `&'tcx`
  * the value *is* interned, which may affect performance
* the `extra_args` list is now an interned `&'tcx ty::List<Ty<'tcx>>`
  * should be cheap (it's empty for anything other than C variadics)

Theoretically, a `FnAbiOfHelpers` implementer could choose to keep the `Result<...>` instead of eagerly erroring, but the only existing users of these APIs are codegen backends, so they don't (want to) take advantage of this.
At least miri could make use of this, since it prefers propagating errors (it "just" doesn't use `FnAbi` yet - cc `@RalfJung).`

The way this is done is probably less efficient than what is possible, because the queries handle the correctness-oriented API (i.e. the split into `fn` pointers vs instances), whereas a lower-level query could end up with more reuse between different instances with identical signatures.

r? `@nagisa` cc `@oli-obk` `@bjorn3`
This commit is contained in:
bors 2021-09-19 21:39:47 +00:00
commit 91198820d7
23 changed files with 508 additions and 244 deletions

View file

@ -5,7 +5,7 @@ mod pass_mode;
mod returning;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::ty::layout::FnAbiExt;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_target::abi::call::{Conv, FnAbi};
use rustc_target::spec::abi::Abi;
@ -53,7 +53,11 @@ pub(crate) fn get_function_sig<'tcx>(
inst: Instance<'tcx>,
) -> Signature {
assert!(!inst.substs.needs_infer());
clif_sig_from_fn_abi(tcx, triple, &FnAbi::of_instance(&RevealAllLayoutCx(tcx), inst, &[]))
clif_sig_from_fn_abi(
tcx,
triple,
&RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
)
}
/// Instance must be monomorphized
@ -350,14 +354,13 @@ pub(crate) fn codegen_terminator_call<'tcx>(
};
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 extra_args = fx
.tcx
.mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
let fn_abi = if let Some(instance) = instance {
FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), instance, &extra_args)
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
} else {
FnAbi::of_fn_ptr(&RevealAllLayoutCx(fx.tcx), fn_ty.fn_sig(fx.tcx), &extra_args)
RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
};
let is_cold = instance
@ -525,7 +528,8 @@ pub(crate) fn codegen_drop<'tcx>(
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 fn_abi =
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi);
let sig = fx.bcx.import_signature(sig);
@ -534,7 +538,8 @@ pub(crate) fn codegen_drop<'tcx>(
_ => {
assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
let fn_abi = FnAbi::of_instance(&RevealAllLayoutCx(fx.tcx), drop_instance, &[]);
let fn_abi =
RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
let arg_value = drop_place.place_ref(
fx,

View file

@ -3,8 +3,7 @@
use cranelift_codegen::binemit::{NullStackMapSink, NullTrapSink};
use rustc_index::vec::IndexVec;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::FnAbiExt;
use rustc_target::abi::call::FnAbi;
use rustc_middle::ty::layout::FnAbiOf;
use crate::constant::ConstantCx;
use crate::prelude::*;
@ -62,7 +61,7 @@ pub(crate) fn codegen_fn<'tcx>(
instance,
symbol_name,
mir,
fn_abi: Some(FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())),
bcx,
block_map,

View file

@ -1,5 +1,7 @@
use rustc_index::vec::IndexVec;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers};
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
};
use rustc_middle::ty::SymbolName;
use rustc_target::abi::call::FnAbi;
use rustc_target::abi::{Integer, Primitive};
@ -239,7 +241,7 @@ pub(crate) struct FunctionCx<'m, 'clif, 'tcx: 'm> {
pub(crate) instance: Instance<'tcx>,
pub(crate) symbol_name: SymbolName<'tcx>,
pub(crate) mir: &'tcx Body<'tcx>,
pub(crate) fn_abi: Option<FnAbi<'tcx, Ty<'tcx>>>,
pub(crate) fn_abi: Option<&'tcx FnAbi<'tcx, Ty<'tcx>>>,
pub(crate) bcx: FunctionBuilder<'clif>,
pub(crate) block_map: IndexVec<BasicBlock, Block>,
@ -266,6 +268,20 @@ impl<'tcx> LayoutOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
}
}
impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
#[inline]
fn handle_fn_abi_err(
&self,
err: FnAbiError<'tcx>,
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
}
}
impl<'tcx> layout::HasTyCtxt<'tcx> for FunctionCx<'_, '_, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.tcx
@ -378,6 +394,43 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
}
}
impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
#[inline]
fn handle_fn_abi_err(
&self,
err: FnAbiError<'tcx>,
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
self.0.sess.span_fatal(span, &err.to_string())
} else {
match fn_abi_request {
FnAbiRequest::OfFnPtr { sig, extra_args } => {
span_bug!(
span,
"`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
sig,
extra_args,
err
);
}
FnAbiRequest::OfInstance { instance, extra_args } => {
span_bug!(
span,
"`fn_abi_of_instance({}, {:?})` failed: {}",
instance,
extra_args,
err
);
}
}
}
}
}
impl<'tcx> layout::HasTyCtxt<'tcx> for RevealAllLayoutCx<'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
self.0

View file

@ -129,9 +129,7 @@ pub(crate) fn codegen_constant<'tcx>(
};
let const_val = match const_.val {
ConstKind::Value(const_val) => const_val,
ConstKind::Unevaluated(uv)
if fx.tcx.is_static(uv.def.did) =>
{
ConstKind::Unevaluated(uv) if fx.tcx.is_static(uv.def.did) => {
assert!(uv.substs(fx.tcx).is_empty());
assert!(uv.promoted.is_none());

View file

@ -61,9 +61,8 @@ use cranelift_codegen::{
write::{FuncWriter, PlainWriter},
};
use rustc_middle::ty::layout::FnAbiExt;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_session::config::OutputType;
use rustc_target::abi::call::FnAbi;
use crate::prelude::*;
@ -81,7 +80,10 @@ impl CommentWriter {
vec![
format!("symbol {}", tcx.symbol_name(instance).name),
format!("instance {:?}", instance),
format!("abi {:?}", FnAbi::of_instance(&RevealAllLayoutCx(tcx), instance, &[])),
format!(
"abi {:?}",
RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())
),
String::new(),
]
} else {

View file

@ -15,10 +15,12 @@ use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::MemFlags;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
use rustc_target::abi::{self, Align, Size, WrappingRange};
use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
use rustc_target::spec::{HasTargetSpec, Target};
use std::borrow::Cow;
use std::ffi::CStr;
@ -97,6 +99,20 @@ impl LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
}
}
impl FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
#[inline]
fn handle_fn_abi_err(
&self,
err: FnAbiError<'tcx>,
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
self.cx.handle_fn_abi_err(err, span, fn_abi_request)
}
}
impl Deref for Builder<'_, 'll, 'tcx> {
type Target = CodegenCx<'ll, 'tcx>;

View file

@ -4,7 +4,7 @@
//! and methods are represented as just a fn ptr and not a full
//! closure.
use crate::abi::{FnAbi, FnAbiLlvmExt};
use crate::abi::FnAbiLlvmExt;
use crate::attributes;
use crate::context::CodegenCx;
use crate::llvm;
@ -12,7 +12,7 @@ use crate::value::Value;
use rustc_codegen_ssa::traits::*;
use tracing::debug;
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
use rustc_middle::ty::{self, Instance, TypeFoldable};
/// Codegens a reference to a fn/method item, monomorphizing and
@ -42,7 +42,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
sym
);
let fn_abi = FnAbi::of_instance(cx, instance, &[]);
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
let llfn = if let Some(llfn) = cx.get_declared_value(&sym) {
// Create a fn pointer with the new signature.

View file

@ -15,14 +15,19 @@ use rustc_data_structures::base_n;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_middle::mir::mono::CodegenUnit;
use rustc_middle::ty::layout::{HasParamEnv, LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, LayoutError, LayoutOfHelpers,
TyAndLayout,
};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CFGuard, CrateType, DebugInfo};
use rustc_session::Session;
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_target::abi::{
call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx,
};
use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel};
use smallvec::SmallVec;
@ -835,6 +840,12 @@ impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
ty::ParamEnv::reveal_all()
}
}
impl LayoutOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
type LayoutOfResult = TyAndLayout<'tcx>;
@ -848,8 +859,39 @@ impl LayoutOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> {
fn param_env(&self) -> ty::ParamEnv<'tcx> {
ty::ParamEnv::reveal_all()
impl FnAbiOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
#[inline]
fn handle_fn_abi_err(
&self,
err: FnAbiError<'tcx>,
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
self.sess().span_fatal(span, &err.to_string())
} else {
match fn_abi_request {
FnAbiRequest::OfFnPtr { sig, extra_args } => {
span_bug!(
span,
"`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
sig,
extra_args,
err
);
}
FnAbiRequest::OfInstance { instance, extra_args } => {
span_bug!(
span,
"`fn_abi_of_instance({}, {:?})` failed: {}",
instance,
extra_args,
err
);
}
}
}
}
}

View file

@ -1,6 +1,6 @@
use crate::llvm;
use crate::abi::{Abi, FnAbi};
use crate::abi::Abi;
use crate::builder::Builder;
use crate::common::CodegenCx;
@ -20,7 +20,7 @@ use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
};
use rustc_middle::ty;
use rustc_middle::ty::layout::FnAbiExt;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::Instance;
@ -200,8 +200,7 @@ fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx
let llfn = cx.declare_fn(
&tcx.symbol_name(instance).name,
&FnAbi::of_fn_ptr(
cx,
&cx.fn_abi_of_fn_ptr(
ty::Binder::dummy(tcx.mk_fn_sig(
iter::once(tcx.mk_unit()),
tcx.mk_unit(),
@ -209,7 +208,7 @@ fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx
hir::Unsafety::Unsafe,
Abi::Rust,
)),
&[],
ty::List::empty(),
),
);

View file

@ -3,12 +3,11 @@ use super::utils::DIB;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
use rustc_codegen_ssa::traits::*;
use crate::abi::FnAbi;
use crate::common::CodegenCx;
use crate::llvm;
use crate::llvm::debuginfo::{DILocation, DIScope};
use rustc_middle::mir::{Body, SourceScope};
use rustc_middle::ty::layout::FnAbiExt;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::{self, Instance};
use rustc_session::config::DebugInfo;
@ -94,7 +93,7 @@ fn make_mir_scope(
ty::ParamEnv::reveal_all(),
callee,
);
let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]);
let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
cx.dbg_scope_fn(callee, &callee_fn_abi, None)
}
None => unsafe {

View file

@ -15,7 +15,7 @@ use rustc_codegen_ssa::mir::operand::OperandRef;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
use rustc_hir as hir;
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, LayoutOf};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
use rustc_middle::ty::{self, Ty};
use rustc_middle::{bug, span_bug};
use rustc_span::{sym, symbol::kw, Span, Symbol};
@ -737,7 +737,7 @@ fn gen_fn<'ll, 'tcx>(
rust_fn_sig: ty::PolyFnSig<'tcx>,
codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
) -> (&'ll Type, &'ll Value) {
let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
let llty = fn_abi.llvm_type(cx);
let llfn = cx.declare_fn(name, &fn_abi);
cx.set_frame_pointer_type(llfn);

View file

@ -1,4 +1,3 @@
use crate::abi::FnAbi;
use crate::attributes;
use crate::base;
use crate::context::CodegenCx;
@ -8,7 +7,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
pub use rustc_middle::mir::mono::MonoItem;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::layout::{FnAbiExt, LayoutOf};
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
use rustc_middle::ty::{self, Instance, TypeFoldable};
use rustc_session::config::CrateType;
use rustc_target::spec::RelocModel;
@ -53,7 +52,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
) {
assert!(!instance.substs.needs_infer());
let fn_abi = FnAbi::of_instance(self, instance, &[]);
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
let lldecl = self.declare_fn(symbol_name, &fn_abi);
unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());

View file

@ -1,10 +1,9 @@
use crate::abi::FnAbi;
use crate::common::*;
use crate::context::TypeLowering;
use crate::type_::Type;
use rustc_codegen_ssa::traits::*;
use rustc_middle::bug;
use rustc_middle::ty::layout::{FnAbiExt, LayoutOf, TyAndLayout};
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Ty, TypeFoldable};
use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
@ -231,7 +230,9 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
ty::Adt(def, _) if def.is_box() => {
cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx))
}
ty::FnPtr(sig) => cx.fn_ptr_backend_type(&FnAbi::of_fn_ptr(cx, sig, &[])),
ty::FnPtr(sig) => {
cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty()))
}
_ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO),
};
cx.scalar_lltypes.borrow_mut().insert(self.ty, llty);

View file

@ -14,7 +14,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_index::vec::Idx;
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::{self, SwitchTargets};
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, LayoutOf};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_span::source_map::Span;
@ -124,7 +124,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
&self,
fx: &mut FunctionCx<'a, 'tcx, Bx>,
bx: &mut Bx,
fn_abi: FnAbi<'tcx, Ty<'tcx>>,
fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
fn_ptr: Bx::Value,
llargs: &[Bx::Value],
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
@ -337,7 +337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
substs: drop_fn.substs,
};
let fn_abi = FnAbi::of_instance(&bx, virtual_drop, &[]);
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
let vtable = args[1];
args = &args[..1];
(
@ -346,7 +346,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn_abi,
)
}
_ => (bx.get_fn_addr(drop_fn), FnAbi::of_instance(&bx, drop_fn, &[])),
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
};
helper.do_call(
self,
@ -433,7 +433,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Obtain the panic entry point.
let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
let instance = ty::Instance::mono(bx.tcx(), def_id);
let fn_abi = FnAbi::of_instance(&bx, instance, &[]);
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
let llfn = bx.get_fn_addr(instance);
// Codegen the actual panic invoke/call.
@ -494,7 +494,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let def_id =
common::langcall(bx.tcx(), Some(source_info.span), "", LangItem::Panic);
let instance = ty::Instance::mono(bx.tcx(), def_id);
let fn_abi = FnAbi::of_instance(bx, instance, &[]);
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
let llfn = bx.get_fn_addr(instance);
// Codegen the actual panic invoke/call.
@ -570,17 +570,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
};
let extra_args = &args[sig.inputs().skip_binder().len()..];
let extra_args = extra_args
.iter()
.map(|op_arg| {
let op_ty = op_arg.ty(self.mir, bx.tcx());
self.monomorphize(op_ty)
})
.collect::<Vec<_>>();
let extra_args = bx.tcx().mk_type_list(extra_args.iter().map(|op_arg| {
let op_ty = op_arg.ty(self.mir, bx.tcx());
self.monomorphize(op_ty)
}));
let fn_abi = match instance {
Some(instance) => FnAbi::of_instance(&bx, instance, &extra_args),
None => FnAbi::of_fn_ptr(&bx, sig, &extra_args),
Some(instance) => bx.fn_abi_of_instance(instance, extra_args),
None => bx.fn_abi_of_fn_ptr(sig, extra_args),
};
if intrinsic == Some(sym::transmute) {

View file

@ -2,7 +2,7 @@ use crate::traits::*;
use rustc_errors::ErrorReported;
use rustc_middle::mir;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_target::abi::call::{FnAbi, PassMode};
@ -29,7 +29,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
cx: &'a Bx::CodegenCx,
fn_abi: FnAbi<'tcx, Ty<'tcx>>,
fn_abi: &'tcx FnAbi<'tcx, Ty<'tcx>>,
/// When unwinding is initiated, we have to store this personality
/// value somewhere so that we can load it and re-use it in the
@ -139,7 +139,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let mir = cx.tcx().instance_mir(instance.def);
let fn_abi = FnAbi::of_instance(cx, instance, &[]);
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
debug!("fn_abi: {:?}", fn_abi);
let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir);

View file

@ -8,14 +8,15 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorReported;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_session::{
config::{self, OutputFilenames, PrintRequest},
Session,
};
use rustc_span::symbol::Symbol;
use rustc_target::abi::call::FnAbi;
use rustc_target::spec::Target;
pub use rustc_data_structures::sync::MetadataRef;
@ -38,12 +39,19 @@ pub trait BackendTypes {
}
pub trait Backend<'tcx>:
Sized + BackendTypes + HasTyCtxt<'tcx> + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
Sized
+ BackendTypes
+ HasTyCtxt<'tcx>
+ LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
+ FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
{
}
impl<'tcx, T> Backend<'tcx> for T where
Self: BackendTypes + HasTyCtxt<'tcx> + LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
Self: BackendTypes
+ HasTyCtxt<'tcx>
+ LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>>
+ FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>>
{
}

View file

@ -11,7 +11,8 @@
macro_rules! arena_types {
($macro:path, $tcx:lifetime) => (
$macro!([
[] layouts: rustc_target::abi::Layout,
[] layout: rustc_target::abi::Layout,
[] fn_abi: rustc_target::abi::call::FnAbi<$tcx, rustc_middle::ty::Ty<$tcx>>,
// AdtDef are interned and compared by address
[] adt_def: rustc_middle::ty::AdtDef,
[] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<$tcx>>,

View file

@ -1128,6 +1128,27 @@ rustc_queries! {
desc { "computing layout of `{}`", key.value }
}
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
///
/// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
/// instead, where the instance is an `InstanceDef::Virtual`.
query fn_abi_of_fn_ptr(
key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}` function pointers", key.value.0 }
}
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
/// direct calls to an `fn`.
///
/// NB: that includes virtual calls, which are represented by "direct calls"
/// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
query fn_abi_of_instance(
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}`", key.value.0 }
}
query dylib_dependency_formats(_: CrateNum)
-> &'tcx [(CrateNum, LinkagePreference)] {
desc { "dylib dependency formats of crate" }

View file

@ -102,8 +102,8 @@ pub struct CtxtInterners<'tcx> {
/// The arena that types, regions, etc. are allocated from.
arena: &'tcx WorkerLocal<Arena<'tcx>>,
/// Specifically use a speedy hash algorithm for these hash sets, since
/// they're accessed quite often.
// Specifically use a speedy hash algorithm for these hash sets, since
// they're accessed quite often.
type_: InternedSet<'tcx, TyS<'tcx>>,
type_list: InternedSet<'tcx, List<Ty<'tcx>>>,
substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
@ -116,9 +116,9 @@ pub struct CtxtInterners<'tcx> {
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
const_: InternedSet<'tcx, Const<'tcx>>,
/// Const allocations.
allocation: InternedSet<'tcx, Allocation>,
const_allocation: InternedSet<'tcx, Allocation>,
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
layout: InternedSet<'tcx, Layout>,
}
impl<'tcx> CtxtInterners<'tcx> {
@ -136,8 +136,9 @@ impl<'tcx> CtxtInterners<'tcx> {
projs: Default::default(),
place_elems: Default::default(),
const_: Default::default(),
allocation: Default::default(),
const_allocation: Default::default(),
bound_variable_kinds: Default::default(),
layout: Default::default(),
}
}
@ -1046,10 +1047,9 @@ pub struct GlobalCtxt<'tcx> {
/// Stores memory for globals (statics/consts).
pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
layout_interner: ShardedHashMap<&'tcx Layout, ()>,
output_filenames: Arc<OutputFilenames>,
// FIXME(eddyb) this doesn't belong here and should be using a query.
pub(super) vtables_cache:
Lock<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), AllocId>>,
}
@ -1091,13 +1091,6 @@ impl<'tcx> TyCtxt<'tcx> {
self.arena.alloc(ty::AdtDef::new(self, did, kind, variants, repr))
}
pub fn intern_const_alloc(self, alloc: Allocation) -> &'tcx Allocation {
self.interners
.allocation
.intern(alloc, |alloc| Interned(self.interners.arena.alloc(alloc)))
.0
}
/// Allocates a read-only byte or string literal for `mir::interpret`.
pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
// Create an allocation that just contains these bytes.
@ -1106,20 +1099,19 @@ impl<'tcx> TyCtxt<'tcx> {
self.create_memory_alloc(alloc)
}
// FIXME(eddyb) move to `direct_interners!`.
pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
self.stability_interner.intern(stab, |stab| self.arena.alloc(stab))
}
// FIXME(eddyb) move to `direct_interners!`.
pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab))
}
pub fn intern_layout(self, layout: Layout) -> &'tcx Layout {
self.layout_interner.intern(layout, |layout| self.arena.alloc(layout))
}
/// Returns a range of the start/end indices specified with the
/// `rustc_layout_scalar_valid_range` attribute.
// FIXME(eddyb) this is an awkward spot for this method, maybe move it?
pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
let attrs = self.get_attrs(def_id);
let get = |name| {
@ -1194,7 +1186,6 @@ impl<'tcx> TyCtxt<'tcx> {
evaluation_cache: Default::default(),
crate_name: Symbol::intern(crate_name),
data_layout,
layout_interner: Default::default(),
stability_interner: Default::default(),
const_stability_interner: Default::default(),
alloc_map: Lock::new(interpret::AllocMap::new()),
@ -1665,7 +1656,7 @@ macro_rules! nop_list_lift {
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
nop_lift! {allocation; &'a Allocation => &'tcx Allocation}
nop_lift! {const_allocation; &'a Allocation => &'tcx Allocation}
nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}
nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
@ -1957,8 +1948,12 @@ impl<'tcx> TyCtxt<'tcx> {
"Const Stability interner: #{}",
self.0.const_stability_interner.len()
)?;
writeln!(fmt, "Allocation interner: #{}", self.0.interners.allocation.len())?;
writeln!(fmt, "Layout interner: #{}", self.0.layout_interner.len())?;
writeln!(
fmt,
"Const Allocation interner: #{}",
self.0.interners.const_allocation.len()
)?;
writeln!(fmt, "Layout interner: #{}", self.0.interners.layout.len())?;
Ok(())
}
@ -2046,38 +2041,6 @@ impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
}
}
impl<'tcx> Borrow<RegionKind> for Interned<'tcx, RegionKind> {
fn borrow(&self) -> &RegionKind {
&self.0
}
}
impl<'tcx> Borrow<Const<'tcx>> for Interned<'tcx, Const<'tcx>> {
fn borrow<'a>(&'a self) -> &'a Const<'tcx> {
&self.0
}
}
impl<'tcx> Borrow<Allocation> for Interned<'tcx, Allocation> {
fn borrow<'a>(&'a self) -> &'a Allocation {
&self.0
}
}
impl<'tcx> PartialEq for Interned<'tcx, Allocation> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<'tcx> Eq for Interned<'tcx, Allocation> {}
impl<'tcx> Hash for Interned<'tcx, Allocation> {
fn hash<H: Hasher>(&self, s: &mut H) {
self.0.hash(s)
}
}
macro_rules! direct_interners {
($($name:ident: $method:ident($ty:ty),)+) => {
$(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
@ -2094,9 +2057,15 @@ macro_rules! direct_interners {
}
}
impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
fn borrow<'a>(&'a self) -> &'a $ty {
&self.0
}
}
impl<'tcx> TyCtxt<'tcx> {
pub fn $method(self, v: $ty) -> &'tcx $ty {
self.interners.$name.intern_ref(&v, || {
self.interners.$name.intern(v, |v| {
Interned(self.interners.arena.alloc(v))
}).0
}
@ -2107,6 +2076,8 @@ macro_rules! direct_interners {
direct_interners! {
region: mk_region(RegionKind),
const_: mk_const(Const<'tcx>),
const_allocation: intern_const_alloc(Allocation),
layout: intern_layout(Layout),
}
macro_rules! slice_interners {

View file

@ -1,4 +1,3 @@
use crate::ich::StableHashingContext;
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
use crate::ty::subst::Subst;
@ -6,7 +5,6 @@ use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
use rustc_ast as ast;
use rustc_attr as attr;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::BitSet;
@ -18,15 +16,19 @@ use rustc_target::abi::call::{
ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
};
use rustc_target::abi::*;
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy};
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
use std::cmp;
use std::fmt;
use std::iter;
use std::mem;
use std::num::NonZeroUsize;
use std::ops::Bound;
pub fn provide(providers: &mut ty::query::Providers) {
*providers =
ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
}
pub trait IntegerExt {
fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer;
@ -191,7 +193,7 @@ pub const FAT_PTR_EXTRA: usize = 1;
/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)]
#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>),
@ -248,10 +250,6 @@ fn layout_of<'tcx>(
})
}
pub fn provide(providers: &mut ty::query::Providers) {
*providers = ty::query::Providers { layout_of, ..*providers };
}
pub struct LayoutCx<'tcx, C> {
pub tcx: C,
pub param_env: ty::ParamEnv<'tcx>,
@ -2015,6 +2013,12 @@ impl<'tcx> HasDataLayout for TyCtxt<'tcx> {
}
}
impl<'tcx> HasTargetSpec for TyCtxt<'tcx> {
fn target_spec(&self) -> &Target {
&self.sess.target
}
}
impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
@ -2029,6 +2033,12 @@ impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
}
}
impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
fn target_spec(&self) -> &Target {
&self.sess.target
}
}
impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
@ -2048,6 +2058,12 @@ impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
}
}
impl<'tcx, T: HasTargetSpec> HasTargetSpec for LayoutCx<'tcx, T> {
fn target_spec(&self) -> &Target {
self.tcx.target_spec()
}
}
impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx.tcx()
@ -2130,10 +2146,10 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
#[inline]
fn spanned_layout_of(&self, ty: Ty<'tcx>, span: Span) -> Self::LayoutOfResult {
let span = if !span.is_dummy() { span } else { self.layout_tcx_at_span() };
let tcx = self.tcx().at(span);
MaybeResult::from(
self.tcx()
.at(span)
.layout_of(self.param_env().and(ty))
tcx.layout_of(self.param_env().and(ty))
.map_err(|err| self.handle_layout_err(err, span, ty)),
)
}
@ -2519,24 +2535,12 @@ where
}
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> {
#[inline]
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
use crate::ty::layout::LayoutError::*;
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
Unknown(t) | SizeOverflow(t) => t.hash_stable(hcx, hasher),
}
}
}
impl<'tcx> ty::Instance<'tcx> {
// NOTE(eddyb) this is private to avoid using it from outside of
// `FnAbi::of_instance` - any other uses are either too high-level
// `fn_abi_of_instance` - any other uses are either too high-level
// for `Instance` (e.g. typeck would use `Ty::fn_sig` instead),
// or should go through `FnAbi` instead, to avoid losing any
// adjustments `FnAbi::of_instance` might be performing.
// adjustments `fn_abi_of_instance` might be performing.
fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
// FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function.
let ty = self.ty(tcx, ty::ParamEnv::reveal_all());
@ -2633,34 +2637,6 @@ impl<'tcx> ty::Instance<'tcx> {
}
}
pub trait FnAbiExt<'tcx, C>
where
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
{
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
///
/// NB: this doesn't handle virtual calls - those should use `FnAbi::of_instance`
/// instead, where the instance is an `InstanceDef::Virtual`.
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
/// direct calls to an `fn`.
///
/// NB: that includes virtual calls, which are represented by "direct calls"
/// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
fn new_internal(
cx: &C,
sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>],
caller_location: Option<Ty<'tcx>>,
codegen_fn_attr_flags: CodegenFnAttrFlags,
make_self_ptr_thin: bool,
) -> Self;
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
}
/// Calculates whether a function's ABI can unwind or not.
///
/// This takes two primary parameters:
@ -2816,48 +2792,175 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
}
}
impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>>
where
C: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + HasTargetSpec,
{
fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
call::FnAbi::new_internal(cx, sig, extra_args, None, CodegenFnAttrFlags::empty(), false)
/// Error produced by attempting to compute or adjust a `FnAbi`.
#[derive(Clone, Debug, HashStable)]
pub enum FnAbiError<'tcx> {
/// Error produced by a `layout_of` call, while computing `FnAbi` initially.
Layout(LayoutError<'tcx>),
/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
AdjustForForeignAbi(call::AdjustForForeignAbiError),
}
impl From<LayoutError<'tcx>> for FnAbiError<'tcx> {
fn from(err: LayoutError<'tcx>) -> Self {
Self::Layout(err)
}
}
impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
fn from(err: call::AdjustForForeignAbiError) -> Self {
Self::AdjustForForeignAbi(err)
}
}
impl<'tcx> fmt::Display for FnAbiError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Layout(err) => err.fmt(f),
Self::AdjustForForeignAbi(err) => err.fmt(f),
}
}
}
// FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
// just for error handling.
#[derive(Debug)]
pub enum FnAbiRequest<'tcx> {
OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
}
/// Trait for contexts that want to be able to compute `FnAbi`s.
/// This automatically gives access to `FnAbiOf`, through a blanket `impl`.
pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
/// The `&FnAbi`-wrapping type (or `&FnAbi` itself), which will be
/// returned from `fn_abi_of_*` (see also `handle_fn_abi_err`).
type FnAbiOfResult: MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>;
/// Helper used for `fn_abi_of_*`, to adapt `tcx.fn_abi_of_*(...)` into a
/// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
///
/// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
/// but this hook allows e.g. codegen to return only `&FnAbi` from its
/// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
/// (and any `FnAbiError`s are turned into fatal errors or ICEs).
fn handle_fn_abi_err(
&self,
err: FnAbiError<'tcx>,
span: Span,
fn_abi_request: FnAbiRequest<'tcx>,
) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
}
/// Blanket extension trait for contexts that can compute `FnAbi`s.
pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
///
/// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
/// instead, where the instance is an `InstanceDef::Virtual`.
#[inline]
fn fn_abi_of_fn_ptr(
&self,
sig: ty::PolyFnSig<'tcx>,
extra_args: &'tcx ty::List<Ty<'tcx>>,
) -> Self::FnAbiOfResult {
// FIXME(eddyb) get a better `span` here.
let span = self.layout_tcx_at_span();
let tcx = self.tcx().at(span);
MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
|err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
))
}
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
let sig = instance.fn_sig_for_fn_abi(cx.tcx());
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
/// direct calls to an `fn`.
///
/// NB: that includes virtual calls, which are represented by "direct calls"
/// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
#[inline]
fn fn_abi_of_instance(
&self,
instance: ty::Instance<'tcx>,
extra_args: &'tcx ty::List<Ty<'tcx>>,
) -> Self::FnAbiOfResult {
// FIXME(eddyb) get a better `span` here.
let span = self.layout_tcx_at_span();
let tcx = self.tcx().at(span);
let caller_location = if instance.def.requires_caller_location(cx.tcx()) {
Some(cx.tcx().caller_location_ty())
} else {
None
};
let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
call::FnAbi::new_internal(
cx,
sig,
extra_args,
caller_location,
attrs,
matches!(instance.def, ty::InstanceDef::Virtual(..)),
MaybeResult::from(
tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
// HACK(eddyb) at least for definitions of/calls to `Instance`s,
// we can get some kind of span even if one wasn't provided.
// However, we don't do this early in order to avoid calling
// `def_span` unconditionally (which may have a perf penalty).
let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
}),
)
}
}
fn new_internal(
cx: &C,
impl<C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
fn fn_abi_of_fn_ptr<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
let (param_env, (sig, extra_args)) = query.into_parts();
LayoutCx { tcx, param_env }.fn_abi_new_uncached(
sig,
extra_args,
None,
CodegenFnAttrFlags::empty(),
false,
)
}
fn fn_abi_of_instance<'tcx>(
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
let (param_env, (instance, extra_args)) = query.into_parts();
let sig = instance.fn_sig_for_fn_abi(tcx);
let caller_location = if instance.def.requires_caller_location(tcx) {
Some(tcx.caller_location_ty())
} else {
None
};
let attrs = tcx.codegen_fn_attrs(instance.def_id()).flags;
LayoutCx { tcx, param_env }.fn_abi_new_uncached(
sig,
extra_args,
caller_location,
attrs,
matches!(instance.def, ty::InstanceDef::Virtual(..)),
)
}
impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
// arguments of this method, into a separate `struct`.
fn fn_abi_new_uncached(
&self,
sig: ty::PolyFnSig<'tcx>,
extra_args: &[Ty<'tcx>],
caller_location: Option<Ty<'tcx>>,
codegen_fn_attr_flags: CodegenFnAttrFlags,
// FIXME(eddyb) replace this with something typed, like an `enum`.
force_thin_self_ptr: bool,
) -> Self {
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args);
let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig);
let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
let conv = conv_from_spec_abi(self.tcx(), sig.abi);
let mut inputs = sig.inputs();
let extra_args = if sig.abi == RustCall {
@ -2884,7 +2987,7 @@ where
extra_args.to_vec()
};
let target = &cx.tcx().sess.target;
let target = &self.tcx.sess.target;
let target_env_gnu_like = matches!(&target.env[..], "gnu" | "musl");
let win_x64_gnu = target.os == "windows" && target.arch == "x86_64" && target.env == "gnu";
let linux_s390x_gnu_like =
@ -2917,7 +3020,7 @@ where
attrs.set(ArgAttribute::NonNull);
}
if let Some(pointee) = layout.pointee_info_at(cx, offset) {
if let Some(pointee) = layout.pointee_info_at(self, offset) {
if let Some(kind) = pointee.safe {
attrs.pointee_align = Some(pointee.align);
@ -2961,20 +3064,20 @@ where
}
};
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
let is_return = arg_idx.is_none();
let layout = cx.layout_of(ty);
let layout = self.layout_of(ty)?;
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
// Don't pass the vtable, it's not an argument of the virtual fn.
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
// or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
make_thin_self_ptr(cx, layout)
make_thin_self_ptr(self, layout)
} else {
layout
};
let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| {
let mut arg = ArgAbi::new(self, layout, |layout, scalar, offset| {
let mut attrs = ArgAttributes::new();
adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
attrs
@ -2995,11 +3098,11 @@ where
}
}
arg
Ok(arg)
};
let mut fn_abi = FnAbi {
ret: arg_of(sig.output(), None),
ret: arg_of(sig.output(), None)?,
args: inputs
.iter()
.cloned()
@ -3007,20 +3110,24 @@ where
.chain(caller_location)
.enumerate()
.map(|(i, ty)| arg_of(ty, Some(i)))
.collect(),
.collect::<Result<_, _>>()?,
c_variadic: sig.c_variadic,
fixed_count: inputs.len(),
conv,
can_unwind: fn_can_unwind(cx.tcx(), codegen_fn_attr_flags, sig.abi),
can_unwind: fn_can_unwind(self.tcx(), codegen_fn_attr_flags, sig.abi),
};
fn_abi.adjust_for_abi(cx, sig.abi);
debug!("FnAbi::new_internal = {:?}", fn_abi);
fn_abi
self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
debug!("fn_abi_new_uncached = {:?}", fn_abi);
Ok(self.tcx.arena.alloc(fn_abi))
}
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
fn fn_abi_adjust_for_abi(
&self,
fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
abi: SpecAbi,
) -> Result<(), FnAbiError<'tcx>> {
if abi == SpecAbi::Unadjusted {
return;
return Ok(());
}
if abi == SpecAbi::Rust
@ -3057,7 +3164,7 @@ where
// anyway, we control all calls to it in libstd.
Abi::Vector { .. }
if abi != SpecAbi::PlatformIntrinsic
&& cx.tcx().sess.target.simd_types_indirect =>
&& self.tcx.sess.target.simd_types_indirect =>
{
arg.make_indirect();
return;
@ -3068,7 +3175,7 @@ where
// Pass and return structures up to 2 pointers in size by value, matching `ScalarPair`.
// LLVM will usually pass these in 2 registers, which is more efficient than by-ref.
let max_by_val_size = Pointer.size(cx) * 2;
let max_by_val_size = Pointer.size(self) * 2;
let size = arg.layout.size;
if arg.layout.is_unsized() || size > max_by_val_size {
@ -3080,16 +3187,15 @@ where
arg.cast_to(Reg { kind: RegKind::Integer, size });
}
};
fixup(&mut self.ret);
for arg in &mut self.args {
fixup(&mut fn_abi.ret);
for arg in &mut fn_abi.args {
fixup(arg);
}
return;
} else {
fn_abi.adjust_for_foreign_abi(self, abi)?;
}
if let Err(msg) = self.adjust_for_cabi(cx, abi) {
cx.tcx().sess.fatal(&msg);
}
Ok(())
}
}

View file

@ -48,6 +48,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
use rustc_session::utils::NativeLibKind;
use rustc_session::Limits;
use rustc_target::abi;
use rustc_target::spec::PanicStrategy;
use rustc_ast as ast;

View file

@ -449,3 +449,25 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
DUMMY_SP
}
}
impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
}
impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
#[inline(always)]
fn query_crate_is_local(&self) -> bool {
true
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
self.0.default_span(tcx)
}
}

View file

@ -1,6 +1,7 @@
use crate::abi::{self, Abi, Align, FieldsShape, Size};
use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
use crate::spec::{self, HasTargetSpec};
use std::fmt;
mod aarch64;
mod amdgpu;
@ -24,7 +25,7 @@ mod x86;
mod x86_64;
mod x86_win64;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum PassMode {
/// Ignore the argument.
///
@ -59,7 +60,7 @@ pub use attr_impl::ArgAttribute;
mod attr_impl {
// The subset of llvm::Attribute needed for arguments, packed into a bitfield.
bitflags::bitflags! {
#[derive(Default)]
#[derive(Default, HashStable_Generic)]
pub struct ArgAttribute: u16 {
const NoAlias = 1 << 1;
const NoCapture = 1 << 2;
@ -76,7 +77,7 @@ mod attr_impl {
/// Sometimes an ABI requires small integers to be extended to a full or partial register. This enum
/// defines if this extension should be zero-extension or sign-extension when necessary. When it is
/// not necessary to extend the argument, this enum is ignored.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum ArgExtension {
None,
Zext,
@ -85,7 +86,7 @@ pub enum ArgExtension {
/// A compact representation of LLVM attributes (at least those relevant for this module)
/// that can be manipulated without interacting with LLVM's Attribute machinery.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct ArgAttributes {
pub regular: ArgAttribute,
pub arg_ext: ArgExtension,
@ -126,14 +127,14 @@ impl ArgAttributes {
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum RegKind {
Integer,
Float,
Vector,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct Reg {
pub kind: RegKind,
pub size: Size,
@ -183,7 +184,7 @@ impl Reg {
/// An argument passed entirely registers with the
/// same kind (e.g., HFA / HVA on PPC64 and AArch64).
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct Uniform {
pub unit: Reg,
@ -208,7 +209,7 @@ impl Uniform {
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct CastTarget {
pub prefix: [Option<RegKind>; 8],
pub prefix_chunk_size: Size,
@ -436,7 +437,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
/// Information about how to pass an argument to,
/// or return a value from, a function, under some ABI.
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct ArgAbi<'a, Ty> {
pub layout: TyAndLayout<'a, Ty>,
@ -544,7 +545,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum Conv {
// General language calling conventions, for which every target
// should have its own backend (e.g. LLVM) support.
@ -578,7 +579,7 @@ pub enum Conv {
///
/// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM
#[derive(Debug)]
#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct FnAbi<'a, Ty> {
/// The LLVM types of each argument.
pub args: Vec<ArgAbi<'a, Ty>>,
@ -599,8 +600,29 @@ pub struct FnAbi<'a, Ty> {
pub can_unwind: bool,
}
/// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
#[derive(Clone, Debug, HashStable_Generic)]
pub enum AdjustForForeignAbiError {
/// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
Unsupported { arch: String, abi: spec::abi::Abi },
}
impl fmt::Display for AdjustForForeignAbiError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unsupported { arch, abi } => {
write!(f, "target architecture {:?} does not support `extern {}` ABI", arch, abi)
}
}
}
}
impl<'a, Ty> FnAbi<'a, Ty> {
pub fn adjust_for_cabi<C>(&mut self, cx: &C, abi: spec::abi::Abi) -> Result<(), String>
pub fn adjust_for_foreign_abi<C>(
&mut self,
cx: &C,
abi: spec::abi::Abi,
) -> Result<(), AdjustForForeignAbiError>
where
Ty: TyAbiInterface<'a, C> + Copy,
C: HasDataLayout + HasTargetSpec,
@ -655,7 +677,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
}
"asmjs" => wasm::compute_c_abi_info(cx, self),
"bpf" => bpf::compute_abi_info(self),
a => return Err(format!("unrecognized arch \"{}\" in target specification", a)),
arch => {
return Err(AdjustForForeignAbiError::Unsupported { arch: arch.to_string(), abi });
}
}
Ok(())