3 use rustc_middle
::mir
::coverage
::*;
4 use rustc_middle
::mir
::{self, Body, Coverage, CoverageInfo}
;
5 use rustc_middle
::query
::Providers
;
6 use rustc_middle
::ty
::{self, TyCtxt}
;
7 use rustc_span
::def_id
::DefId
;
9 /// A `query` provider for retrieving coverage information injected into MIR.
10 pub(crate) fn provide(providers
: &mut Providers
) {
11 providers
.coverageinfo
= |tcx
, def_id
| coverageinfo(tcx
, def_id
);
12 providers
.covered_code_regions
= |tcx
, def_id
| covered_code_regions(tcx
, def_id
);
15 /// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in
16 /// other words, the number of counter value references injected into the MIR (plus 1 for the
17 /// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected
18 /// counters have a counter ID from `1..num_counters-1`.
20 /// `num_expressions` is the number of counter expressions added to the MIR body.
22 /// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend
23 /// code generate, to lookup counters and expressions by simple u32 indexes.
25 /// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code
26 /// including injected counters. (It is OK if some counters are optimized out, but those counters
27 /// are still included in the total `num_counters` or `num_expressions`.) Simply counting the
28 /// calls may not work; but computing the number of counters or expressions by adding `1` to the
29 /// highest ID (for a given instrumented function) is valid.
31 /// This visitor runs twice, first with `add_missing_operands` set to `false`, to find the maximum
32 /// counter ID and maximum expression ID based on their enum variant `id` fields; then, as a
33 /// safeguard, with `add_missing_operands` set to `true`, to find any other counter or expression
34 /// IDs referenced by expression operands, if not already seen.
36 /// Ideally, each operand ID in a MIR `CoverageKind::Expression` will have a separate MIR `Coverage`
37 /// statement for the `Counter` or `Expression` with the referenced ID. but since current or future
38 /// MIR optimizations can theoretically optimize out segments of a MIR, it may not be possible to
39 /// guarantee this, so the second pass ensures the `CoverageInfo` counts include all referenced IDs.
40 struct CoverageVisitor
{
42 add_missing_operands
: bool
,
45 impl CoverageVisitor
{
46 /// Updates `num_counters` to the maximum encountered counter ID plus 1.
48 fn update_num_counters(&mut self, counter_id
: CounterId
) {
49 let counter_id
= counter_id
.as_u32();
50 self.info
.num_counters
= std
::cmp
::max(self.info
.num_counters
, counter_id
+ 1);
53 /// Updates `num_expressions` to the maximum encountered expression ID plus 1.
55 fn update_num_expressions(&mut self, expression_id
: ExpressionId
) {
56 let expression_id
= expression_id
.as_u32();
57 self.info
.num_expressions
= std
::cmp
::max(self.info
.num_expressions
, expression_id
+ 1);
60 fn update_from_expression_operand(&mut self, operand
: Operand
) {
62 Operand
::Counter(id
) => self.update_num_counters(id
),
63 Operand
::Expression(id
) => self.update_num_expressions(id
),
68 fn visit_body(&mut self, body
: &Body
<'_
>) {
69 for bb_data
in body
.basic_blocks
.iter() {
70 for statement
in bb_data
.statements
.iter() {
71 if let StatementKind
::Coverage(box ref coverage
) = statement
.kind
{
72 if is_inlined(body
, statement
) {
75 self.visit_coverage(coverage
);
81 fn visit_coverage(&mut self, coverage
: &Coverage
) {
82 if self.add_missing_operands
{
84 CoverageKind
::Expression { lhs, rhs, .. }
=> {
85 self.update_from_expression_operand(lhs
);
86 self.update_from_expression_operand(rhs
);
92 CoverageKind
::Counter { id, .. }
=> self.update_num_counters(id
),
93 CoverageKind
::Expression { id, .. }
=> self.update_num_expressions(id
),
100 fn coverageinfo
<'tcx
>(tcx
: TyCtxt
<'tcx
>, instance_def
: ty
::InstanceDef
<'tcx
>) -> CoverageInfo
{
101 let mir_body
= tcx
.instance_mir(instance_def
);
103 let mut coverage_visitor
= CoverageVisitor
{
104 info
: CoverageInfo { num_counters: 0, num_expressions: 0 }
,
105 add_missing_operands
: false,
108 coverage_visitor
.visit_body(mir_body
);
110 coverage_visitor
.add_missing_operands
= true;
111 coverage_visitor
.visit_body(mir_body
);
113 coverage_visitor
.info
116 fn covered_code_regions(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> Vec
<&CodeRegion
> {
117 let body
= mir_body(tcx
, def_id
);
121 data
.statements
.iter().filter_map(|statement
| match statement
.kind
{
122 StatementKind
::Coverage(box ref coverage
) => {
123 if is_inlined(body
, statement
) {
126 coverage
.code_region
.as_ref() // may be None
135 fn is_inlined(body
: &Body
<'_
>, statement
: &Statement
<'_
>) -> bool
{
136 let scope_data
= &body
.source_scopes
[statement
.source_info
.scope
];
137 scope_data
.inlined
.is_some() || scope_data
.inlined_parent_scope
.is_some()
140 /// This function ensures we obtain the correct MIR for the given item irrespective of
141 /// whether that means const mir or runtime mir. For `const fn` this opts for runtime
143 fn mir_body(tcx
: TyCtxt
<'_
>, def_id
: DefId
) -> &mir
::Body
<'_
> {
144 let def
= ty
::InstanceDef
::Item(def_id
);
145 tcx
.instance_mir(def
)