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:
|
/// 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:
|
#[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
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
For efficiency reasons, but also others, it would be nice to change how MIR represents the
Placedata structure. Right now we have a tree-like structure:rust/src/librustc/mir/mod.rs
Lines 1694 to 1709 in fefe816
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):
where
ProjectionElemis basically the same type as today:rust/src/librustc/mir/mod.rs
Lines 1734 to 1770 in fefe816
In other words, instead of representing
a.b.cas.c.b.awe would represent it as
(a, [b, c])(here,[b, c]would be an interned slice).The advantages of this setup:
Placeis nowCopy, which is always nicea.b.cis disjoint fromd.e.funroll_placecallsAnd it is a building block, I think, for other improvements to NLL performance.
cc @eddyb