about summary refs log tree commit diff
path: root/compiler/rustc_mir/src/transform/coverage/query.rs
diff options
context:
space:
mode:
authorRich Kadel <richkadel@google.com>2020-10-23 00:45:07 -0700
committerRich Kadel <richkadel@google.com>2020-11-05 18:24:12 -0800
commitc7ae4c2cb6d7e58ad0f9c12047e3d747c26a9d71 (patch)
treefdbb5014c0353a7a29a61b07364575b04d81362a /compiler/rustc_mir/src/transform/coverage/query.rs
parentc7747cc772f4b4c30ede3616678d7a3bc2c89bf7 (diff)
downloadrust-c7ae4c2cb6d7e58ad0f9c12047e3d747c26a9d71.tar.gz
rust-c7ae4c2cb6d7e58ad0f9c12047e3d747c26a9d71.zip
Splitting transform/instrument_coverage.rs into transform/coverage/...
Diffstat (limited to 'compiler/rustc_mir/src/transform/coverage/query.rs')
-rw-r--r--compiler/rustc_mir/src/transform/coverage/query.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs
new file mode 100644
index 00000000000..c17221b78dd
--- /dev/null
+++ b/compiler/rustc_mir/src/transform/coverage/query.rs
@@ -0,0 +1,113 @@
+use rustc_middle::mir::coverage::*;
+use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::{Coverage, CoverageInfo, Location};
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::def_id::DefId;
+
+/// The `query` provider for `CoverageInfo`, requested by `codegen_coverage()` (to inject each
+/// counter) and `FunctionCoverage::new()` (to extract the coverage map metadata from the MIR).
+pub(crate) fn provide(providers: &mut Providers) {
+    providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id);
+}
+
+/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in
+/// other words, the number of counter value references injected into the MIR (plus 1 for the
+/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected
+/// counters have a counter ID from `1..num_counters-1`.
+///
+/// `num_expressions` is the number of counter expressions added to the MIR body.
+///
+/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend
+/// code generate, to lookup counters and expressions by simple u32 indexes.
+///
+/// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code
+/// including injected counters. (It is OK if some counters are optimized out, but those counters
+/// are still included in the total `num_counters` or `num_expressions`.) Simply counting the
+/// calls may not work; but computing the number of counters or expressions by adding `1` to the
+/// highest ID (for a given instrumented function) is valid.
+///
+/// This visitor runs twice, first with `add_missing_operands` set to `false`, to find the maximum
+/// counter ID and maximum expression ID based on their enum variant `id` fields; then, as a
+/// safeguard, with `add_missing_operands` set to `true`, to find any other counter or expression
+/// IDs referenced by expression operands, if not already seen.
+///
+/// Ideally, every expression operand in the MIR will have a corresponding Counter or Expression,
+/// but since current or future MIR optimizations can theoretically optimize out segments of a
+/// MIR, it may not be possible to guarantee this, so the second pass ensures the `CoverageInfo`
+/// counts include all referenced IDs.
+struct CoverageVisitor {
+    info: CoverageInfo,
+    add_missing_operands: bool,
+}
+
+impl CoverageVisitor {
+    // If an expression operand is encountered with an ID outside the range of known counters and
+    // expressions, the only way to determine if the ID is a counter ID or an expression ID is to
+    // assume a maximum possible counter ID value.
+    const MAX_COUNTER_GUARD: u32 = (u32::MAX / 2) + 1;
+
+    #[inline(always)]
+    fn update_num_counters(&mut self, counter_id: u32) {
+        self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1);
+    }
+
+    #[inline(always)]
+    fn update_num_expressions(&mut self, expression_id: u32) {
+        let expression_index = u32::MAX - expression_id;
+        self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1);
+    }
+
+    fn update_from_expression_operand(&mut self, operand_id: u32) {
+        if operand_id >= self.info.num_counters {
+            let operand_as_expression_index = u32::MAX - operand_id;
+            if operand_as_expression_index >= self.info.num_expressions {
+                if operand_id <= Self::MAX_COUNTER_GUARD {
+                    self.update_num_counters(operand_id)
+                } else {
+                    self.update_num_expressions(operand_id)
+                }
+            }
+        }
+    }
+}
+
+impl Visitor<'_> for CoverageVisitor {
+    fn visit_coverage(&mut self, coverage: &Coverage, _location: Location) {
+        if self.add_missing_operands {
+            match coverage.kind {
+                CoverageKind::Expression { lhs, rhs, .. } => {
+                    self.update_from_expression_operand(u32::from(lhs));
+                    self.update_from_expression_operand(u32::from(rhs));
+                }
+                _ => {}
+            }
+        } else {
+            match coverage.kind {
+                CoverageKind::Counter { id, .. } => {
+                    self.update_num_counters(u32::from(id));
+                }
+                CoverageKind::Expression { id, .. } => {
+                    self.update_num_expressions(u32::from(id));
+                }
+                _ => {}
+            }
+        }
+    }
+}
+
+fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo {
+    let mir_body = tcx.optimized_mir(def_id);
+
+    let mut coverage_visitor = CoverageVisitor {
+        info: CoverageInfo { num_counters: 0, num_expressions: 0 },
+        add_missing_operands: false,
+    };
+
+    coverage_visitor.visit_body(mir_body);
+
+    coverage_visitor.add_missing_operands = true;
+    coverage_visitor.visit_body(mir_body);
+
+    coverage_visitor.info
+}