Skip to content

change how MIR represents places #52708

Closed
@nikomatsakis

Description

@nikomatsakis

For efficiency reasons, but also others, it would be nice to change how MIR represents the Place data structure. Right now we have a tree-like structure:

rust/src/librustc/mir/mod.rs

Lines 1694 to 1709 in fefe816

/// A path to a value; something that can be evaluated without
/// changing or disturbing program state.
#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum Place<'tcx> {
/// local variable
Local(Local),
/// static or static mut variable
Static(Box<Static<'tcx>>),
/// Constant code promoted to an injected static
Promoted(Box<(Promoted, Ty<'tcx>)>),
/// projection out of a place (access a field, deref a pointer, etc)
Projection(Box<PlaceProjection<'tcx>>),
}

But this is not the most convenient and it can be an efficiency hazard. Instead, I propose a structure like this (inspired by something @eddyb said, and I imagine that they will have suggestions too):

struct Place<'tcx> {
    base: PlaceBase<'tcx>,
    elem: &'tcx Slice<ProjectionElem<'tcx>>,
}

enum PlaceBase<'tcx> {
    /// local variable
    Local(Local),

    /// static or static mut variable
    Static(Box<Static<'tcx>>),

    /// Constant code promoted to an injected static
    Promoted(Box<(Promoted, Ty<'tcx>)>),
}

where ProjectionElem is basically the same type as today:

rust/src/librustc/mir/mod.rs

Lines 1734 to 1770 in fefe816

#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum ProjectionElem<'tcx, V, T> {
Deref,
Field(Field, T),
Index(V),
/// These indices are generated by slice patterns. Easiest to explain
/// by example:
///
/// ```
/// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false },
/// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false },
/// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true },
/// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true },
/// ```
ConstantIndex {
/// index or -index (in Python terms), depending on from_end
offset: u32,
/// thing being indexed must be at least this long
min_length: u32,
/// counting backwards from end?
from_end: bool,
},
/// These indices are generated by slice patterns.
///
/// slice[from:-to] in Python terms.
Subslice {
from: u32,
to: u32,
},
/// "Downcast" to a variant of an ADT. Currently, we only introduce
/// this for ADTs with more than one variant. It may be better to
/// just introduce it always, or always for enums.
Downcast(&'tcx AdtDef, usize),
}

In other words, instead of representing a.b.c as

  • .c
    • .b
      • .a

we would represent it as (a, [b, c]) (here, [b, c] would be an interned slice).

The advantages of this setup:

  • Place is now Copy, which is always nice
  • You can figure out very quickly that a.b.c is disjoint from d.e.f

And it is a building block, I think, for other improvements to NLL performance.

cc @eddyb

Metadata

Metadata

Labels

A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlP-mediumMedium priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.WG-compiler-performanceWorking group: Compiler Performance

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions