Skip to content

Commit a871fed

Browse files
committed
Reduce the amount of interning and layout_of calls in const eval.
1 parent 7e11379 commit a871fed

File tree

2 files changed

+70
-17
lines changed

2 files changed

+70
-17
lines changed

src/librustc_middle/mir/interpret/value.rs

+12
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ impl<'tcx> ConstValue<'tcx> {
6060
self.try_to_scalar()?.to_bits(size).ok()
6161
}
6262

63+
pub fn try_to_bool(&self) -> Option<bool> {
64+
match self.try_to_bits(Size::from_bytes(1))? {
65+
0 => Some(false),
66+
1 => Some(true),
67+
_ => None,
68+
}
69+
}
70+
71+
pub fn try_to_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
72+
Some(self.try_to_bits(tcx.data_layout.pointer_size)? as u64)
73+
}
74+
6375
pub fn try_to_bits_for_ty(
6476
&self,
6577
tcx: TyCtxt<'tcx>,

src/librustc_middle/ty/sty.rs

+58-17
Original file line numberDiff line numberDiff line change
@@ -2340,14 +2340,41 @@ impl<'tcx> Const<'tcx> {
23402340
assert_eq!(self.ty, ty);
23412341
let size = tcx.layout_of(param_env.with_reveal_all().and(ty)).ok()?.size;
23422342
// if `ty` does not depend on generic parameters, use an empty param_env
2343-
self.eval(tcx, param_env).val.try_to_bits(size)
2343+
self.val.eval(tcx, param_env).try_to_bits(size)
23442344
}
23452345

23462346
#[inline]
23472347
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
23482348
/// unevaluated constant.
23492349
pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
2350-
if let ConstKind::Unevaluated(def, substs, promoted) = self.val {
2350+
if let Some(val) = self.val.try_eval(tcx, param_env) {
2351+
match val {
2352+
Ok(val) => Const::from_value(tcx, val, self.ty),
2353+
Err(ErrorReported) => tcx.const_error(self.ty),
2354+
}
2355+
} else {
2356+
self
2357+
}
2358+
}
2359+
}
2360+
2361+
impl<'tcx> ConstKind<'tcx> {
2362+
#[inline]
2363+
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
2364+
/// unevaluated constant.
2365+
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
2366+
self.try_eval(tcx, param_env).and_then(Result::ok).map(ConstKind::Value).unwrap_or(self)
2367+
}
2368+
2369+
#[inline]
2370+
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
2371+
// return None
2372+
pub fn try_eval(
2373+
self,
2374+
tcx: TyCtxt<'tcx>,
2375+
param_env: ParamEnv<'tcx>,
2376+
) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
2377+
if let ConstKind::Unevaluated(def, substs, promoted) = self {
23512378
use crate::mir::interpret::ErrorHandled;
23522379

23532380
let param_env_and_substs = param_env.with_reveal_all().and(substs);
@@ -2378,27 +2405,25 @@ impl<'tcx> Const<'tcx> {
23782405
// and we use the original type, so nothing from `substs`
23792406
// (which may be identity substs, see above),
23802407
// can leak through `val` into the const we return.
2381-
Ok(val) => Const::from_value(tcx, val, self.ty),
2382-
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
2383-
Err(ErrorHandled::Reported(ErrorReported)) => tcx.const_error(self.ty),
2408+
Ok(val) => Some(Ok(val)),
2409+
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
2410+
Err(ErrorHandled::Reported(e)) => Some(Err(e)),
23842411
}
23852412
} else {
2386-
self
2413+
None
23872414
}
23882415
}
2416+
}
23892417

2418+
impl<'tcx> Const<'tcx> {
23902419
#[inline]
23912420
pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
2392-
self.try_eval_bits(tcx, param_env, tcx.types.bool).and_then(|v| match v {
2393-
0 => Some(false),
2394-
1 => Some(true),
2395-
_ => None,
2396-
})
2421+
self.val.eval(tcx, param_env).try_to_bool()
23972422
}
23982423

23992424
#[inline]
24002425
pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
2401-
self.try_eval_bits(tcx, param_env, tcx.types.usize).map(|v| v as u64)
2426+
self.val.eval(tcx, param_env).try_to_usize(tcx)
24022427
}
24032428

24042429
#[inline]
@@ -2411,7 +2436,8 @@ impl<'tcx> Const<'tcx> {
24112436
#[inline]
24122437
/// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
24132438
pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
2414-
self.eval_bits(tcx, param_env, tcx.types.usize) as u64
2439+
self.try_eval_usize(tcx, param_env)
2440+
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
24152441
}
24162442
}
24172443

@@ -2448,13 +2474,28 @@ static_assert_size!(ConstKind<'_>, 40);
24482474

24492475
impl<'tcx> ConstKind<'tcx> {
24502476
#[inline]
2451-
pub fn try_to_scalar(&self) -> Option<Scalar> {
2452-
if let ConstKind::Value(val) = self { val.try_to_scalar() } else { None }
2477+
pub fn try_to_value(self) -> Option<ConstValue<'tcx>> {
2478+
if let ConstKind::Value(val) = self { Some(val) } else { None }
2479+
}
2480+
2481+
#[inline]
2482+
pub fn try_to_scalar(self) -> Option<Scalar> {
2483+
self.try_to_value()?.try_to_scalar()
2484+
}
2485+
2486+
#[inline]
2487+
pub fn try_to_bits(self, size: Size) -> Option<u128> {
2488+
self.try_to_value()?.try_to_bits(size)
2489+
}
2490+
2491+
#[inline]
2492+
pub fn try_to_bool(self) -> Option<bool> {
2493+
self.try_to_value()?.try_to_bool()
24532494
}
24542495

24552496
#[inline]
2456-
pub fn try_to_bits(&self, size: Size) -> Option<u128> {
2457-
if let ConstKind::Value(val) = self { val.try_to_bits(size) } else { None }
2497+
pub fn try_to_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
2498+
self.try_to_value()?.try_to_usize(tcx)
24582499
}
24592500
}
24602501

0 commit comments

Comments
 (0)