about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-01-13 05:26:43 +0100
committerGitHub <noreply@github.com>2019-01-13 05:26:43 +0100
commit035eff1c1fdc42ae7713efd81d7a481014015a95 (patch)
treed20a5ffc18cf40db462067ef19d48f8e84c425ca /src
parent75a369c5b11459baa6bf7734eeb6135998a0a7de (diff)
parentdec79e44705992d607b001cd349c98807761d3d8 (diff)
downloadrust-035eff1c1fdc42ae7713efd81d7a481014015a95.tar.gz
rust-035eff1c1fdc42ae7713efd81d7a481014015a95.zip
Rollup merge of #57351 - oli-obk:cheap_const_ops, r=RalfJung
Don't actually create a full MIR stack frame when not needed

r? @dotdash

This should significantly reduce overhead during const propagation and reduce overhead *after* copy propagation (cc https://github.com/rust-lang/rust/issues/36673)
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/const_eval.rs50
1 files changed, 36 insertions, 14 deletions
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 01177e5e49a..f5f40481679 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -35,6 +35,16 @@ const STEPS_UNTIL_DETECTOR_ENABLED: isize = 1_000_000;
 /// Should be a power of two for performance reasons.
 const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
 
+/// Warning: do not use this function if you expect to start interpreting the given `Mir`.
+/// The `EvalContext` is only meant to be used to query values from constants and statics.
+///
+/// This function is used during const propagation. We cannot use `mk_eval_cx`, because copy
+/// propagation happens *during* the computation of the MIR of the current function. So if we
+/// tried to call the `optimized_mir` query, we'd get a cycle error because we are (transitively)
+/// inside the `optimized_mir` query of the `Instance` given.
+///
+/// Since we are looking at the MIR of the function in an abstract manner, we don't have a
+/// `ParamEnv` available to us. This function creates a `ParamEnv` for the given instance.
 pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     instance: Instance<'tcx>,
@@ -43,9 +53,22 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
 ) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
     debug!("mk_borrowck_eval_cx: {:?}", instance);
     let param_env = tcx.param_env(instance.def_id());
+    mk_eval_cx_inner(tcx, instance, mir, span, param_env)
+}
+
+/// This is just a helper function to reduce code duplication between `mk_borrowck_eval_cx` and
+/// `mk_eval_cx`. Do not call this function directly.
+fn mk_eval_cx_inner<'a, 'mir, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    instance: Instance<'tcx>,
+    mir: &'mir mir::Mir<'tcx>,
+    span: Span,
+    param_env: ty::ParamEnv<'tcx>,
+) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
-    // insert a stack frame so any queries have the correct substs
-    // cannot use `push_stack_frame`; if we do `const_prop` explodes
+    // Insert a stack frame so any queries have the correct substs.
+    // We also avoid all the extra work performed by push_stack_frame,
+    // like initializing local variables
     ecx.stack.push(interpret::Frame {
         block: mir::START_BLOCK,
         locals: IndexVec::new(),
@@ -60,24 +83,23 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
     Ok(ecx)
 }
 
-pub fn mk_eval_cx<'a, 'tcx>(
+/// Warning: do not use this function if you expect to start interpreting the given `Mir`.
+/// The `EvalContext` is only meant to be used to do field and index projections into constants for
+/// `simd_shuffle` and const patterns in match arms.
+///
+/// The function containing the `match` that is currently being analyzed may have generic bounds
+/// that inform us about the generic bounds of the constant. E.g. using an associated constant
+/// of a function's generic parameter will require knowledge about the bounds on the generic
+/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
+fn mk_eval_cx<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     instance: Instance<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 ) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> {
     debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
     let span = tcx.def_span(instance.def_id());
-    let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
-    let mir = ecx.load_mir(instance.def)?;
-    // insert a stack frame so any queries have the correct substs
-    ecx.push_stack_frame(
-        instance,
-        mir.span,
-        mir,
-        None,
-        StackPopCleanup::Goto(None), // never pop
-    )?;
-    Ok(ecx)
+    let mir = tcx.optimized_mir(instance.def.def_id());
+    mk_eval_cx_inner(tcx, instance, mir, span, param_env)
 }
 
 pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(