Skip to content

Commit d87385f

Browse files
authored
Rollup merge of rust-lang#57677 - dotdash:locals, r=michaelwoerister
const_eval: Predetermine the layout of all locals when pushing a stack frame Usually the layout of any locals is required at least three times, once when it becomes live, once when it is written to, and once it is read from. By adding a cache for them, we can reduce the number of layout queries speeding up code that is heavy on const_eval.
2 parents d29a1bc + 98d4f33 commit d87385f

File tree

4 files changed

+24
-18
lines changed

4 files changed

+24
-18
lines changed

src/librustc_mir/const_eval.rs

+1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ fn mk_eval_cx_inner<'a, 'mir, 'tcx>(
7272
ecx.stack.push(interpret::Frame {
7373
block: mir::START_BLOCK,
7474
locals: IndexVec::new(),
75+
local_layouts: IndexVec::new(),
7576
instance,
7677
span,
7778
mir,

src/librustc_mir/interpret/eval_context.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::cell::Cell;
12
use std::fmt::Write;
23
use std::mem;
34

@@ -76,6 +77,7 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
7677
/// `None` represents a local that is currently dead, while a live local
7778
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
7879
pub locals: IndexVec<mir::Local, LocalValue<Tag>>,
80+
pub local_layouts: IndexVec<mir::Local, Cell<Option<TyLayout<'tcx>>>>,
7981

8082
////////////////////////////////////////////////////////////////////////////////
8183
// Current position within the function
@@ -290,9 +292,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
290292
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
291293
local: mir::Local
292294
) -> EvalResult<'tcx, TyLayout<'tcx>> {
293-
let local_ty = frame.mir.local_decls[local].ty;
294-
let local_ty = self.monomorphize(local_ty, frame.instance.substs);
295-
self.layout_of(local_ty)
295+
let cell = &frame.local_layouts[local];
296+
if cell.get().is_none() {
297+
let local_ty = frame.mir.local_decls[local].ty;
298+
let local_ty = self.monomorphize(local_ty, frame.instance.substs);
299+
let layout = self.layout_of(local_ty)?;
300+
cell.set(Some(layout));
301+
}
302+
303+
Ok(cell.get().unwrap())
296304
}
297305

298306
pub fn str_to_immediate(&mut self, s: &str) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
@@ -426,6 +434,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
426434
// empty local array, we fill it in below, after we are inside the stack frame and
427435
// all methods actually know about the frame
428436
locals: IndexVec::new(),
437+
local_layouts: IndexVec::from_elem_n(Default::default(), mir.local_decls.len()),
429438
span,
430439
instance,
431440
stmt: 0,
@@ -464,11 +473,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
464473
},
465474
}
466475
// Finally, properly initialize all those that still have the dummy value
467-
for (local, decl) in locals.iter_mut().zip(mir.local_decls.iter()) {
476+
for (idx, local) in locals.iter_enumerated_mut() {
468477
match *local {
469478
LocalValue::Live(_) => {
470479
// This needs to be peoperly initialized.
471-
let layout = self.layout_of(self.monomorphize(decl.ty, instance.substs))?;
480+
let layout = self.layout_of_local(self.frame(), idx)?;
472481
*local = LocalValue::Live(self.uninit_operand(layout)?);
473482
}
474483
LocalValue::Dead => {

src/librustc_mir/interpret/operand.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -457,36 +457,30 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
457457
}
458458

459459
/// This is used by [priroda](https://github.com/oli-obk/priroda) to get an OpTy from a local
460-
///
461-
/// When you know the layout of the local in advance, you can pass it as last argument
462-
pub fn access_local(
460+
fn access_local(
463461
&self,
464462
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
465463
local: mir::Local,
466-
layout: Option<TyLayout<'tcx>>,
467464
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
468465
assert_ne!(local, mir::RETURN_PLACE);
469466
let op = *frame.locals[local].access()?;
470-
let layout = from_known_layout(layout,
471-
|| self.layout_of_local(frame, local))?;
467+
let layout = self.layout_of_local(frame, local)?;
472468
Ok(OpTy { op, layout })
473469
}
474470

475471
// Evaluate a place with the goal of reading from it. This lets us sometimes
476-
// avoid allocations. If you already know the layout, you can pass it in
477-
// to avoid looking it up again.
472+
// avoid allocations.
478473
fn eval_place_to_op(
479474
&self,
480475
mir_place: &mir::Place<'tcx>,
481-
layout: Option<TyLayout<'tcx>>,
482476
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
483477
use rustc::mir::Place::*;
484478
let op = match *mir_place {
485479
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
486-
Local(local) => self.access_local(self.frame(), local, layout)?,
480+
Local(local) => self.access_local(self.frame(), local)?,
487481

488482
Projection(ref proj) => {
489-
let op = self.eval_place_to_op(&proj.base, None)?;
483+
let op = self.eval_place_to_op(&proj.base)?;
490484
self.operand_projection(op, &proj.elem)?
491485
}
492486

@@ -510,7 +504,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
510504
// FIXME: do some more logic on `move` to invalidate the old location
511505
Copy(ref place) |
512506
Move(ref place) =>
513-
self.eval_place_to_op(place, layout)?,
507+
self.eval_place_to_op(place)?,
514508

515509
Constant(ref constant) => {
516510
let layout = from_known_layout(layout, || {

src/librustc_mir/interpret/snapshot.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -314,13 +314,14 @@ struct FrameSnapshot<'a, 'tcx: 'a> {
314314
stmt: usize,
315315
}
316316

317-
impl_stable_hash_for!(impl<'tcx, 'mir: 'tcx> for struct Frame<'mir, 'tcx> {
317+
impl_stable_hash_for!(impl<'mir, 'tcx: 'mir> for struct Frame<'mir, 'tcx> {
318318
mir,
319319
instance,
320320
span,
321321
return_to_block,
322322
return_place -> (return_place.as_ref().map(|r| &**r)),
323323
locals,
324+
local_layouts -> _,
324325
block,
325326
stmt,
326327
extra,
@@ -339,6 +340,7 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
339340
return_to_block,
340341
return_place,
341342
locals,
343+
local_layouts: _,
342344
block,
343345
stmt,
344346
extra: _,

0 commit comments

Comments
 (0)