-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Description
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:
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:
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 nowCopy
, which is always nice- You can figure out very quickly that
a.b.c
is disjoint fromd.e.f
- Right now we have to use these
unroll_place
calls
- Right now we have to use these
And it is a building block, I think, for other improvements to NLL performance.
cc @eddyb