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