Skip to content

Commit

Permalink
Avoid layout calculations in assert_bits to speed up match checking
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dotdash committed Jan 12, 2019
1 parent b439861 commit 42e996e
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
27 changes: 11 additions & 16 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2152,20 +2152,19 @@ impl<'tcx> Const<'tcx> {
}

#[inline]
pub fn assert_bits(
&self,
tcx: TyCtxt<'_, '_, '_>,
ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Option<u128> {
pub fn assert_bits(&self, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Option<u128> {
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<bool> {
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,
Expand All @@ -2174,16 +2173,12 @@ impl<'tcx> Const<'tcx> {

#[inline]
pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
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))
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/build/matches/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/simplify_branches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down

0 comments on commit 42e996e

Please sign in to comment.