Skip to content

Commit 775da71

Browse files
committed
Add a fast path for lowering trivial consts
1 parent 4ddbb60 commit 775da71

File tree

16 files changed

+191
-83
lines changed

16 files changed

+191
-83
lines changed

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rustc_hir::def::DefKind;
77
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
88
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
99
use rustc_middle::query::TyCtxtAt;
10-
use rustc_middle::ty::layout::HasTypingEnv;
10+
use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
1111
use rustc_middle::ty::print::with_no_trimmed_paths;
1212
use rustc_middle::ty::{self, Ty, TyCtxt};
1313
use rustc_middle::{bug, throw_inval};
@@ -24,13 +24,11 @@ use crate::interpret::{
2424
};
2525
use crate::{CTRL_C_RECEIVED, errors};
2626

27-
// Returns a pointer to where the result lives
28-
#[instrument(level = "trace", skip(ecx, body))]
29-
fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
27+
fn setup_for_eval<'tcx>(
3028
ecx: &mut CompileTimeInterpCx<'tcx>,
3129
cid: GlobalId<'tcx>,
32-
body: &'tcx mir::Body<'tcx>,
33-
) -> InterpResult<'tcx, R> {
30+
layout: TyAndLayout<'tcx>,
31+
) -> InterpResult<'tcx, (InternKind, MPlaceTy<'tcx>)> {
3432
let tcx = *ecx.tcx;
3533
assert!(
3634
cid.promoted.is_some()
@@ -46,7 +44,6 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
4644
"Unexpected DefKind: {:?}",
4745
ecx.tcx.def_kind(cid.instance.def_id())
4846
);
49-
let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?;
5047
assert!(layout.is_sized());
5148

5249
let intern_kind = if cid.promoted.is_some() {
@@ -58,12 +55,25 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
5855
}
5956
};
6057

61-
let ret = if let InternKind::Static(_) = intern_kind {
62-
create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)?
58+
let return_place = if let InternKind::Static(_) = intern_kind {
59+
create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)
6360
} else {
64-
ecx.allocate(layout, MemoryKind::Stack)?
61+
ecx.allocate(layout, MemoryKind::Stack)
6562
};
6663

64+
return_place.map(|ret| (intern_kind, ret))
65+
}
66+
67+
#[instrument(level = "trace", skip(ecx, body))]
68+
fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
69+
ecx: &mut CompileTimeInterpCx<'tcx>,
70+
cid: GlobalId<'tcx>,
71+
body: &'tcx mir::Body<'tcx>,
72+
) -> InterpResult<'tcx, R> {
73+
let tcx = *ecx.tcx;
74+
let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?;
75+
let (intern_kind, ret) = setup_for_eval(ecx, cid, layout)?;
76+
6777
trace!(
6878
"eval_body_using_ecx: pushing stack frame for global: {}{}",
6979
with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())),
@@ -87,6 +97,31 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
8797
}
8898
}
8999

100+
intern_and_validate(ecx, cid, intern_kind, ret)
101+
}
102+
103+
#[instrument(level = "trace", skip(ecx))]
104+
fn eval_trivial_const_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
105+
ecx: &mut CompileTimeInterpCx<'tcx>,
106+
cid: GlobalId<'tcx>,
107+
val: ConstValue,
108+
ty: Ty<'tcx>,
109+
) -> InterpResult<'tcx, R> {
110+
let layout = ecx.layout_of(ty)?;
111+
let (intern_kind, return_place) = setup_for_eval(ecx, cid, layout)?;
112+
113+
let opty = ecx.const_val_to_op(val, ty, Some(layout))?;
114+
ecx.copy_op(&opty, &return_place)?;
115+
116+
intern_and_validate(ecx, cid, intern_kind, return_place)
117+
}
118+
119+
fn intern_and_validate<'tcx, R: InterpretationResult<'tcx>>(
120+
ecx: &mut CompileTimeInterpCx<'tcx>,
121+
cid: GlobalId<'tcx>,
122+
intern_kind: InternKind,
123+
ret: MPlaceTy<'tcx>,
124+
) -> InterpResult<'tcx, R> {
90125
// Intern the result
91126
let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret);
92127

@@ -292,6 +327,9 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
292327
tcx: TyCtxt<'tcx>,
293328
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
294329
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
330+
if let Some((value, _ty)) = tcx.trivial_const(key.value.instance.def_id()) {
331+
return Ok(value);
332+
}
295333
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
296334
}
297335

@@ -368,10 +406,14 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
368406
// so we have to reject reading mutable global memory.
369407
CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
370408
);
371-
let res = ecx.load_mir(cid.instance.def, cid.promoted);
372-
res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body))
373-
.report_err()
374-
.map_err(|error| report_eval_error(&ecx, cid, error))
409+
410+
let result = if let Some((value, ty)) = tcx.trivial_const(def) {
411+
eval_trivial_const_using_ecx(&mut ecx, cid, value, ty)
412+
} else {
413+
ecx.load_mir(cid.instance.def, cid.promoted)
414+
.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body))
415+
};
416+
result.report_err().map_err(|error| report_eval_error(&ecx, cid, error))
375417
}
376418

377419
#[inline(always)]

compiler/rustc_interface/src/passes.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,9 +1088,15 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
10881088

10891089
sess.time("MIR_borrow_checking", || {
10901090
tcx.par_hir_body_owners(|def_id| {
1091-
if !tcx.is_typeck_child(def_id.to_def_id()) {
1091+
let not_typeck_child = !tcx.is_typeck_child(def_id.to_def_id());
1092+
if not_typeck_child {
10921093
// Child unsafety and borrowck happens together with the parent
10931094
tcx.ensure_ok().check_unsafety(def_id);
1095+
}
1096+
if tcx.is_trivial_const(def_id) {
1097+
return;
1098+
}
1099+
if not_typeck_child {
10941100
tcx.ensure_ok().mir_borrowck(def_id);
10951101
tcx.ensure_ok().check_transmutes(def_id);
10961102
}
@@ -1198,7 +1204,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
11981204
if tcx.sess.opts.unstable_opts.validate_mir {
11991205
sess.time("ensuring_final_MIR_is_computable", || {
12001206
tcx.par_hir_body_owners(|def_id| {
1201-
tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
1207+
if !tcx.is_trivial_const(def_id) {
1208+
tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
1209+
}
12021210
});
12031211
});
12041212
}

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ provide! { tcx, def_id, other, cdata,
240240
thir_abstract_const => { table }
241241
optimized_mir => { table }
242242
mir_for_ctfe => { table }
243+
trivial_const => { table }
243244
closure_saved_names_of_captured_variables => { table }
244245
mir_coroutine_witnesses => { table }
245246
promoted_mir => { table }

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1791,8 +1791,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
17911791
record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses);
17921792
}
17931793
}
1794+
let mut is_trivial = false;
17941795
if encode_const {
1795-
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id));
1796+
if let Some((val, ty)) = tcx.trivial_const(def_id) {
1797+
is_trivial = true;
1798+
record!(self.tables.trivial_const[def_id.to_def_id()] <- (val, ty));
1799+
} else {
1800+
is_trivial = false;
1801+
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id));
1802+
}
17961803

17971804
// FIXME(generic_const_exprs): this feels wrong to have in `encode_mir`
17981805
let abstract_const = tcx.thir_abstract_const(def_id);
@@ -1810,7 +1817,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
18101817
}
18111818
}
18121819
}
1813-
record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id));
1820+
if !is_trivial {
1821+
record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id));
1822+
}
18141823

18151824
if self.tcx.is_coroutine(def_id.to_def_id())
18161825
&& let Some(witnesses) = tcx.mir_coroutine_witnesses(def_id)
@@ -2234,6 +2243,9 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
22342243

22352244
let reachable_set = tcx.reachable_set(());
22362245
par_for_each_in(tcx.mir_keys(()), |&&def_id| {
2246+
if tcx.is_trivial_const(def_id) {
2247+
return;
2248+
}
22372249
let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
22382250

22392251
if encode_const {

compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
2929
use rustc_middle::middle::lib_features::FeatureStability;
3030
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
3131
use rustc_middle::mir;
32+
use rustc_middle::mir::ConstValue;
3233
use rustc_middle::ty::fast_reject::SimplifiedType;
3334
use rustc_middle::ty::{self, Ty, TyCtxt, UnusedGenericParams};
3435
use rustc_middle::util::Providers;
@@ -426,6 +427,7 @@ define_tables! {
426427
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
427428
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
428429
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
430+
trivial_const: Table<DefIndex, LazyValue<(ConstValue, Ty<'static>)>>,
429431
closure_saved_names_of_captured_variables: Table<DefIndex, LazyValue<IndexVec<FieldIdx, Symbol>>>,
430432
mir_coroutine_witnesses: Table<DefIndex, LazyValue<mir::CoroutineLayout<'static>>>,
431433
promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,

compiler/rustc_metadata/src/rmeta/parameterized.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ trivially_parameterized_over_tcx! {
102102
rustc_middle::middle::lib_features::FeatureStability,
103103
rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault,
104104
rustc_middle::mir::ConstQualifs,
105+
rustc_middle::mir::ConstValue,
105106
rustc_middle::ty::AnonConstKind,
106107
rustc_middle::ty::AssocContainer,
107108
rustc_middle::ty::AsyncDestructor,

compiler/rustc_middle/src/mir/graphviz.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ where
1616

1717
let mirs = def_ids
1818
.iter()
19+
.filter(|def_id| !tcx.is_trivial_const(*def_id))
1920
.flat_map(|def_id| {
2021
if tcx.is_const_fn(*def_id) {
2122
vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]

compiler/rustc_middle/src/mir/pretty.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,16 @@ pub fn write_mir_pretty<'tcx>(
353353
// are shared between mir_for_ctfe and optimized_mir
354354
writer.write_mir_fn(tcx.mir_for_ctfe(def_id), w)?;
355355
} else {
356-
let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id));
357-
render_body(w, instance_mir)?;
356+
if let Some((val, ty)) = tcx.trivial_const(def_id) {
357+
ty::print::with_forced_impl_filename_line! {
358+
// see notes on #41697 elsewhere
359+
write!(w, "const {}", tcx.def_path_str(def_id))?
360+
}
361+
writeln!(w, ": {} = const {};", ty, Const::Val(val, ty))?;
362+
} else {
363+
let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id));
364+
render_body(w, instance_mir)?;
365+
}
358366
}
359367
}
360368
Ok(())

compiler/rustc_middle/src/query/erase.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ impl EraseType for Result<mir::ConstValue, mir::interpret::ErrorHandled> {
160160
type Result = [u8; size_of::<Result<mir::ConstValue, mir::interpret::ErrorHandled>>()];
161161
}
162162

163+
impl EraseType for Option<(mir::ConstValue, Ty<'_>)> {
164+
type Result = [u8; size_of::<Option<(mir::ConstValue, Ty<'_>)>>()];
165+
}
166+
163167
impl EraseType for EvalToValTreeResult<'_> {
164168
type Result = [u8; size_of::<EvalToValTreeResult<'static>>()];
165169
}

compiler/rustc_middle/src/query/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2719,6 +2719,12 @@ rustc_queries! {
27192719
separate_provide_extern
27202720
}
27212721

2722+
query trivial_const(def_id: DefId) -> Option<(mir::ConstValue, Ty<'tcx>)> {
2723+
desc { |tcx| "checking if `{}` is a trivial const", tcx.def_path_str(def_id) }
2724+
cache_on_disk_if { def_id.is_local() }
2725+
separate_provide_extern
2726+
}
2727+
27222728
/// Checks for the nearest `#[sanitize(xyz = "off")]` or
27232729
/// `#[sanitize(xyz = "on")]` on this def and any enclosing defs, up to the
27242730
/// crate root.

0 commit comments

Comments
 (0)