mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 18:23:49 +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>,
|
||||
_: euv::ConsumeMode) {
|
||||
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,
|
||||
"cannot move a value of type {0}: the size of {0} cannot be statically determined",
|
||||
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={}",
|
||||
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");
|
||||
|
||||
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.
|
||||
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.
|
||||
pub const_qualif_map: RefCell<NodeMap<check_const::ConstQualif>>,
|
||||
|
||||
@ -827,6 +817,23 @@ bitflags! {
|
||||
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
|
||||
TypeFlags::HAS_SELF.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::$variant(..) => &mut $variant,)*
|
||||
};
|
||||
let region = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
|
||||
let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
|
||||
let region = t.flags.get().intersects(ty::TypeFlags::HAS_RE_INFER);
|
||||
let ty = t.flags.get().intersects(ty::TypeFlags::HAS_TY_INFER);
|
||||
|
||||
variant.total += 1;
|
||||
total.total += 1;
|
||||
@ -908,7 +915,7 @@ impl<'tcx> ctxt<'tcx> {
|
||||
#[derive(Debug)]
|
||||
pub struct TyS<'tcx> {
|
||||
pub sty: sty<'tcx>,
|
||||
pub flags: TypeFlags,
|
||||
pub flags: Cell<TypeFlags>,
|
||||
|
||||
// the maximal depth of any bound regions appearing in this type.
|
||||
region_depth: u32,
|
||||
@ -964,23 +971,23 @@ impl<'tcx> Borrow<sty<'tcx>> for InternedTy<'tcx> {
|
||||
}
|
||||
|
||||
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 {
|
||||
ty.flags.intersects(TypeFlags::HAS_SELF)
|
||||
ty.flags.get().intersects(TypeFlags::HAS_SELF)
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
ty.flags.intersects(TypeFlags::HAS_PROJECTION)
|
||||
ty.flags.get().intersects(TypeFlags::HAS_PROJECTION)
|
||||
}
|
||||
|
||||
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`.
|
||||
@ -2770,8 +2777,6 @@ pub fn mk_ctxt<'tcx>(s: Session,
|
||||
stability: RefCell::new(stability),
|
||||
selection_cache: traits::SelectionCache::new(),
|
||||
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()),
|
||||
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
|
||||
cast_kinds: RefCell::new(NodeMap()),
|
||||
@ -2871,7 +2876,7 @@ fn intern_ty<'tcx>(type_arena: &'tcx TypedArena<TyS<'tcx>>,
|
||||
|
||||
let ty = match () {
|
||||
() => type_arena.alloc(TyS { sty: st,
|
||||
flags: flags.flags,
|
||||
flags: Cell::new(flags.flags),
|
||||
region_depth: flags.depth, }),
|
||||
};
|
||||
|
||||
@ -2902,7 +2907,7 @@ impl FlagComputation {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -3008,7 +3013,7 @@ impl FlagComputation {
|
||||
}
|
||||
|
||||
fn add_ty(&mut self, ty: Ty) {
|
||||
self.add_flags(ty.flags);
|
||||
self.add_flags(ty.flags.get());
|
||||
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 {
|
||||
ty.flags.intersects(TypeFlags::HAS_TY_ERR)
|
||||
ty.flags.get().intersects(TypeFlags::HAS_TY_ERR)
|
||||
}
|
||||
|
||||
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 {
|
||||
@ -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>,
|
||||
cache: &RefCell<HashMap<Ty<'tcx>,bool>>,
|
||||
fn type_impls_bound<'a,'tcx>(param_env: Option<&ParameterEnvironment<'a,'tcx>>,
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
bound: ty::BuiltinBound,
|
||||
span: Span)
|
||||
-> bool
|
||||
{
|
||||
assert!(!ty::type_needs_infer(ty));
|
||||
|
||||
if !type_has_params(ty) && !type_has_self(ty) {
|
||||
match cache.borrow().get(&ty) {
|
||||
None => {}
|
||||
Some(&result) => {
|
||||
debug!("type_impls_bound({}, {:?}) = {:?} (cached)",
|
||||
ty.repr(param_env.tcx),
|
||||
bound,
|
||||
result);
|
||||
return result
|
||||
}
|
||||
let pe;
|
||||
let param_env = match param_env {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
pe = empty_parameter_environment(tcx);
|
||||
&pe
|
||||
}
|
||||
}
|
||||
|
||||
let infcx = infer::new_infer_ctxt(param_env.tcx);
|
||||
};
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
|
||||
let is_impld = traits::type_known_to_meet_builtin_bound(&infcx, param_env, ty, bound, span);
|
||||
|
||||
debug!("type_impls_bound({}, {:?}) = {:?}",
|
||||
ty.repr(param_env.tcx),
|
||||
ty.repr(tcx),
|
||||
bound,
|
||||
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
|
||||
}
|
||||
|
||||
@ -3955,17 +3948,85 @@ pub fn type_moves_by_default<'a,'tcx>(param_env: &ParameterEnvironment<'a,'tcx>,
|
||||
ty: Ty<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
let tcx = param_env.tcx;
|
||||
!type_impls_bound(param_env, &tcx.type_impls_copy_cache, ty, ty::BoundCopy, span)
|
||||
if ty.flags.get().intersects(TypeFlags::MOVENESS_CACHED) {
|
||||
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,
|
||||
ty: Ty<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
let tcx = param_env.tcx;
|
||||
type_impls_bound(param_env, &tcx.type_impls_sized_cache, ty, ty::BoundSized, span)
|
||||
if ty.flags.get().intersects(TypeFlags::SIZEDNESS_CACHED) {
|
||||
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 {
|
||||
|
@ -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 {
|
||||
let param_env = ty::empty_parameter_environment(tcx);
|
||||
// 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
|
||||
ty::type_is_sized(None, tcx, DUMMY_SP, ty)
|
||||
}
|
||||
|
||||
pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
|
Loading…
Reference in New Issue
Block a user