Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Eagerly convert literals to consts #68118

Merged
merged 4 commits into from
Jan 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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