From 42e996e03e8ebdb42d4bd6de2c4272ffb3bf8ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Thu, 10 Jan 2019 19:07:40 +0100 Subject: [PATCH] Avoid layout calculations in assert_bits to speed up match checking assert_bits ensures that the given type matches the type of the constant value, and additionally performs a query for the layout of the given type to get its size. This is then used to assert that it matches the size of the constant. But since the types are already known to be the same, this second check is unnecessary, and skipping it also allows to skip the expensive layout query. For the unicode_normalization crate, the match checking time drops from about 3.8s to about 0.8s for me. --- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/sty.rs | 27 ++++++++----------- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/hair/pattern/_match.rs | 4 +-- .../transform/simplify_branches.rs | 2 +- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a2c96e7cf9f66..760d888d215b1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2277,7 +2277,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { match tcx.const_eval(param_env.and(cid)) { Ok(val) => { // FIXME: Find the right type and use it instead of `val.ty` here - if let Some(b) = val.assert_bits(tcx.global_tcx(), param_env.and(val.ty)) { + if let Some(b) = val.assert_bits(param_env.and(val.ty)) { trace!("discriminants: {} ({:?})", b, repr_type); Some(Discr { val: b, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b98369b62ea37..d647a9ccf9ddc 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -2152,20 +2152,19 @@ impl<'tcx> Const<'tcx> { } #[inline] - pub fn assert_bits( - &self, - tcx: TyCtxt<'_, '_, '_>, - ty: ParamEnvAnd<'tcx, Ty<'tcx>>, - ) -> Option { + pub fn assert_bits(&self, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Option { assert_eq!(self.ty, ty.value); - let ty = tcx.lift_to_global(&ty).unwrap(); - let size = tcx.layout_of(ty).ok()?.size; - self.val.try_to_bits(size) + match self.val.try_to_scalar()? { + Scalar::Bits { bits, .. } => { + Some(bits) + } + Scalar::Ptr(_) => None, + } } #[inline] pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option { - self.assert_bits(tcx, ParamEnv::empty().and(tcx.types.bool)).and_then(|v| match v { + self.assert_bits(ParamEnv::empty().and(tcx.types.bool)).and_then(|v| match v { 0 => Some(false), 1 => Some(true), _ => None, @@ -2174,16 +2173,12 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option { - self.assert_bits(tcx, ParamEnv::empty().and(tcx.types.usize)).map(|v| v as u64) + self.assert_bits(ParamEnv::empty().and(tcx.types.usize)).map(|v| v as u64) } #[inline] - pub fn unwrap_bits( - &self, - tcx: TyCtxt<'_, '_, '_>, - ty: ParamEnvAnd<'tcx, Ty<'tcx>>, - ) -> u128 { - self.assert_bits(tcx, ty).unwrap_or_else(|| + pub fn unwrap_bits(&self, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> u128 { + self.assert_bits(ty).unwrap_or_else(|| bug!("expected bits of {}, got {:#?}", ty.value, self)) } diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 696c173b048ad..d2e20820b7af1 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let switch_ty = ty::ParamEnv::empty().and(switch_ty); indices.entry(value) .or_insert_with(|| { - options.push(value.unwrap_bits(self.hir.tcx(), switch_ty)); + options.push(value.unwrap_bits(switch_ty)); options.len() - 1 }); true diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index b25d47b390175..46b9f4f4f5d88 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -844,7 +844,7 @@ impl<'tcx> IntRange<'tcx> { } ConstantValue(val) if is_integral(val.ty) => { let ty = val.ty; - if let Some(val) = val.assert_bits(tcx, ty::ParamEnv::empty().and(ty)) { + if let Some(val) = val.assert_bits(ty::ParamEnv::empty().and(ty)) { let bias = IntRange::signed_bias(tcx, ty); let val = val ^ bias; Some(IntRange { range: val..=val, ty }) @@ -1458,7 +1458,7 @@ fn slice_pat_covered_by_const<'tcx>( { match pat.kind { box PatternKind::Constant { value } => { - let b = value.unwrap_bits(tcx, ty::ParamEnv::empty().and(pat.ty)); + let b = value.unwrap_bits(ty::ParamEnv::empty().and(pat.ty)); assert_eq!(b as u8 as u128, b); if b as u8 != *ch { return Ok(false); diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index abaea70946383..af09a60959c53 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -30,7 +30,7 @@ impl MirPass for SimplifyBranches { discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, .. } => { let switch_ty = ParamEnv::empty().and(switch_ty); - let constant = c.literal.map_evaluated(|c| c.assert_bits(tcx, switch_ty)); + let constant = c.literal.map_evaluated(|c| c.assert_bits(switch_ty)); if let Some(constant) = constant { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise };