From a871fedf98ee004c3d7b85ab5ce5f28a0347263c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 10 Jul 2020 00:24:48 +0200 Subject: [PATCH] Reduce the amount of interning and `layout_of` calls in const eval. --- src/librustc_middle/mir/interpret/value.rs | 12 ++++ src/librustc_middle/ty/sty.rs | 75 +++++++++++++++++----- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/src/librustc_middle/mir/interpret/value.rs b/src/librustc_middle/mir/interpret/value.rs index 0e913ff58bb4..ce47c2e62826 100644 --- a/src/librustc_middle/mir/interpret/value.rs +++ b/src/librustc_middle/mir/interpret/value.rs @@ -60,6 +60,18 @@ impl<'tcx> ConstValue<'tcx> { self.try_to_scalar()?.to_bits(size).ok() } + pub fn try_to_bool(&self) -> Option { + match self.try_to_bits(Size::from_bytes(1))? { + 0 => Some(false), + 1 => Some(true), + _ => None, + } + } + + pub fn try_to_usize(&self, tcx: TyCtxt<'tcx>) -> Option { + Some(self.try_to_bits(tcx.data_layout.pointer_size)? as u64) + } + pub fn try_to_bits_for_ty( &self, tcx: TyCtxt<'tcx>, diff --git a/src/librustc_middle/ty/sty.rs b/src/librustc_middle/ty/sty.rs index 3104d2ee36a7..b921ad665147 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/src/librustc_middle/ty/sty.rs @@ -2340,14 +2340,41 @@ impl<'tcx> Const<'tcx> { assert_eq!(self.ty, ty); let 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 - self.eval(tcx, param_env).val.try_to_bits(size) + self.val.eval(tcx, param_env).try_to_bits(size) } #[inline] /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the /// unevaluated constant. pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> { - if let ConstKind::Unevaluated(def, substs, promoted) = self.val { + if let Some(val) = self.val.try_eval(tcx, param_env) { + match val { + Ok(val) => Const::from_value(tcx, val, self.ty), + Err(ErrorReported) => tcx.const_error(self.ty), + } + } else { + self + } + } +} + +impl<'tcx> ConstKind<'tcx> { + #[inline] + /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the + /// unevaluated constant. + pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { + self.try_eval(tcx, param_env).and_then(Result::ok).map(ConstKind::Value).unwrap_or(self) + } + + #[inline] + /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary + // return None + pub fn try_eval( + self, + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + ) -> Option, ErrorReported>> { + if let ConstKind::Unevaluated(def, substs, promoted) = self { use crate::mir::interpret::ErrorHandled; let param_env_and_substs = param_env.with_reveal_all().and(substs); @@ -2378,27 +2405,25 @@ impl<'tcx> Const<'tcx> { // and we use the original type, so nothing from `substs` // (which may be identity substs, see above), // can leak through `val` into the const we return. - Ok(val) => Const::from_value(tcx, val, self.ty), - Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self, - Err(ErrorHandled::Reported(ErrorReported)) => tcx.const_error(self.ty), + Ok(val) => Some(Ok(val)), + Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None, + Err(ErrorHandled::Reported(e)) => Some(Err(e)), } } else { - self + None } } +} +impl<'tcx> Const<'tcx> { #[inline] pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option { - self.try_eval_bits(tcx, param_env, tcx.types.bool).and_then(|v| match v { - 0 => Some(false), - 1 => Some(true), - _ => None, - }) + self.val.eval(tcx, param_env).try_to_bool() } #[inline] pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option { - self.try_eval_bits(tcx, param_env, tcx.types.usize).map(|v| v as u64) + self.val.eval(tcx, param_env).try_to_usize(tcx) } #[inline] @@ -2411,7 +2436,8 @@ impl<'tcx> Const<'tcx> { #[inline] /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`. pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 { - self.eval_bits(tcx, param_env, tcx.types.usize) as u64 + self.try_eval_usize(tcx, param_env) + .unwrap_or_else(|| bug!("expected usize, got {:#?}", self)) } } @@ -2448,13 +2474,28 @@ static_assert_size!(ConstKind<'_>, 40); impl<'tcx> ConstKind<'tcx> { #[inline] - pub fn try_to_scalar(&self) -> Option { - if let ConstKind::Value(val) = self { val.try_to_scalar() } else { None } + pub fn try_to_value(self) -> Option> { + if let ConstKind::Value(val) = self { Some(val) } else { None } } #[inline] - pub fn try_to_bits(&self, size: Size) -> Option { - if let ConstKind::Value(val) = self { val.try_to_bits(size) } else { None } + pub fn try_to_scalar(self) -> Option { + self.try_to_value()?.try_to_scalar() + } + + #[inline] + pub fn try_to_bits(self, size: Size) -> Option { + self.try_to_value()?.try_to_bits(size) + } + + #[inline] + pub fn try_to_bool(self) -> Option { + self.try_to_value()?.try_to_bool() + } + + #[inline] + pub fn try_to_usize(self, tcx: TyCtxt<'tcx>) -> Option { + self.try_to_value()?.try_to_usize(tcx) } }