Skip to content

Commit

Permalink
Optimize try_eval_bits to avoid layout queries
Browse files Browse the repository at this point in the history
This specifically targets match checking, but is possibly more widely
useful as well. In code with large, single-value match statements, we
were previously spending a lot of time running layout_of for the
primitive types (integers, chars) -- which is essentially useless. This
optimizes the code to avoid those query calls by directly obtaining the
size for these types, when possible.

It may be worth considering adding a `size_of` query in the future which
might be far faster, especially if specialized for "const" cases --
match arms being the most obvious example. It's possibly such a function
would benefit from *not* being a query as well, since it's trivially
evaluatable from the sty for many cases whereas a query needs to hash
the input and such.
  • Loading branch information
Mark-Simulacrum committed Sep 29, 2019
1 parent 06c6894 commit 06c6e75
Showing 1 changed file with 16 additions and 2 deletions.
18 changes: 16 additions & 2 deletions src/librustc/ty/sty.rs
Expand Up @@ -13,7 +13,7 @@ use rustc_macros::HashStable;
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef, GenericArg, GenericArgKind};
use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFoldable};
use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
use crate::ty::layout::VariantIdx;
use crate::ty::layout::{Size, Integer, IntegerExt, VariantIdx};
use crate::util::captures::Captures;
use crate::mir::interpret::{Scalar, GlobalId};

Expand All @@ -24,6 +24,7 @@ use std::marker::PhantomData;
use std::ops::Range;
use rustc_target::spec::abi;
use syntax::ast::{self, Ident};
use syntax::attr::{SignedInt, UnsignedInt};
use syntax::symbol::{kw, InternedString};

use self::InferTy::*;
Expand Down Expand Up @@ -2298,8 +2299,21 @@ impl<'tcx> Const<'tcx> {
ty: Ty<'tcx>,
) -> Option<u128> {
assert_eq!(self.ty, ty);
// This is purely an optimization -- layout_of is a pretty expensive operation,
// but if we can determine the size without calling it, we don't need all that complexity
// (hashing, caching, etc.). As such, try to skip it.
let size = match ty.kind {
ty::Bool => Size::from_bytes(1),
ty::Char => Size::from_bytes(4),
ty::Int(ity) => {
Integer::from_attr(&tcx, SignedInt(ity)).size()
}
ty::Uint(uty) => {
Integer::from_attr(&tcx, UnsignedInt(uty)).size()
}
_ => tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size,
};
// if `ty` does not depend on generic parameters, use an empty param_env
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
self.eval(tcx, param_env).val.try_to_bits(size)
}

Expand Down

0 comments on commit 06c6e75

Please sign in to comment.