From 06c6e75aae8918f2d7e5ab7089b36c7ac9ec73bb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 21 Sep 2019 18:39:35 -0400 Subject: [PATCH] Optimize try_eval_bits to avoid layout queries 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. --- src/librustc/ty/sty.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 91479751ef41d..cfad02c152d87 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -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}; @@ -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::*; @@ -2298,8 +2299,21 @@ impl<'tcx> Const<'tcx> { ty: Ty<'tcx>, ) -> Option { 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) }