Skip to content

Commit

Permalink
Auto merge of #68118 - skinny121:eager_lit_eval, r=varkor
Browse files Browse the repository at this point in the history
perf: Eagerly convert literals to consts

Previousely even literal constants were being converted to an `Unevaluted` constant for evaluation later. This seems unecessary as no more information is needed to be able to convert the literal to a mir constant.

Hopefully this will also minimise the performance impact of #67717, as far less constant evaluations are needed.
  • Loading branch information
bors committed Jan 15, 2020
2 parents 8a87b94 + 583a4fc commit 4b172cc
Show file tree
Hide file tree
Showing 19 changed files with 173 additions and 115 deletions.
2 changes: 1 addition & 1 deletion src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
use crate::hir::map::DefPathHash;
use crate::ich::{Fingerprint, StableHashingContext};
use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::mir::interpret::{GlobalId, LitToConstInput};
use crate::traits;
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
Expand Down
21 changes: 20 additions & 1 deletion src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ use crate::mir;
use crate::ty::codec::TyDecoder;
use crate::ty::layout::{self, Size};
use crate::ty::subst::GenericArgKind;
use crate::ty::{self, Instance, TyCtxt};
use crate::ty::{self, Instance, Ty, TyCtxt};
use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{HashMapExt, Lock};
Expand All @@ -131,6 +131,7 @@ use std::fmt;
use std::io;
use std::num::NonZeroU32;
use std::sync::atomic::{AtomicU32, Ordering};
use syntax::ast::LitKind;

/// Uniquely identifies one of the following:
/// - A constant
Expand All @@ -147,6 +148,24 @@ pub struct GlobalId<'tcx> {
pub promoted: Option<mir::Promoted>,
}

/// Input argument for `tcx.lit_to_const`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable)]
pub struct LitToConstInput<'tcx> {
/// The absolute value of the resultant constant.
pub lit: &'tcx LitKind,
/// The type of the constant.
pub ty: Ty<'tcx>,
/// If the constant is negative.
pub neg: bool,
}

/// Error type for `tcx.lit_to_const`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable)]
pub enum LitToConstError {
UnparseableFloat,
Reported,
}

#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)]
pub struct AllocId(pub u64);

Expand Down
9 changes: 8 additions & 1 deletion src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::dep_graph::{DepKind, DepNode, RecoverKey, SerializedDepNodeIndex};
use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::mir::interpret::{GlobalId, LitToConstInput};
use crate::traits;
use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
Expand Down Expand Up @@ -518,6 +518,13 @@ rustc_queries! {
no_force
desc { "get a &core::panic::Location referring to a span" }
}

query lit_to_const(
key: LitToConstInput<'tcx>
) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
no_force
desc { "converting literal to const" }
}
}

TypeChecking {
Expand Down
10 changes: 10 additions & 0 deletions src/librustc/ty/query/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,16 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> {
}
}

impl<'tcx> Key for mir::interpret::LitToConstInput<'tcx> {
fn query_crate(&self) -> CrateNum {
LOCAL_CRATE
}

fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
DUMMY_SP
}
}

impl Key for CrateNum {
fn query_crate(&self) -> CrateNum {
*self
Expand Down
1 change: 1 addition & 0 deletions src/librustc/ty/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::middle::stability::{self, DeprecationEntry};
use crate::mir;
use crate::mir::interpret::GlobalId;
use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult};
use crate::mir::interpret::{LitToConstError, LitToConstInput};
use crate::mir::mono::CodegenUnit;
use crate::session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
use crate::session::CrateDisambiguator;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ pub fn provide(providers: &mut Providers<'_>) {
providers.destructure_const = |tcx, param_env_and_value| {
let (param_env, value) = param_env_and_value.into_parts();
const_eval::destructure_const(tcx, param_env, value)
}
};
}
57 changes: 33 additions & 24 deletions src/librustc_mir_build/hair/constant.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
use rustc::mir::interpret::{ConstValue, Scalar};
use rustc::ty::{self, layout::Size, ParamEnv, Ty, TyCtxt};
use rustc::mir::interpret::{
truncate, Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc::ty::{self, layout::Size, ParamEnv, TyCtxt};
use rustc_span::symbol::Symbol;
use syntax::ast;

#[derive(PartialEq)]
crate enum LitToConstError {
UnparseableFloat,
Reported,
}

crate fn lit_to_const<'tcx>(
lit: &'tcx ast::LitKind,
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
neg: bool,
lit_input: LitToConstInput<'tcx>,
) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
use syntax::ast::*;
let LitToConstInput { lit, ty, neg } = lit_input;

let trunc = |n| {
let param_ty = ParamEnv::reveal_all().and(ty);
Expand All @@ -26,35 +20,50 @@ crate fn lit_to_const<'tcx>(
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
};

use rustc::mir::interpret::*;
let lit = match *lit {
LitKind::Str(ref s, _) => {
ast::LitKind::Str(ref s, _) => {
let s = s.as_str();
let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
}
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::Ptr(id.into()))
ast::LitKind::ByteStr(ref data) => {
if let ty::Ref(_, ref_ty, _) = ty.kind {
match ref_ty.kind {
ty::Slice(_) => {
let allocation = Allocation::from_byte_aligned_bytes(data as &Vec<u8>);
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: data.len() }
}
ty::Array(_, _) => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::Ptr(id.into()))
}
_ => {
bug!("bytestring should have type of either &[u8] or &[u8; _], not {}", ty)
}
}
} else {
bug!("bytestring should have type of either &[u8] or &[u8; _], not {}", ty)
}
}
LitKind::Byte(n) => ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))),
LitKind::Int(n, _) if neg => {
ast::LitKind::Byte(n) => ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))),
ast::LitKind::Int(n, _) if neg => {
let n = n as i128;
let n = n.overflowing_neg().0;
trunc(n as u128)?
}
LitKind::Int(n, _) => trunc(n)?,
LitKind::Float(n, _) => {
ast::LitKind::Int(n, _) => trunc(n)?,
ast::LitKind::Float(n, _) => {
let fty = match ty.kind {
ty::Float(fty) => fty,
_ => bug!(),
};
parse_float(n, fty, neg).map_err(|_| LitToConstError::UnparseableFloat)?
}
LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
LitKind::Err(_) => unreachable!(),
ast::LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)),
ast::LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)),
ast::LitKind::Err(_) => return Err(LitToConstError::Reported),
};
Ok(tcx.mk_const(ty::Const { val: ty::ConstKind::Value(lit), ty }))
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir_build/hair/cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
use crate::hair::util::UserAnnotatedTyHelpers;
use crate::hair::*;

use crate::hair::constant::{lit_to_const, LitToConstError};
use rustc::infer::InferCtxt;
use rustc::middle::region;
use rustc::mir::interpret::{LitToConstError, LitToConstInput};
use rustc::ty::layout::VariantIdx;
use rustc::ty::subst::Subst;
use rustc::ty::subst::{GenericArg, InternalSubsts};
Expand Down Expand Up @@ -136,7 +136,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> {
) -> &'tcx ty::Const<'tcx> {
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);

match lit_to_const(lit, self.tcx, ty, neg) {
match self.tcx.at(sp).lit_to_const(LitToConstInput { lit, ty, neg }) {
Ok(c) => c,
Err(LitToConstError::UnparseableFloat) => {
// FIXME(#31407) this is only necessary because float parsing is buggy
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir_build/hair/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::Span;

mod constant;
crate mod constant;
crate mod cx;

crate mod pattern;
Expand Down
49 changes: 22 additions & 27 deletions src/librustc_mir_build/hair/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ mod const_to_pat;

pub(crate) use self::check_match::check_match;

use crate::hair::constant::*;
use crate::hair::util::UserAnnotatedTyHelpers;

use rustc::mir::interpret::{get_slice_bytes, sign_extend, ConstValue, ErrorHandled};
use rustc::mir::interpret::{LitToConstError, LitToConstInput};
use rustc::mir::UserTypeProjection;
use rustc::mir::{BorrowKind, Field, Mutability};
use rustc::ty::layout::VariantIdx;
Expand Down Expand Up @@ -822,35 +822,30 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// which would overflow if we tried to evaluate `128_i8` and then negate
/// afterwards.
fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
match expr.kind {
hir::ExprKind::Lit(ref lit) => {
let ty = self.tables.expr_ty(expr);
match lit_to_const(&lit.node, self.tcx, ty, false) {
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
Err(LitToConstError::UnparseableFloat) => {
self.errors.push(PatternError::FloatBug);
PatKind::Wild
}
Err(LitToConstError::Reported) => PatKind::Wild,
if let hir::ExprKind::Path(ref qpath) = expr.kind {
*self.lower_path(qpath, expr.hir_id, expr.span).kind
} else {
let (lit, neg) = match expr.kind {
hir::ExprKind::Lit(ref lit) => (lit, false),
hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => {
let lit = match expr.kind {
hir::ExprKind::Lit(ref lit) => lit,
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
(lit, true)
}
}
hir::ExprKind::Path(ref qpath) => *self.lower_path(qpath, expr.hir_id, expr.span).kind,
hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => {
let ty = self.tables.expr_ty(expr);
let lit = match expr.kind {
hir::ExprKind::Lit(ref lit) => lit,
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};
match lit_to_const(&lit.node, self.tcx, ty, true) {
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
Err(LitToConstError::UnparseableFloat) => {
self.errors.push(PatternError::FloatBug);
PatKind::Wild
}
Err(LitToConstError::Reported) => PatKind::Wild,
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
};

let lit_input = LitToConstInput { lit: &lit.node, ty: self.tables.expr_ty(expr), neg };
match self.tcx.at(expr.span).lit_to_const(lit_input) {
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span).kind,
Err(LitToConstError::UnparseableFloat) => {
self.errors.push(PatternError::FloatBug);
PatKind::Wild
}
Err(LitToConstError::Reported) => PatKind::Wild,
}
_ => span_bug!(expr.span, "not a literal: {:?}", expr),
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir_build/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ use rustc::ty::query::Providers;

pub fn provide(providers: &mut Providers<'_>) {
providers.check_match = hair::pattern::check_match;
providers.lit_to_const = hair::constant::lit_to_const;
providers.mir_built = build::mir_built;
}
40 changes: 27 additions & 13 deletions src/librustc_typeck/astconv.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// ignore-tidy-filelength FIXME(#67418) Split up this file.
//! Conversion from AST representation of types to the `ty.rs` representation.
//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
//! instance of `AstConv`.
Expand Down Expand Up @@ -37,6 +38,7 @@ use std::collections::BTreeSet;
use std::iter;
use std::slice;

use rustc::mir::interpret::LitToConstInput;
use rustc_error_codes::*;

#[derive(Debug)]
Expand Down Expand Up @@ -2699,17 +2701,28 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let tcx = self.tcx();
let def_id = tcx.hir().local_def_id(ast_const.hir_id);

let mut const_ = ty::Const {
val: ty::ConstKind::Unevaluated(
def_id,
InternalSubsts::identity_for_item(tcx, def_id),
None,
),
ty,
let expr = &tcx.hir().body(ast_const.body).value;

let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => match expr.kind {
hir::ExprKind::Lit(ref lit) => {
Some(LitToConstInput { lit: &lit.node, ty, neg: true })
}
_ => None,
},
_ => None,
};

let expr = &tcx.hir().body(ast_const.body).value;
if let Some(def_id) = self.const_param_def_id(expr) {
if let Some(lit_input) = lit_input {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
return c;
}
}

let kind = if let Some(def_id) = self.const_param_def_id(expr) {
// Find the name and index of the const parameter by indexing the generics of the
// parent item and construct a `ParamConst`.
let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
Expand All @@ -2718,10 +2731,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let generics = tcx.generics_of(item_def_id);
let index = generics.param_def_id_to_index[&tcx.hir().local_def_id(hir_id)];
let name = tcx.hir().name(hir_id);
const_.val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
}

tcx.mk_const(const_)
ty::ConstKind::Param(ty::ParamConst::new(index, name))
} else {
ty::ConstKind::Unevaluated(def_id, InternalSubsts::identity_for_item(tcx, def_id), None)
};
tcx.mk_const(ty::Const { val: kind, ty })
}

pub fn impl_trait_ty_to_ty(
Expand Down
Loading

0 comments on commit 4b172cc

Please sign in to comment.