Skip to content

Commit 393db2d

Browse files
[WIP] Move MIR towards a single kind of local
1 parent 205dac9 commit 393db2d

33 files changed

+625
-658
lines changed

src/librustc/mir/repr.rs

Lines changed: 139 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -70,24 +70,26 @@ pub struct Mir<'tcx> {
7070

7171
/// Rvalues promoted from this function, such as borrows of constants.
7272
/// Each of them is the Mir of a constant with the fn's type parameters
73-
/// in scope, but no vars or args and a separate set of temps.
73+
/// in scope, but a separate set of locals.
7474
pub promoted: IndexVec<Promoted, Mir<'tcx>>,
7575

7676
/// Return type of the function.
7777
pub return_ty: Ty<'tcx>,
7878

79-
/// Variables: these are stack slots corresponding to user variables. They may be
80-
/// assigned many times.
81-
pub var_decls: IndexVec<Var, VarDecl<'tcx>>,
82-
83-
/// Args: these are stack slots corresponding to the input arguments.
84-
pub arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
79+
/// Declarations of locals.
80+
///
81+
/// The first local is the return value pointer, followed by `arg_count`
82+
/// locals for the function arguments, followed by any user-declared
83+
/// variables and temporaries.
84+
pub local_decls: IndexVec<Local, LocalDecl<'tcx>>,
8585

86-
/// Temp declarations: stack slots that for temporaries created by
87-
/// the compiler. These are assigned once, but they are not SSA
88-
/// values in that it is possible to borrow them and mutate them
89-
/// through the resulting reference.
90-
pub temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
86+
/// Number of arguments this function takes.
87+
///
88+
/// Starting at local1, `arg_count` locals will be provided by the caller
89+
/// and can be assumed to be initialized.
90+
///
91+
/// If this MIR was built for a constant, this will be 0.
92+
pub arg_count: usize,
9193

9294
/// Names and capture modes of all the closure upvars, assuming
9395
/// the first argument is either the closure or a reference to it.
@@ -114,20 +116,23 @@ impl<'tcx> Mir<'tcx> {
114116
visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
115117
promoted: IndexVec<Promoted, Mir<'tcx>>,
116118
return_ty: Ty<'tcx>,
117-
var_decls: IndexVec<Var, VarDecl<'tcx>>,
118-
arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
119-
temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
119+
local_decls: IndexVec<Local, LocalDecl<'tcx>>,
120+
arg_count: usize,
120121
upvar_decls: Vec<UpvarDecl>,
121122
span: Span) -> Self
122123
{
124+
// We need `arg_count` locals, and one for the return pointer
125+
assert!(local_decls.len() >= arg_count + 1,
126+
"expected at least {} locals, got {}", arg_count + 1, local_decls.len());
127+
assert_eq!(local_decls[RETURN_POINTER].ty, return_ty);
128+
123129
Mir {
124130
basic_blocks: basic_blocks,
125131
visibility_scopes: visibility_scopes,
126132
promoted: promoted,
127133
return_ty: return_ty,
128-
var_decls: var_decls,
129-
arg_decls: arg_decls,
130-
temp_decls: temp_decls,
134+
local_decls: local_decls,
135+
arg_count: arg_count,
131136
upvar_decls: upvar_decls,
132137
spread_last_arg: false,
133138
span: span,
@@ -161,56 +166,63 @@ impl<'tcx> Mir<'tcx> {
161166
dominators(self)
162167
}
163168

164-
/// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
165-
/// to their index in the whole list of locals. This is useful if you
166-
/// want to treat all locals the same instead of repeating yourself.
167-
pub fn local_index(&self, lvalue: &Lvalue<'tcx>) -> Option<Local> {
168-
let idx = match *lvalue {
169-
Lvalue::Arg(arg) => arg.index(),
170-
Lvalue::Var(var) => {
171-
self.arg_decls.len() +
172-
var.index()
173-
}
174-
Lvalue::Temp(temp) => {
175-
self.arg_decls.len() +
176-
self.var_decls.len() +
177-
temp.index()
169+
#[inline]
170+
pub fn local_kind(&self, local: Local) -> LocalKind {
171+
let index = local.0 as usize;
172+
if index == 0 {
173+
debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
174+
"return pointer should be mutable");
175+
176+
LocalKind::ReturnPointer
177+
} else if index < self.arg_count + 1 {
178+
LocalKind::Arg
179+
} else if self.local_decls[local].name.is_some() {
180+
LocalKind::Var
181+
} else {
182+
debug_assert!(self.local_decls[local].mutability == Mutability::Mut,
183+
"temp should be mutable");
184+
185+
LocalKind::Temp
186+
}
187+
}
188+
189+
/// Returns an iterator over all temporaries.
190+
#[inline]
191+
pub fn temp_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
192+
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
193+
let local = Local::new(index);
194+
if self.local_decls[local].source_info.is_none() {
195+
Some(local)
196+
} else {
197+
None
178198
}
179-
Lvalue::ReturnPointer => {
180-
self.arg_decls.len() +
181-
self.var_decls.len() +
182-
self.temp_decls.len()
199+
})
200+
}
201+
202+
/// Returns an iterator over all user-declared locals.
203+
#[inline]
204+
pub fn var_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
205+
(self.arg_count+1..self.local_decls.len()).filter_map(move |index| {
206+
let local = Local::new(index);
207+
if self.local_decls[local].source_info.is_none() {
208+
None
209+
} else {
210+
Some(local)
183211
}
184-
Lvalue::Static(_) |
185-
Lvalue::Projection(_) => return None
186-
};
187-
Some(Local::new(idx))
212+
})
188213
}
189214

190-
/// Counts the number of locals, such that local_index
191-
/// will always return an index smaller than this count.
192-
pub fn count_locals(&self) -> usize {
193-
self.arg_decls.len() +
194-
self.var_decls.len() +
195-
self.temp_decls.len() + 1
215+
/// Returns an iterator over all function arguments.
216+
#[inline]
217+
pub fn arg_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
218+
(1..self.arg_count+1).map(Local::new)
196219
}
197220

198-
pub fn format_local(&self, local: Local) -> String {
199-
let mut index = local.index();
200-
index = match index.checked_sub(self.arg_decls.len()) {
201-
None => return format!("{:?}", Arg::new(index)),
202-
Some(index) => index,
203-
};
204-
index = match index.checked_sub(self.var_decls.len()) {
205-
None => return format!("{:?}", Var::new(index)),
206-
Some(index) => index,
207-
};
208-
index = match index.checked_sub(self.temp_decls.len()) {
209-
None => return format!("{:?}", Temp::new(index)),
210-
Some(index) => index,
211-
};
212-
debug_assert!(index == 0);
213-
return "ReturnPointer".to_string()
221+
/// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
222+
/// locals that are neither arguments nor the return pointer).
223+
#[inline]
224+
pub fn var_and_temp_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a {
225+
(self.arg_count+1..self.local_decls.len()).map(Local::new)
214226
}
215227

216228
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -308,49 +320,76 @@ pub enum BorrowKind {
308320
///////////////////////////////////////////////////////////////////////////
309321
// Variables and temps
310322

311-
/// A "variable" is a binding declared by the user as part of the fn
312-
/// decl, a let, etc.
323+
newtype_index!(Local, "local");
324+
325+
pub const RETURN_POINTER: Local = Local(0);
326+
327+
/// Classifies locals into categories. See `Mir::local_kind`.
328+
#[derive(PartialEq, Eq, Debug)]
329+
pub enum LocalKind {
330+
/// User-declared variable binding
331+
Var,
332+
/// Compiler-introduced temporary
333+
Temp,
334+
/// Function argument
335+
Arg,
336+
/// Location of function's return value
337+
ReturnPointer,
338+
}
339+
340+
/// A MIR local.
341+
///
342+
/// This can be a binding declared by the user, a temporary inserted by the compiler, a function
343+
/// argument, or the return pointer.
313344
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
314-
pub struct VarDecl<'tcx> {
315-
/// `let mut x` vs `let x`
345+
pub struct LocalDecl<'tcx> {
346+
/// `let mut x` vs `let x`.
347+
///
348+
/// Temporaries and the return pointer are always mutable.
316349
pub mutability: Mutability,
317350

318-
/// name that user gave the variable; not that, internally,
319-
/// mir references variables by index
320-
pub name: Name,
321-
322-
/// type inferred for this variable (`let x: ty = ...`)
351+
/// Type of this local.
323352
pub ty: Ty<'tcx>,
324353

325-
/// source information (span, scope, etc.) for the declaration
326-
pub source_info: SourceInfo,
327-
}
354+
/// Name of the local, used in debuginfo and pretty-printing.
355+
///
356+
/// Note that function arguments can also have this set to `Some(_)`
357+
/// to generate better debuginfo.
358+
pub name: Option<Name>,
328359

329-
/// A "temp" is a temporary that we place on the stack. They are
330-
/// anonymous, always mutable, and have only a type.
331-
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
332-
pub struct TempDecl<'tcx> {
333-
pub ty: Ty<'tcx>,
360+
/// For user-declared variables, stores their source information.
361+
///
362+
/// For temporaries, this is `None`.
363+
///
364+
/// This is the primary way to differentiate between user-declared
365+
/// variables and compiler-generated temporaries.
366+
pub source_info: Option<SourceInfo>,
334367
}
335368

336-
/// A "arg" is one of the function's formal arguments. These are
337-
/// anonymous and distinct from the bindings that the user declares.
338-
///
339-
/// For example, in this function:
340-
///
341-
/// ```
342-
/// fn foo((x, y): (i32, u32)) { ... }
343-
/// ```
344-
///
345-
/// there is only one argument, of type `(i32, u32)`, but two bindings
346-
/// (`x` and `y`).
347-
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
348-
pub struct ArgDecl<'tcx> {
349-
pub ty: Ty<'tcx>,
369+
impl<'tcx> LocalDecl<'tcx> {
370+
/// Create a new `LocalDecl` for a temporary.
371+
#[inline]
372+
pub fn new_temp(ty: Ty<'tcx>) -> Self {
373+
LocalDecl {
374+
mutability: Mutability::Mut,
375+
ty: ty,
376+
name: None,
377+
source_info: None,
378+
}
379+
}
350380

351-
/// Either keywords::Invalid or the name of a single-binding
352-
/// pattern associated with this argument. Useful for debuginfo.
353-
pub debug_name: Name
381+
/// Builds a `LocalDecl` for the return pointer.
382+
///
383+
/// This must be inserted into the `local_decls` list as the first local.
384+
#[inline]
385+
pub fn new_return_pointer(return_ty: Ty) -> LocalDecl {
386+
LocalDecl {
387+
mutability: Mutability::Mut,
388+
ty: return_ty,
389+
source_info: None,
390+
name: None, // FIXME maybe we do want some name here?
391+
}
392+
}
354393
}
355394

356395
/// A closure capture, with its name and mode.
@@ -442,7 +481,7 @@ pub enum TerminatorKind<'tcx> {
442481
/// continue. Emitted by build::scope::diverge_cleanup.
443482
Resume,
444483

445-
/// Indicates a normal return. The ReturnPointer lvalue should
484+
/// Indicates a normal return. The return pointer lvalue should
446485
/// have been filled in by now. This should occur at most once.
447486
Return,
448487

@@ -759,31 +798,16 @@ impl<'tcx> Debug for Statement<'tcx> {
759798
///////////////////////////////////////////////////////////////////////////
760799
// Lvalues
761800

762-
newtype_index!(Var, "var");
763-
newtype_index!(Temp, "tmp");
764-
newtype_index!(Arg, "arg");
765-
newtype_index!(Local, "local");
766-
767801
/// A path to a value; something that can be evaluated without
768802
/// changing or disturbing program state.
769803
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
770804
pub enum Lvalue<'tcx> {
771-
/// local variable declared by the user
772-
Var(Var),
773-
774-
/// temporary introduced during lowering into MIR
775-
Temp(Temp),
776-
777-
/// formal parameter of the function; note that these are NOT the
778-
/// bindings that the user declares, which are vars
779-
Arg(Arg),
805+
/// local variable
806+
Local(Local),
780807

781808
/// static or static mut variable
782809
Static(DefId),
783810

784-
/// the return pointer of the fn
785-
ReturnPointer,
786-
787811
/// projection out of an lvalue (access a field, deref a pointer, etc)
788812
Projection(Box<LvalueProjection<'tcx>>),
789813
}
@@ -865,38 +889,16 @@ impl<'tcx> Lvalue<'tcx> {
865889
elem: elem,
866890
}))
867891
}
868-
869-
pub fn from_local(mir: &Mir<'tcx>, local: Local) -> Lvalue<'tcx> {
870-
let mut index = local.index();
871-
index = match index.checked_sub(mir.arg_decls.len()) {
872-
None => return Lvalue::Arg(Arg(index as u32)),
873-
Some(index) => index,
874-
};
875-
index = match index.checked_sub(mir.var_decls.len()) {
876-
None => return Lvalue::Var(Var(index as u32)),
877-
Some(index) => index,
878-
};
879-
index = match index.checked_sub(mir.temp_decls.len()) {
880-
None => return Lvalue::Temp(Temp(index as u32)),
881-
Some(index) => index,
882-
};
883-
debug_assert!(index == 0);
884-
Lvalue::ReturnPointer
885-
}
886892
}
887893

888894
impl<'tcx> Debug for Lvalue<'tcx> {
889895
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
890896
use self::Lvalue::*;
891897

892898
match *self {
893-
Var(id) => write!(fmt, "{:?}", id),
894-
Arg(id) => write!(fmt, "{:?}", id),
895-
Temp(id) => write!(fmt, "{:?}", id),
899+
Local(id) => write!(fmt, "{:?}", id),
896900
Static(def_id) =>
897901
write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))),
898-
ReturnPointer =>
899-
write!(fmt, "return"),
900902
Projection(ref data) =>
901903
match data.elem {
902904
ProjectionElem::Downcast(ref adt_def, index) =>

0 commit comments

Comments
 (0)