@@ -7,10 +7,9 @@ use rustc_middle::hir;
77use rustc_middle:: ich:: StableHashingContext ;
88use rustc_middle:: mir:: coverage:: * ;
99use rustc_middle:: mir:: interpret:: Scalar ;
10- use rustc_middle:: mir:: CoverageInfo ;
1110use rustc_middle:: mir:: {
12- self , traversal, BasicBlock , BasicBlockData , Operand , Place , SourceInfo , StatementKind ,
13- Terminator , TerminatorKind , START_BLOCK ,
11+ self , traversal, BasicBlock , BasicBlockData , CoverageInfo , Operand , Place , SourceInfo ,
12+ SourceScope , StatementKind , Terminator , TerminatorKind ,
1413} ;
1514use rustc_middle:: ty;
1615use rustc_middle:: ty:: query:: Providers ;
@@ -41,14 +40,14 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> Coverage
4140 tcx. require_lang_item ( lang_items:: CoverageCounterSubtractFnLangItem , None ) ;
4241
4342 // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected
44- // counters, with each counter having an index from `0..num_counters-1`. MIR optimization
43+ // counters, with each counter having a counter ID from `0..num_counters-1`. MIR optimization
4544 // may split and duplicate some BasicBlock sequences. Simply counting the calls may not
46- // not work; but computing the num_counters by adding `1` to the highest index (for a given
45+ // work; but computing the num_counters by adding `1` to the highest counter_id (for a given
4746 // instrumented function) is valid.
4847 //
4948 // `num_expressions` is the number of counter expressions added to the MIR body. Both
5049 // `num_counters` and `num_expressions` are used to initialize new vectors, during backend
51- // code generate, to lookup counters and expressions by their simple u32 indexes.
50+ // code generate, to lookup counters and expressions by simple u32 indexes.
5251 let mut num_counters: u32 = 0 ;
5352 let mut num_expressions: u32 = 0 ;
5453 for terminator in
@@ -57,27 +56,26 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> Coverage
5756 if let TerminatorKind :: Call { func : Operand :: Constant ( func) , args, .. } = & terminator. kind {
5857 match func. literal . ty . kind {
5958 FnDef ( id, _) if id == count_code_region_fn => {
60- let index_arg =
59+ let counter_id_arg =
6160 args. get ( count_code_region_args:: COUNTER_ID ) . expect ( "arg found" ) ;
62- let counter_index = mir:: Operand :: scalar_from_const ( index_arg )
61+ let counter_id = mir:: Operand :: scalar_from_const ( counter_id_arg )
6362 . to_u32 ( )
64- . expect ( "index arg is u32" ) ;
65- num_counters = std:: cmp:: max ( num_counters, counter_index + 1 ) ;
63+ . expect ( "counter_id arg is u32" ) ;
64+ num_counters = std:: cmp:: max ( num_counters, counter_id + 1 ) ;
6665 }
6766 FnDef ( id, _)
6867 if id == coverage_counter_add_fn || id == coverage_counter_subtract_fn =>
6968 {
70- let index_arg = args
69+ let expression_id_arg = args
7170 . get ( coverage_counter_expression_args:: EXPRESSION_ID )
7271 . expect ( "arg found" ) ;
73- let translated_index = mir:: Operand :: scalar_from_const ( index_arg )
72+ let id_descending_from_max = mir:: Operand :: scalar_from_const ( expression_id_arg )
7473 . to_u32 ( )
75- . expect ( "index arg is u32" ) ;
76- // Counter expressions start with "translated indexes", descending from
77- // `u32::MAX`, so the range of expression indexes is disjoint from the range of
78- // counter indexes. This way, both counters and expressions can be operands in
79- // other expressions.
80- let expression_index = u32:: MAX - translated_index;
74+ . expect ( "expression_id arg is u32" ) ;
75+ // Counter expressions are initially assigned IDs descending from `u32::MAX`, so
76+ // the range of expression IDs is disjoint from the range of counter IDs. This
77+ // way, both counters and expressions can be operands in other expressions.
78+ let expression_index = u32:: MAX - id_descending_from_max;
8179 num_expressions = std:: cmp:: max ( num_expressions, expression_index + 1 ) ;
8280 }
8381 _ => { }
@@ -97,12 +95,10 @@ fn call_terminators(data: &'tcx BasicBlockData<'tcx>) -> Option<&'tcx Terminator
9795
9896impl < ' tcx > MirPass < ' tcx > for InstrumentCoverage {
9997 fn run_pass ( & self , tcx : TyCtxt < ' tcx > , src : MirSource < ' tcx > , mir_body : & mut mir:: Body < ' tcx > ) {
100- if tcx. sess . opts . debugging_opts . instrument_coverage {
101- // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
102- // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
103- if src. promoted . is_none ( ) {
104- Instrumentor :: new ( tcx, src, mir_body) . inject_counters ( ) ;
105- }
98+ // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
99+ // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
100+ if src. promoted . is_none ( ) {
101+ Instrumentor :: new ( tcx, src, mir_body) . inject_counters ( ) ;
106102 }
107103 }
108104}
@@ -113,6 +109,12 @@ enum Op {
113109 Subtract ,
114110}
115111
112+ struct InjectedCall < ' tcx > {
113+ func : Operand < ' tcx > ,
114+ args : Vec < Operand < ' tcx > > ,
115+ inject_at : Span ,
116+ }
117+
116118struct Instrumentor < ' a , ' tcx > {
117119 tcx : TyCtxt < ' tcx > ,
118120 mir_def_id : DefId ,
@@ -147,11 +149,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
147149 }
148150
149151 /// Expression IDs start from u32::MAX and go down because a CounterExpression can reference
150- /// (add or subtract counts) of both Counter regions and CounterExpression regions. The indexes
151- /// of each type of region must be contiguous, but also must be unique across both sets.
152- /// The expression IDs are eventually translated into region indexes (starting after the last
153- /// counter index, for the given function), during backend code generation, by the helper method
154- /// `rustc_codegen_ssa::coverageinfo::map::FunctionCoverage::translate_expressions()`.
152+ /// (add or subtract counts) of both Counter regions and CounterExpression regions. The counter
153+ /// expression operand IDs must be unique across both types.
155154 fn next_expression ( & mut self ) -> u32 {
156155 assert ! ( self . num_counters < u32 :: MAX - self . num_expressions) ;
157156 let next = u32:: MAX - self . num_expressions ;
@@ -171,17 +170,25 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
171170 }
172171
173172 fn inject_counters ( & mut self ) {
173+ let mir_body = & self . mir_body ;
174174 let body_span = self . hir_body . value . span ;
175- debug ! (
176- "instrumenting {:?}, span: {}" ,
177- self . mir_def_id,
178- self . tcx. sess. source_map( ) . span_to_string( body_span)
179- ) ;
175+ debug ! ( "instrumenting {:?}, span: {:?}" , self . mir_def_id, body_span) ;
180176
181177 // FIXME(richkadel): As a first step, counters are only injected at the top of each
182178 // function. The complete solution will inject counters at each conditional code branch.
183- let next_block = START_BLOCK ;
184- self . inject_counter ( body_span, next_block) ;
179+ let _ignore = mir_body;
180+ let id = self . next_counter ( ) ;
181+ let function_source_hash = self . function_source_hash ( ) ;
182+ let code_region = body_span;
183+ let scope = rustc_middle:: mir:: OUTERMOST_SOURCE_SCOPE ;
184+ let is_cleanup = false ;
185+ let next_block = rustc_middle:: mir:: START_BLOCK ;
186+ self . inject_call (
187+ self . make_counter ( id, function_source_hash, code_region) ,
188+ scope,
189+ is_cleanup,
190+ next_block,
191+ ) ;
185192
186193 // FIXME(richkadel): The next step to implement source based coverage analysis will be
187194 // instrumenting branches within functions, and some regions will be counted by "counter
@@ -190,57 +197,68 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
190197 let fake_use = false ;
191198 if fake_use {
192199 let add = false ;
193- if add {
194- self . inject_counter_expression ( body_span, next_block, 1 , Op :: Add , 2 ) ;
195- } else {
196- self . inject_counter_expression ( body_span, next_block, 1 , Op :: Subtract , 2 ) ;
197- }
200+ let lhs = 1 ;
201+ let op = if add { Op :: Add } else { Op :: Subtract } ;
202+ let rhs = 2 ;
203+
204+ let code_region = body_span;
205+ let scope = rustc_middle:: mir:: OUTERMOST_SOURCE_SCOPE ;
206+ let is_cleanup = false ;
207+ let next_block = rustc_middle:: mir:: START_BLOCK ;
208+
209+ let id = self . next_expression ( ) ;
210+ self . inject_call (
211+ self . make_expression ( id, code_region, lhs, op, rhs) ,
212+ scope,
213+ is_cleanup,
214+ next_block,
215+ ) ;
198216 }
199217 }
200218
201- fn inject_counter ( & mut self , code_region : Span , next_block : BasicBlock ) -> u32 {
202- let counter_id = self . next_counter ( ) ;
203- let function_source_hash = self . function_source_hash ( ) ;
204- let injection_point = code_region. shrink_to_lo ( ) ;
219+ fn make_counter (
220+ & self ,
221+ id : u32 ,
222+ function_source_hash : u64 ,
223+ code_region : Span ,
224+ ) -> InjectedCall < ' tcx > {
225+ let inject_at = code_region. shrink_to_lo ( ) ;
205226
206- let count_code_region_fn = function_handle (
227+ let func = function_handle (
207228 self . tcx ,
208229 self . tcx . require_lang_item ( lang_items:: CountCodeRegionFnLangItem , None ) ,
209- injection_point ,
230+ inject_at ,
210231 ) ;
211232
212233 let mut args = Vec :: new ( ) ;
213234
214235 use count_code_region_args:: * ;
215236 debug_assert_eq ! ( FUNCTION_SOURCE_HASH , args. len( ) ) ;
216- args. push ( self . const_u64 ( function_source_hash, injection_point ) ) ;
237+ args. push ( self . const_u64 ( function_source_hash, inject_at ) ) ;
217238
218239 debug_assert_eq ! ( COUNTER_ID , args. len( ) ) ;
219- args. push ( self . const_u32 ( counter_id , injection_point ) ) ;
240+ args. push ( self . const_u32 ( id , inject_at ) ) ;
220241
221242 debug_assert_eq ! ( START_BYTE_POS , args. len( ) ) ;
222- args. push ( self . const_u32 ( code_region. lo ( ) . to_u32 ( ) , injection_point ) ) ;
243+ args. push ( self . const_u32 ( code_region. lo ( ) . to_u32 ( ) , inject_at ) ) ;
223244
224245 debug_assert_eq ! ( END_BYTE_POS , args. len( ) ) ;
225- args. push ( self . const_u32 ( code_region. hi ( ) . to_u32 ( ) , injection_point) ) ;
226-
227- self . inject_call ( count_code_region_fn, args, injection_point, next_block) ;
246+ args. push ( self . const_u32 ( code_region. hi ( ) . to_u32 ( ) , inject_at) ) ;
228247
229- counter_id
248+ InjectedCall { func , args , inject_at }
230249 }
231250
232- fn inject_counter_expression (
233- & mut self ,
251+ fn make_expression (
252+ & self ,
253+ id : u32 ,
234254 code_region : Span ,
235- next_block : BasicBlock ,
236255 lhs : u32 ,
237256 op : Op ,
238257 rhs : u32 ,
239- ) -> u32 {
240- let expression_id = self . next_expression ( ) ;
241- let injection_point = code_region. shrink_to_lo ( ) ;
258+ ) -> InjectedCall < ' tcx > {
259+ let inject_at = code_region. shrink_to_lo ( ) ;
242260
243- let count_code_region_fn = function_handle (
261+ let func = function_handle (
244262 self . tcx ,
245263 self . tcx . require_lang_item (
246264 match op {
@@ -249,43 +267,51 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
249267 } ,
250268 None ,
251269 ) ,
252- injection_point ,
270+ inject_at ,
253271 ) ;
254272
255273 let mut args = Vec :: new ( ) ;
256274
257275 use coverage_counter_expression_args:: * ;
258276 debug_assert_eq ! ( EXPRESSION_ID , args. len( ) ) ;
259- args. push ( self . const_u32 ( expression_id , injection_point ) ) ;
277+ args. push ( self . const_u32 ( id , inject_at ) ) ;
260278
261279 debug_assert_eq ! ( LEFT_ID , args. len( ) ) ;
262- args. push ( self . const_u32 ( lhs, injection_point ) ) ;
280+ args. push ( self . const_u32 ( lhs, inject_at ) ) ;
263281
264282 debug_assert_eq ! ( RIGHT_ID , args. len( ) ) ;
265- args. push ( self . const_u32 ( rhs, injection_point ) ) ;
283+ args. push ( self . const_u32 ( rhs, inject_at ) ) ;
266284
267285 debug_assert_eq ! ( START_BYTE_POS , args. len( ) ) ;
268- args. push ( self . const_u32 ( code_region. lo ( ) . to_u32 ( ) , injection_point ) ) ;
286+ args. push ( self . const_u32 ( code_region. lo ( ) . to_u32 ( ) , inject_at ) ) ;
269287
270288 debug_assert_eq ! ( END_BYTE_POS , args. len( ) ) ;
271- args. push ( self . const_u32 ( code_region. hi ( ) . to_u32 ( ) , injection_point ) ) ;
289+ args. push ( self . const_u32 ( code_region. hi ( ) . to_u32 ( ) , inject_at ) ) ;
272290
273- self . inject_call ( count_code_region_fn, args, injection_point, next_block) ;
274-
275- expression_id
291+ InjectedCall { func, args, inject_at }
276292 }
277293
278294 fn inject_call (
279295 & mut self ,
280- func : Operand < ' tcx > ,
281- args : Vec < Operand < ' tcx > > ,
282- fn_span : Span ,
296+ call : InjectedCall < ' tcx > ,
297+ scope : SourceScope ,
298+ is_cleanup : bool ,
283299 next_block : BasicBlock ,
284300 ) {
301+ let InjectedCall { func, args, inject_at } = call;
302+ debug ! (
303+ " injecting {}call to {:?}({:?}) at: {:?}, scope: {:?}" ,
304+ if is_cleanup { "cleanup " } else { "" } ,
305+ func,
306+ args,
307+ inject_at,
308+ scope,
309+ ) ;
310+
285311 let mut patch = MirPatch :: new ( self . mir_body ) ;
286312
287- let temp = patch. new_temp ( self . tcx . mk_unit ( ) , fn_span ) ;
288- let new_block = patch. new_block ( placeholder_block ( fn_span ) ) ;
313+ let temp = patch. new_temp ( self . tcx . mk_unit ( ) , inject_at ) ;
314+ let new_block = patch. new_block ( placeholder_block ( inject_at , scope , is_cleanup ) ) ;
289315 patch. patch_terminator (
290316 new_block,
291317 TerminatorKind :: Call {
@@ -295,7 +321,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
295321 destination : Some ( ( Place :: from ( temp) , new_block) ) ,
296322 cleanup : None ,
297323 from_hir_call : false ,
298- fn_span,
324+ fn_span : inject_at ,
299325 } ,
300326 ) ;
301327
@@ -325,15 +351,15 @@ fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Ope
325351 Operand :: function_handle ( tcx, fn_def_id, substs, span)
326352}
327353
328- fn placeholder_block ( span : Span ) -> BasicBlockData < ' tcx > {
354+ fn placeholder_block ( span : Span , scope : SourceScope , is_cleanup : bool ) -> BasicBlockData < ' tcx > {
329355 BasicBlockData {
330356 statements : vec ! [ ] ,
331357 terminator : Some ( Terminator {
332- source_info : SourceInfo :: outermost ( span) ,
358+ source_info : SourceInfo { span, scope } ,
333359 // this gets overwritten by the counter Call
334360 kind : TerminatorKind :: Unreachable ,
335361 } ) ,
336- is_cleanup : false ,
362+ is_cleanup,
337363 }
338364}
339365
0 commit comments