@@ -7,10 +7,9 @@ use rustc_middle::hir;
7
7
use rustc_middle:: ich:: StableHashingContext ;
8
8
use rustc_middle:: mir:: coverage:: * ;
9
9
use rustc_middle:: mir:: interpret:: Scalar ;
10
- use rustc_middle:: mir:: CoverageInfo ;
11
10
use 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 ,
14
13
} ;
15
14
use rustc_middle:: ty;
16
15
use rustc_middle:: ty:: query:: Providers ;
@@ -41,14 +40,14 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> Coverage
41
40
tcx. require_lang_item ( lang_items:: CoverageCounterSubtractFnLangItem , None ) ;
42
41
43
42
// 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
45
44
// 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
47
46
// instrumented function) is valid.
48
47
//
49
48
// `num_expressions` is the number of counter expressions added to the MIR body. Both
50
49
// `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.
52
51
let mut num_counters: u32 = 0 ;
53
52
let mut num_expressions: u32 = 0 ;
54
53
for terminator in
@@ -57,27 +56,26 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> Coverage
57
56
if let TerminatorKind :: Call { func : Operand :: Constant ( func) , args, .. } = & terminator. kind {
58
57
match func. literal . ty . kind {
59
58
FnDef ( id, _) if id == count_code_region_fn => {
60
- let index_arg =
59
+ let counter_id_arg =
61
60
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 )
63
62
. 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 ) ;
66
65
}
67
66
FnDef ( id, _)
68
67
if id == coverage_counter_add_fn || id == coverage_counter_subtract_fn =>
69
68
{
70
- let index_arg = args
69
+ let expression_id_arg = args
71
70
. get ( coverage_counter_expression_args:: EXPRESSION_ID )
72
71
. 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 )
74
73
. 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;
81
79
num_expressions = std:: cmp:: max ( num_expressions, expression_index + 1 ) ;
82
80
}
83
81
_ => { }
@@ -97,12 +95,10 @@ fn call_terminators(data: &'tcx BasicBlockData<'tcx>) -> Option<&'tcx Terminator
97
95
98
96
impl < ' tcx > MirPass < ' tcx > for InstrumentCoverage {
99
97
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 ( ) ;
106
102
}
107
103
}
108
104
}
@@ -113,6 +109,12 @@ enum Op {
113
109
Subtract ,
114
110
}
115
111
112
+ struct InjectedCall < ' tcx > {
113
+ func : Operand < ' tcx > ,
114
+ args : Vec < Operand < ' tcx > > ,
115
+ inject_at : Span ,
116
+ }
117
+
116
118
struct Instrumentor < ' a , ' tcx > {
117
119
tcx : TyCtxt < ' tcx > ,
118
120
mir_def_id : DefId ,
@@ -147,11 +149,8 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
147
149
}
148
150
149
151
/// 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.
155
154
fn next_expression ( & mut self ) -> u32 {
156
155
assert ! ( self . num_counters < u32 :: MAX - self . num_expressions) ;
157
156
let next = u32:: MAX - self . num_expressions ;
@@ -171,17 +170,25 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
171
170
}
172
171
173
172
fn inject_counters ( & mut self ) {
173
+ let mir_body = & self . mir_body ;
174
174
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) ;
180
176
181
177
// FIXME(richkadel): As a first step, counters are only injected at the top of each
182
178
// 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
+ ) ;
185
192
186
193
// FIXME(richkadel): The next step to implement source based coverage analysis will be
187
194
// instrumenting branches within functions, and some regions will be counted by "counter
@@ -190,57 +197,68 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
190
197
let fake_use = false ;
191
198
if fake_use {
192
199
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
+ ) ;
198
216
}
199
217
}
200
218
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 ( ) ;
205
226
206
- let count_code_region_fn = function_handle (
227
+ let func = function_handle (
207
228
self . tcx ,
208
229
self . tcx . require_lang_item ( lang_items:: CountCodeRegionFnLangItem , None ) ,
209
- injection_point ,
230
+ inject_at ,
210
231
) ;
211
232
212
233
let mut args = Vec :: new ( ) ;
213
234
214
235
use count_code_region_args:: * ;
215
236
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 ) ) ;
217
238
218
239
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 ) ) ;
220
241
221
242
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 ) ) ;
223
244
224
245
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) ) ;
228
247
229
- counter_id
248
+ InjectedCall { func , args , inject_at }
230
249
}
231
250
232
- fn inject_counter_expression (
233
- & mut self ,
251
+ fn make_expression (
252
+ & self ,
253
+ id : u32 ,
234
254
code_region : Span ,
235
- next_block : BasicBlock ,
236
255
lhs : u32 ,
237
256
op : Op ,
238
257
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 ( ) ;
242
260
243
- let count_code_region_fn = function_handle (
261
+ let func = function_handle (
244
262
self . tcx ,
245
263
self . tcx . require_lang_item (
246
264
match op {
@@ -249,43 +267,51 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
249
267
} ,
250
268
None ,
251
269
) ,
252
- injection_point ,
270
+ inject_at ,
253
271
) ;
254
272
255
273
let mut args = Vec :: new ( ) ;
256
274
257
275
use coverage_counter_expression_args:: * ;
258
276
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 ) ) ;
260
278
261
279
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 ) ) ;
263
281
264
282
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 ) ) ;
266
284
267
285
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 ) ) ;
269
287
270
288
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 ) ) ;
272
290
273
- self . inject_call ( count_code_region_fn, args, injection_point, next_block) ;
274
-
275
- expression_id
291
+ InjectedCall { func, args, inject_at }
276
292
}
277
293
278
294
fn inject_call (
279
295
& 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 ,
283
299
next_block : BasicBlock ,
284
300
) {
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
+
285
311
let mut patch = MirPatch :: new ( self . mir_body ) ;
286
312
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 ) ) ;
289
315
patch. patch_terminator (
290
316
new_block,
291
317
TerminatorKind :: Call {
@@ -295,7 +321,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
295
321
destination : Some ( ( Place :: from ( temp) , new_block) ) ,
296
322
cleanup : None ,
297
323
from_hir_call : false ,
298
- fn_span,
324
+ fn_span : inject_at ,
299
325
} ,
300
326
) ;
301
327
@@ -325,15 +351,15 @@ fn function_handle<'tcx>(tcx: TyCtxt<'tcx>, fn_def_id: DefId, span: Span) -> Ope
325
351
Operand :: function_handle ( tcx, fn_def_id, substs, span)
326
352
}
327
353
328
- fn placeholder_block ( span : Span ) -> BasicBlockData < ' tcx > {
354
+ fn placeholder_block ( span : Span , scope : SourceScope , is_cleanup : bool ) -> BasicBlockData < ' tcx > {
329
355
BasicBlockData {
330
356
statements : vec ! [ ] ,
331
357
terminator : Some ( Terminator {
332
- source_info : SourceInfo :: outermost ( span) ,
358
+ source_info : SourceInfo { span, scope } ,
333
359
// this gets overwritten by the counter Call
334
360
kind : TerminatorKind :: Unreachable ,
335
361
} ) ,
336
- is_cleanup : false ,
362
+ is_cleanup,
337
363
}
338
364
}
339
365
0 commit comments