@@ -70,29 +70,37 @@ pub struct Mir<'tcx> {
70
70
71
71
/// Rvalues promoted from this function, such as borrows of constants.
72
72
/// 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 .
74
74
pub promoted : IndexVec < Promoted , Mir < ' tcx > > ,
75
75
76
76
/// Return type of the function.
77
77
pub return_ty : Ty < ' tcx > ,
78
78
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 > > ,
85
85
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 local 1, `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 ,
91
93
92
94
/// Names and capture modes of all the closure upvars, assuming
93
95
/// the first argument is either the closure or a reference to it.
94
96
pub upvar_decls : Vec < UpvarDecl > ,
95
97
98
+ /// Mark an argument local (which must be a tuple) as getting passed as
99
+ /// its individual components at the LLVM level.
100
+ ///
101
+ /// This is used for the "rust-call" ABI.
102
+ pub spread_arg : Option < Local > ,
103
+
96
104
/// A span representing this MIR, for error reporting
97
105
pub span : Span ,
98
106
@@ -108,21 +116,25 @@ impl<'tcx> Mir<'tcx> {
108
116
visibility_scopes : IndexVec < VisibilityScope , VisibilityScopeData > ,
109
117
promoted : IndexVec < Promoted , Mir < ' tcx > > ,
110
118
return_ty : Ty < ' tcx > ,
111
- var_decls : IndexVec < Var , VarDecl < ' tcx > > ,
112
- arg_decls : IndexVec < Arg , ArgDecl < ' tcx > > ,
113
- temp_decls : IndexVec < Temp , TempDecl < ' tcx > > ,
119
+ local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
120
+ arg_count : usize ,
114
121
upvar_decls : Vec < UpvarDecl > ,
115
122
span : Span ) -> Self
116
123
{
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
+
117
129
Mir {
118
130
basic_blocks : basic_blocks,
119
131
visibility_scopes : visibility_scopes,
120
132
promoted : promoted,
121
133
return_ty : return_ty,
122
- var_decls : var_decls,
123
- arg_decls : arg_decls,
124
- temp_decls : temp_decls,
134
+ local_decls : local_decls,
135
+ arg_count : arg_count,
125
136
upvar_decls : upvar_decls,
137
+ spread_arg : None ,
126
138
span : span,
127
139
cache : Cache :: new ( )
128
140
}
@@ -154,56 +166,66 @@ impl<'tcx> Mir<'tcx> {
154
166
dominators ( self )
155
167
}
156
168
157
- /// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
158
- /// to their index in the whole list of locals. This is useful if you
159
- /// want to treat all locals the same instead of repeating yourself.
160
- pub fn local_index ( & self , lvalue : & Lvalue < ' tcx > ) -> Option < Local > {
161
- let idx = match * lvalue {
162
- Lvalue :: Arg ( arg) => arg. index ( ) ,
163
- Lvalue :: Var ( var) => {
164
- self . arg_decls . len ( ) +
165
- var. index ( )
166
- }
167
- Lvalue :: Temp ( temp) => {
168
- self . arg_decls . len ( ) +
169
- self . var_decls . len ( ) +
170
- 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 temps_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
171
198
}
172
- Lvalue :: ReturnPointer => {
173
- self . arg_decls . len ( ) +
174
- self . var_decls . len ( ) +
175
- self . temp_decls . len ( )
199
+ } )
200
+ }
201
+
202
+ /// Returns an iterator over all user-declared locals.
203
+ #[ inline]
204
+ pub fn vars_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)
176
211
}
177
- Lvalue :: Static ( _) |
178
- Lvalue :: Projection ( _) => return None
179
- } ;
180
- Some ( Local :: new ( idx) )
212
+ } )
181
213
}
182
214
183
- /// Counts the number of locals, such that local_index
184
- /// will always return an index smaller than this count.
185
- pub fn count_locals ( & self ) -> usize {
186
- self . arg_decls . len ( ) +
187
- self . var_decls . len ( ) +
188
- self . temp_decls . len ( ) + 1
215
+ /// Returns an iterator over all function arguments.
216
+ #[ inline]
217
+ pub fn args_iter ( & self ) -> impl Iterator < Item =Local > {
218
+ let arg_count = self . arg_count ;
219
+ ( 1 ..arg_count+1 ) . map ( Local :: new)
189
220
}
190
221
191
- pub fn format_local ( & self , local : Local ) -> String {
192
- let mut index = local. index ( ) ;
193
- index = match index. checked_sub ( self . arg_decls . len ( ) ) {
194
- None => return format ! ( "{:?}" , Arg :: new( index) ) ,
195
- Some ( index) => index,
196
- } ;
197
- index = match index. checked_sub ( self . var_decls . len ( ) ) {
198
- None => return format ! ( "{:?}" , Var :: new( index) ) ,
199
- Some ( index) => index,
200
- } ;
201
- index = match index. checked_sub ( self . temp_decls . len ( ) ) {
202
- None => return format ! ( "{:?}" , Temp :: new( index) ) ,
203
- Some ( index) => index,
204
- } ;
205
- debug_assert ! ( index == 0 ) ;
206
- return "ReturnPointer" . to_string ( )
222
+ /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all
223
+ /// locals that are neither arguments nor the return pointer).
224
+ #[ inline]
225
+ pub fn vars_and_temps_iter ( & self ) -> impl Iterator < Item =Local > {
226
+ let arg_count = self . arg_count ;
227
+ let local_count = self . local_decls . len ( ) ;
228
+ ( arg_count+1 ..local_count) . map ( Local :: new)
207
229
}
208
230
209
231
/// Changes a statement to a nop. This is both faster than deleting instructions and avoids
@@ -301,53 +323,76 @@ pub enum BorrowKind {
301
323
///////////////////////////////////////////////////////////////////////////
302
324
// Variables and temps
303
325
304
- /// A "variable" is a binding declared by the user as part of the fn
305
- /// decl, a let, etc.
306
- #[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
307
- pub struct VarDecl < ' tcx > {
308
- /// `let mut x` vs `let x`
309
- pub mutability : Mutability ,
310
-
311
- /// name that user gave the variable; not that, internally,
312
- /// mir references variables by index
313
- pub name : Name ,
326
+ newtype_index ! ( Local , "_" ) ;
314
327
315
- /// type inferred for this variable (`let x: ty = ...`)
316
- pub ty : Ty < ' tcx > ,
328
+ pub const RETURN_POINTER : Local = Local ( 0 ) ;
317
329
318
- /// source information (span, scope, etc.) for the declaration
319
- pub source_info : SourceInfo ,
320
- }
321
-
322
- /// A "temp" is a temporary that we place on the stack. They are
323
- /// anonymous, always mutable, and have only a type.
324
- #[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
325
- pub struct TempDecl < ' tcx > {
326
- pub ty : Ty < ' tcx > ,
330
+ /// Classifies locals into categories. See `Mir::local_kind`.
331
+ #[ derive( PartialEq , Eq , Debug ) ]
332
+ pub enum LocalKind {
333
+ /// User-declared variable binding
334
+ Var ,
335
+ /// Compiler-introduced temporary
336
+ Temp ,
337
+ /// Function argument
338
+ Arg ,
339
+ /// Location of function's return value
340
+ ReturnPointer ,
327
341
}
328
342
329
- /// A "arg" is one of the function's formal arguments. These are
330
- /// anonymous and distinct from the bindings that the user declares.
331
- ///
332
- /// For example, in this function:
333
- ///
334
- /// ```
335
- /// fn foo((x, y): (i32, u32)) { ... }
336
- /// ```
343
+ /// A MIR local.
337
344
///
338
- /// there is only one argument, of type `(i32, u32)`, but two bindings
339
- /// (`x` and `y`) .
345
+ /// This can be a binding declared by the user, a temporary inserted by the compiler, a function
346
+ /// argument, or the return pointer .
340
347
#[ derive( Clone , Debug , RustcEncodable , RustcDecodable ) ]
341
- pub struct ArgDecl < ' tcx > {
348
+ pub struct LocalDecl < ' tcx > {
349
+ /// `let mut x` vs `let x`.
350
+ ///
351
+ /// Temporaries and the return pointer are always mutable.
352
+ pub mutability : Mutability ,
353
+
354
+ /// Type of this local.
342
355
pub ty : Ty < ' tcx > ,
343
356
344
- /// If true, this argument is a tuple after monomorphization,
345
- /// and has to be collected from multiple actual arguments.
346
- pub spread : bool ,
357
+ /// Name of the local, used in debuginfo and pretty-printing.
358
+ ///
359
+ /// Note that function arguments can also have this set to `Some(_)`
360
+ /// to generate better debuginfo.
361
+ pub name : Option < Name > ,
347
362
348
- /// Either keywords::Invalid or the name of a single-binding
349
- /// pattern associated with this argument. Useful for debuginfo.
350
- pub debug_name : Name
363
+ /// For user-declared variables, stores their source information.
364
+ ///
365
+ /// For temporaries, this is `None`.
366
+ ///
367
+ /// This is the primary way to differentiate between user-declared
368
+ /// variables and compiler-generated temporaries.
369
+ pub source_info : Option < SourceInfo > ,
370
+ }
371
+
372
+ impl < ' tcx > LocalDecl < ' tcx > {
373
+ /// Create a new `LocalDecl` for a temporary.
374
+ #[ inline]
375
+ pub fn new_temp ( ty : Ty < ' tcx > ) -> Self {
376
+ LocalDecl {
377
+ mutability : Mutability :: Mut ,
378
+ ty : ty,
379
+ name : None ,
380
+ source_info : None ,
381
+ }
382
+ }
383
+
384
+ /// Builds a `LocalDecl` for the return pointer.
385
+ ///
386
+ /// This must be inserted into the `local_decls` list as the first local.
387
+ #[ inline]
388
+ pub fn new_return_pointer ( return_ty : Ty ) -> LocalDecl {
389
+ LocalDecl {
390
+ mutability : Mutability :: Mut ,
391
+ ty : return_ty,
392
+ source_info : None ,
393
+ name : None , // FIXME maybe we do want some name here?
394
+ }
395
+ }
351
396
}
352
397
353
398
/// A closure capture, with its name and mode.
@@ -439,7 +484,7 @@ pub enum TerminatorKind<'tcx> {
439
484
/// continue. Emitted by build::scope::diverge_cleanup.
440
485
Resume ,
441
486
442
- /// Indicates a normal return. The ReturnPointer lvalue should
487
+ /// Indicates a normal return. The return pointer lvalue should
443
488
/// have been filled in by now. This should occur at most once.
444
489
Return ,
445
490
@@ -756,31 +801,16 @@ impl<'tcx> Debug for Statement<'tcx> {
756
801
///////////////////////////////////////////////////////////////////////////
757
802
// Lvalues
758
803
759
- newtype_index ! ( Var , "var" ) ;
760
- newtype_index ! ( Temp , "tmp" ) ;
761
- newtype_index ! ( Arg , "arg" ) ;
762
- newtype_index ! ( Local , "local" ) ;
763
-
764
804
/// A path to a value; something that can be evaluated without
765
805
/// changing or disturbing program state.
766
806
#[ derive( Clone , PartialEq , RustcEncodable , RustcDecodable ) ]
767
807
pub enum Lvalue < ' tcx > {
768
- /// local variable declared by the user
769
- Var ( Var ) ,
770
-
771
- /// temporary introduced during lowering into MIR
772
- Temp ( Temp ) ,
773
-
774
- /// formal parameter of the function; note that these are NOT the
775
- /// bindings that the user declares, which are vars
776
- Arg ( Arg ) ,
808
+ /// local variable
809
+ Local ( Local ) ,
777
810
778
811
/// static or static mut variable
779
812
Static ( DefId ) ,
780
813
781
- /// the return pointer of the fn
782
- ReturnPointer ,
783
-
784
814
/// projection out of an lvalue (access a field, deref a pointer, etc)
785
815
Projection ( Box < LvalueProjection < ' tcx > > ) ,
786
816
}
@@ -862,38 +892,16 @@ impl<'tcx> Lvalue<'tcx> {
862
892
elem : elem,
863
893
} ) )
864
894
}
865
-
866
- pub fn from_local ( mir : & Mir < ' tcx > , local : Local ) -> Lvalue < ' tcx > {
867
- let mut index = local. index ( ) ;
868
- index = match index. checked_sub ( mir. arg_decls . len ( ) ) {
869
- None => return Lvalue :: Arg ( Arg ( index as u32 ) ) ,
870
- Some ( index) => index,
871
- } ;
872
- index = match index. checked_sub ( mir. var_decls . len ( ) ) {
873
- None => return Lvalue :: Var ( Var ( index as u32 ) ) ,
874
- Some ( index) => index,
875
- } ;
876
- index = match index. checked_sub ( mir. temp_decls . len ( ) ) {
877
- None => return Lvalue :: Temp ( Temp ( index as u32 ) ) ,
878
- Some ( index) => index,
879
- } ;
880
- debug_assert ! ( index == 0 ) ;
881
- Lvalue :: ReturnPointer
882
- }
883
895
}
884
896
885
897
impl < ' tcx > Debug for Lvalue < ' tcx > {
886
898
fn fmt ( & self , fmt : & mut Formatter ) -> fmt:: Result {
887
899
use self :: Lvalue :: * ;
888
900
889
901
match * self {
890
- Var ( id) => write ! ( fmt, "{:?}" , id) ,
891
- Arg ( id) => write ! ( fmt, "{:?}" , id) ,
892
- Temp ( id) => write ! ( fmt, "{:?}" , id) ,
902
+ Local ( id) => write ! ( fmt, "{:?}" , id) ,
893
903
Static ( def_id) =>
894
904
write ! ( fmt, "{}" , ty:: tls:: with( |tcx| tcx. item_path_str( def_id) ) ) ,
895
- ReturnPointer =>
896
- write ! ( fmt, "return" ) ,
897
905
Projection ( ref data) =>
898
906
match data. elem {
899
907
ProjectionElem :: Downcast ( ref adt_def, index) =>
0 commit comments