mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 02:33:55 +00:00
Introduce a fast-path for type_is_sized/type_moves_by_default
This seems to improve performance by the same 2-3% of my selection fast-path.
This commit is contained in:
parent
52e530af4c
commit
595409df06
@ -60,7 +60,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'tcx> {
|
|||||||
cmt: mc::cmt<'tcx>,
|
cmt: mc::cmt<'tcx>,
|
||||||
_: euv::ConsumeMode) {
|
_: euv::ConsumeMode) {
|
||||||
debug!("consume; cmt: {:?}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
|
debug!("consume; cmt: {:?}; type: {}", *cmt, ty_to_string(self.tcx, cmt.ty));
|
||||||
if !ty::type_is_sized(self.param_env, span, cmt.ty) {
|
if !ty::type_is_sized(Some(self.param_env), self.tcx, span, cmt.ty) {
|
||||||
span_err!(self.tcx.sess, span, E0161,
|
span_err!(self.tcx.sess, span, E0161,
|
||||||
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
|
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
|
||||||
ty_to_string(self.tcx, cmt.ty));
|
ty_to_string(self.tcx, cmt.ty));
|
||||||
|
@ -212,7 +212,7 @@ impl<'a, 'tcx> IntrinsicCheckingVisitor<'a, 'tcx> {
|
|||||||
debug!("with_each_combination: space={:?}, index={}, param_ty={}",
|
debug!("with_each_combination: space={:?}, index={}, param_ty={}",
|
||||||
space, index, param_ty.repr(self.tcx));
|
space, index, param_ty.repr(self.tcx));
|
||||||
|
|
||||||
if !ty::type_is_sized(param_env, span, param_ty) {
|
if !ty::type_is_sized(Some(param_env), self.tcx, span, param_ty) {
|
||||||
debug!("with_each_combination: param_ty is not known to be sized");
|
debug!("with_each_combination: param_ty is not known to be sized");
|
||||||
|
|
||||||
substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
|
substs.types.get_mut_slice(space)[index] = self.dummy_unsized_ty;
|
||||||
|
@ -756,16 +756,6 @@ pub struct ctxt<'tcx> {
|
|||||||
/// Caches the representation hints for struct definitions.
|
/// Caches the representation hints for struct definitions.
|
||||||
pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
|
pub repr_hint_cache: RefCell<DefIdMap<Rc<Vec<attr::ReprAttr>>>>,
|
||||||
|
|
||||||
/// Caches whether types are known to impl Copy. Note that type
|
|
||||||
/// parameters are never placed into this cache, because their
|
|
||||||
/// results are dependent on the parameter environment.
|
|
||||||
pub type_impls_copy_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
|
|
||||||
|
|
||||||
/// Caches whether types are known to impl Sized. Note that type
|
|
||||||
/// parameters are never placed into this cache, because their
|
|
||||||
/// results are dependent on the parameter environment.
|
|
||||||
pub type_impls_sized_cache: RefCell<HashMap<Ty<'tcx>,bool>>,
|
|
||||||
|
|
||||||
/// Maps Expr NodeId's to their constant qualification.
|
/// Maps Expr NodeId's to their constant qualification.
|
||||||
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
|
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
|
||||||
|
|
||||||
@ -827,6 +817,23 @@ bitflags! {
|
|||||||
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
|
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
|
||||||
TypeFlags::HAS_SELF.bits |
|
TypeFlags::HAS_SELF.bits |
|
||||||
TypeFlags::HAS_REGIONS.bits,
|
TypeFlags::HAS_REGIONS.bits,
|
||||||
|
|
||||||
|
// Flags representing the nominal content of a type,
|
||||||
|
// computed by FlagsComputetion
|
||||||
|
const NOMINAL_FLAGS = TypeFlags::HAS_PARAMS.bits |
|
||||||
|
TypeFlags::HAS_SELF.bits |
|
||||||
|
TypeFlags::HAS_TY_INFER.bits |
|
||||||
|
TypeFlags::HAS_RE_INFER.bits |
|
||||||
|
TypeFlags::HAS_RE_LATE_BOUND.bits |
|
||||||
|
TypeFlags::HAS_REGIONS.bits |
|
||||||
|
TypeFlags::HAS_TY_ERR.bits |
|
||||||
|
TypeFlags::HAS_PROJECTION.bits,
|
||||||
|
|
||||||
|
// Caches for type_is_sized, type_moves_by_default
|
||||||
|
const SIZEDNESS_CACHED = 1 << 16,
|
||||||
|
const IS_SIZED = 1 << 17,
|
||||||
|
const MOVENESS_CACHED = 1 << 18,
|
||||||
|
const MOVES_BY_DEFAULT = 1 << 19,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,8 +866,8 @@ macro_rules! sty_debug_print {
|
|||||||
ty::ty_err => /* unimportant */ continue,
|
ty::ty_err => /* unimportant */ continue,
|
||||||
$(ty::$variant(..) => &mut $variant,)*
|
$(ty::$variant(..) => &mut $variant,)*
|
||||||
};
|
};
|
||||||
let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
|
let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
|
||||||
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
|
let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
|
||||||
|
|
||||||
variant.total += 1;
|
variant.total += 1;
|
||||||
total.total += 1;
|
total.total += 1;
|
||||||
@ -908,7 +915,7 @@ impl<'tcx> ctxt<'tcx> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TyS<'tcx> {
|
pub struct TyS<'tcx> {
|
||||||
pub sty: sty<'tcx>,
|
pub sty: sty<'tcx>,
|
||||||
pub flags: TypeFlags,
|
pub flags: Cell<TypeFlags>,
|
||||||
|
|
||||||
// the maximal depth of any bound regions appearing in this type.
|
// the maximal depth of any bound regions appearing in this type.
|
||||||
region_depth: u32,
|
region_depth: u32,
|
||||||
@ -964,23 +971,23 @@ impl<'tcx> Borrow<sty<'tcx>> for InternedTy<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_has_params(ty: Ty) -> bool {
|
pub fn type_has_params(ty: Ty) -> bool {
|
||||||
ty.flags.intersects(TypeFlags::HAS_PARAMS)
|
ty.flags.get().intersects(TypeFlags::HAS_PARAMS)
|
||||||
}
|
}
|
||||||
pub fn type_has_self(ty: Ty) -> bool {
|
pub fn type_has_self(ty: Ty) -> bool {
|
||||||
ty.flags.intersects(TypeFlags::HAS_SELF)
|
ty.flags.get().intersects(TypeFlags::HAS_SELF)
|
||||||
}
|
}
|
||||||
pub fn type_has_ty_infer(ty: Ty) -> bool {
|
pub fn type_has_ty_infer(ty: Ty) -> bool {
|
||||||
ty.flags.intersects(TypeFlags::HAS_TY_INFER)
|
ty.flags.get().intersects(TypeFlags::HAS_TY_INFER)
|
||||||
}
|
}
|
||||||
pub fn type_needs_infer(ty: Ty) -> bool {
|
pub fn type_needs_infer(ty: Ty) -> bool {
|
||||||
ty.flags.intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
|
ty.flags.get().intersects(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_RE_INFER)
|
||||||
}
|
}
|
||||||
pub fn type_has_projection(ty: Ty) -> bool {
|
pub fn type_has_projection(ty: Ty) -> bool {
|
||||||
ty.flags.intersects(TypeFlags::HAS_PROJECTION)
|
ty.flags.get().intersects(TypeFlags::HAS_PROJECTION)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_has_late_bound_regions(ty: Ty) -> bool {
|
pub fn type_has_late_bound_regions(ty: Ty) -> bool {
|
||||||
ty.flags.intersects(TypeFlags::HAS_RE_LATE_BOUND)
|
ty.flags.get().intersects(TypeFlags::HAS_RE_LATE_BOUND)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An "escaping region" is a bound region whose binder is not part of `t`.
|
/// An "escaping region" is a bound region whose binder is not part of `t`.
|
||||||
@ -2770,8 +2777,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
|||||||
stability: RefCell::new(stability),
|
stability: RefCell::new(stability),
|
||||||
selection_cache: traits::SelectionCache::new(),
|
selection_cache: traits::SelectionCache::new(),
|
||||||
repr_hint_cache: RefCell::new(DefIdMap()),
|
repr_hint_cache: RefCell::new(DefIdMap()),
|
||||||
type_impls_copy_cache: RefCell::new(HashMap::new()),
|
|
||||||
type_impls_sized_cache: RefCell::new(HashMap::new()),
|
|
||||||
const_qualif_map: RefCell::new(NodeMap()),
|
const_qualif_map: RefCell::new(NodeMap()),
|
||||||
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
|
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
|
||||||
cast_kinds: RefCell::new(NodeMap()),
|
cast_kinds: RefCell::new(NodeMap()),
|
||||||
@ -2871,7 +2876,7 @@ fn intern_ty<'tcx>(type_arena: &'tcx TypedArena<TyS<'tcx>>,
|
|||||||
|
|
||||||
let ty = match () {
|
let ty = match () {
|
||||||
() => type_arena.alloc(TyS { sty: st,
|
() => type_arena.alloc(TyS { sty: st,
|
||||||
flags: flags.flags,
|
flags: Cell::new(flags.flags),
|
||||||
region_depth: flags.depth, }),
|
region_depth: flags.depth, }),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2902,7 +2907,7 @@ impl FlagComputation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_flags(&mut self, flags: TypeFlags) {
|
fn add_flags(&mut self, flags: TypeFlags) {
|
||||||
self.flags = self.flags | flags;
|
self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_depth(&mut self, depth: u32) {
|
fn add_depth(&mut self, depth: u32) {
|
||||||
@ -3008,7 +3013,7 @@ impl FlagComputation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add_ty(&mut self, ty: Ty) {
|
fn add_ty(&mut self, ty: Ty) {
|
||||||
self.add_flags(ty.flags);
|
self.add_flags(ty.flags.get());
|
||||||
self.add_depth(ty.region_depth);
|
self.add_depth(ty.region_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3389,11 +3394,11 @@ pub fn type_is_nil(ty: Ty) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_is_error(ty: Ty) -> bool {
|
pub fn type_is_error(ty: Ty) -> bool {
|
||||||
ty.flags.intersects(TypeFlags::HAS_TY_ERR)
|
ty.flags.get().intersects(TypeFlags::HAS_TY_ERR)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_needs_subst(ty: Ty) -> bool {
|
pub fn type_needs_subst(ty: Ty) -> bool {
|
||||||
ty.flags.intersects(TypeFlags::NEEDS_SUBST)
|
ty.flags.get().intersects(TypeFlags::NEEDS_SUBST)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
|
pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool {
|
||||||
@ -3911,42 +3916,30 @@ pub fn type_contents<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> TypeContents {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_impls_bound<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
|
fn type_impls_bound<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
|
||||||
cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
|
tcx: &ty::ctxt<'tcx>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
bound: ty::BuiltinBound,
|
bound: ty::BuiltinBound,
|
||||||
span: Span)
|
span: Span)
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
assert!(!ty::type_needs_infer(ty));
|
let pe;
|
||||||
|
let param_env = match param_env {
|
||||||
if !type_has_params(ty) && !type_has_self(ty) {
|
Some(e) => e,
|
||||||
match cache.borrow().get(&ty) {
|
None => {
|
||||||
None => {}
|
pe = empty_parameter_environment(tcx);
|
||||||
Some(&result) => {
|
&pe
|
||||||
debug!("type_impls_bound({}, {:?}) = {:?} (cached)",
|
|
||||||
ty.repr(param_env.tcx),
|
|
||||||
bound,
|
|
||||||
result);
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
let infcx = infer::new_infer_ctxt(tcx);
|
||||||
let infcx = infer::new_infer_ctxt(param_env.tcx);
|
|
||||||
|
|
||||||
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span);
|
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span);
|
||||||
|
|
||||||
debug!("type_impls_bound({}, {:?}) = {:?}",
|
debug!("type_impls_bound({}, {:?}) = {:?}",
|
||||||
ty.repr(param_env.tcx),
|
ty.repr(tcx),
|
||||||
bound,
|
bound,
|
||||||
is_impld);
|
is_impld);
|
||||||
|
|
||||||
if !type_has_params(ty) && !type_has_self(ty) {
|
|
||||||
let old_value = cache.borrow_mut().insert(ty, is_impld);
|
|
||||||
assert!(old_value.is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
is_impld
|
is_impld
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3955,17 +3948,85 @@ pub fn type_moves_by_default<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
|
|||||||
ty: Ty<'tcx>)
|
ty: Ty<'tcx>)
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
let tcx = param_env.tcx;
|
if ty.flags.get().intersects(TypeFlags::MOVENESS_CACHED) {
|
||||||
!type_impls_bound(param_env, &tcx.type_impls_copy_cache, ty, ty::BoundCopy, span)
|
return ty.flags.get().intersects(TypeFlags::MOVES_BY_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(!ty::type_needs_infer(ty));
|
||||||
|
|
||||||
|
// Fast-path for primitive types
|
||||||
|
let result = match ty.sty {
|
||||||
|
ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
|
||||||
|
ty_ptr(..) | ty_bare_fn(..) | ty_rptr(_, mt {
|
||||||
|
mutbl: ast::MutImmutable, ..
|
||||||
|
}) => Some(false),
|
||||||
|
|
||||||
|
ty_str | ty_uniq(..) | ty_rptr(_, mt {
|
||||||
|
mutbl: ast::MutMutable, ..
|
||||||
|
}) => Some(true),
|
||||||
|
|
||||||
|
ty_vec(..) | ty_trait(..) | ty_tup(..) |
|
||||||
|
ty_closure(..) | ty_enum(..) | ty_struct(..) |
|
||||||
|
ty_projection(..) | ty_param(..) | ty_infer(..) | ty_err => None
|
||||||
|
}.unwrap_or_else(|| !type_impls_bound(Some(param_env),
|
||||||
|
param_env.tcx,
|
||||||
|
ty,
|
||||||
|
ty::BoundCopy,
|
||||||
|
span));
|
||||||
|
|
||||||
|
if !type_has_params(ty) && !type_has_self(ty) {
|
||||||
|
ty.flags.set(ty.flags.get() | if result {
|
||||||
|
TypeFlags::MOVENESS_CACHED | TypeFlags::MOVES_BY_DEFAULT
|
||||||
|
} else {
|
||||||
|
TypeFlags::MOVENESS_CACHED
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_is_sized<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
|
#[inline]
|
||||||
|
pub fn type_is_sized<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
|
||||||
|
tcx: &ty::ctxt<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
ty: Ty<'tcx>)
|
ty: Ty<'tcx>)
|
||||||
-> bool
|
-> bool
|
||||||
{
|
{
|
||||||
let tcx = param_env.tcx;
|
if ty.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) {
|
||||||
type_impls_bound(param_env, &tcx.type_impls_sized_cache, ty, ty::BoundSized, span)
|
let result = ty.flags.get().intersects(TypeFlags::IS_SIZED);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
type_is_sized_uncached(param_env, tcx, span, ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn type_is_sized_uncached<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
|
||||||
|
tcx: &ty::ctxt<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
ty: Ty<'tcx>) -> bool {
|
||||||
|
assert!(!ty::type_needs_infer(ty));
|
||||||
|
|
||||||
|
// Fast-path for primitive types
|
||||||
|
let result = match ty.sty {
|
||||||
|
ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
|
||||||
|
ty_uniq(..) | ty_ptr(..) | ty_rptr(..) | ty_bare_fn(..) |
|
||||||
|
ty_vec(_, Some(..)) | ty_tup(..) | ty_closure(..) => Some(true),
|
||||||
|
|
||||||
|
ty_str | ty_trait(..) | ty_vec(_, None) => Some(false),
|
||||||
|
|
||||||
|
ty_enum(..) | ty_struct(..) | ty_projection(..) | ty_param(..) |
|
||||||
|
ty_infer(..) | ty_err => None
|
||||||
|
}.unwrap_or_else(|| type_impls_bound(param_env, tcx, ty, ty::BoundSized, span));
|
||||||
|
|
||||||
|
if !type_has_params(ty) && !type_has_self(ty) {
|
||||||
|
ty.flags.set(ty.flags.get() | if result {
|
||||||
|
TypeFlags::SIZEDNESS_CACHED | TypeFlags::IS_SIZED
|
||||||
|
} else {
|
||||||
|
TypeFlags::SIZEDNESS_CACHED
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub fn is_ffi_safe<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
|
@ -118,19 +118,9 @@ pub fn erase_regions<'tcx,T>(cx: &ty::ctxt<'tcx>, value: &T) -> T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the type's representation size known at compile time?
|
/// Is the type's representation size known at compile time?
|
||||||
pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub fn type_is_sized<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
let param_env = ty::empty_parameter_environment(tcx);
|
ty::type_is_sized(None, tcx, DUMMY_SP, ty)
|
||||||
// FIXME(#4287) This can cause errors due to polymorphic recursion,
|
|
||||||
// a better span should be provided, if available.
|
|
||||||
let err_count = tcx.sess.err_count();
|
|
||||||
let is_sized = ty::type_is_sized(¶m_env, DUMMY_SP, ty);
|
|
||||||
// Those errors aren't fatal, but an incorrect result can later
|
|
||||||
// trip over asserts in both rustc's trans and LLVM.
|
|
||||||
if err_count < tcx.sess.err_count() {
|
|
||||||
tcx.sess.abort_if_errors();
|
|
||||||
}
|
|
||||||
is_sized
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user