rustc_codegen_llvm/coverageinfo/
mod.rs

1use std::cell::{OnceCell, RefCell};
2use std::ffi::{CStr, CString};
3
4use rustc_codegen_ssa::traits::{
5    ConstCodegenMethods, CoverageInfoBuilderMethods, MiscCodegenMethods,
6};
7use rustc_data_structures::fx::FxIndexMap;
8use rustc_middle::mir::coverage::CoverageKind;
9use rustc_middle::ty::Instance;
10use tracing::{debug, instrument};
11
12use crate::builder::Builder;
13use crate::common::CodegenCx;
14use crate::llvm;
15
16pub(crate) mod ffi;
17mod llvm_cov;
18mod mapgen;
19
20/// Extra per-CGU context/state needed for coverage instrumentation.
21pub(crate) struct CguCoverageContext<'ll, 'tcx> {
22    /// Associates function instances with an LLVM global that holds the
23    /// function's symbol name, as needed by LLVM coverage intrinsics.
24    ///
25    /// Instances in this map are also considered "used" for the purposes of
26    /// emitting covfun records. Every covfun record holds a hash of its
27    /// symbol name, and `llvm-cov` will exit fatally if it can't resolve that
28    /// hash back to an entry in the binary's `__llvm_prf_names` linker section.
29    pub(crate) pgo_func_name_var_map: RefCell<FxIndexMap<Instance<'tcx>, &'ll llvm::Value>>,
30
31    covfun_section_name: OnceCell<CString>,
32}
33
34impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> {
35    pub(crate) fn new() -> Self {
36        Self { pgo_func_name_var_map: Default::default(), covfun_section_name: Default::default() }
37    }
38
39    /// Returns the list of instances considered "used" in this CGU, as
40    /// inferred from the keys of `pgo_func_name_var_map`.
41    pub(crate) fn instances_used(&self) -> Vec<Instance<'tcx>> {
42        // Collecting into a Vec is way easier than trying to juggle RefCell
43        // projections, and this should only run once per CGU anyway.
44        self.pgo_func_name_var_map.borrow().keys().copied().collect::<Vec<_>>()
45    }
46}
47
48impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
49    pub(crate) fn coverageinfo_finalize(&mut self) {
50        mapgen::finalize(self)
51    }
52
53    /// Returns the section name to use when embedding per-function coverage information
54    /// in the object file, according to the target's object file format. LLVM's coverage
55    /// tools use information from this section when producing coverage reports.
56    ///
57    /// Typical values are:
58    /// - `__llvm_covfun` on Linux
59    /// - `__LLVM_COV,__llvm_covfun` on macOS (includes `__LLVM_COV,` segment prefix)
60    /// - `.lcovfun$M` on Windows (includes `$M` sorting suffix)
61    fn covfun_section_name(&self) -> &CStr {
62        self.coverage_cx()
63            .covfun_section_name
64            .get_or_init(|| llvm_cov::covfun_section_name(self.llmod))
65    }
66
67    /// For LLVM codegen, returns a function-specific `Value` for a global
68    /// string, to hold the function name passed to LLVM intrinsic
69    /// `instrprof.increment()`. The `Value` is only created once per instance.
70    /// Multiple invocations with the same instance return the same `Value`.
71    ///
72    /// This has the side-effect of causing coverage codegen to consider this
73    /// function "used", making it eligible to emit an associated covfun record.
74    fn ensure_pgo_func_name_var(&self, instance: Instance<'tcx>) -> &'ll llvm::Value {
75        debug!("getting pgo_func_name_var for instance={:?}", instance);
76        let mut pgo_func_name_var_map = self.coverage_cx().pgo_func_name_var_map.borrow_mut();
77        pgo_func_name_var_map.entry(instance).or_insert_with(|| {
78            let llfn = self.get_fn(instance);
79            let mangled_fn_name: &str = self.tcx.symbol_name(instance).name;
80            llvm_cov::create_pgo_func_name_var(llfn, mangled_fn_name)
81        })
82    }
83}
84
85impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
86    #[instrument(level = "debug", skip(self))]
87    fn add_coverage(&mut self, instance: Instance<'tcx>, kind: &CoverageKind) {
88        // Our caller should have already taken care of inlining subtleties,
89        // so we can assume that counter/expression IDs in this coverage
90        // statement are meaningful for the given instance.
91        //
92        // (Either the statement was not inlined and directly belongs to this
93        // instance, or it was inlined *from* this instance.)
94
95        let bx = self;
96
97        // Due to LocalCopy instantiation or MIR inlining, coverage statements
98        // can end up in a crate that isn't doing coverage instrumentation.
99        // When that happens, we currently just discard those statements, so
100        // the corresponding code will be undercounted.
101        // FIXME(Zalathar): Find a better solution for mixed-coverage builds.
102        let Some(_coverage_cx) = &bx.cx.coverage_cx else { return };
103
104        let Some(function_coverage_info) =
105            bx.tcx.instance_mir(instance.def).function_coverage_info.as_deref()
106        else {
107            debug!("function has a coverage statement but no coverage info");
108            return;
109        };
110        let Some(ids_info) = bx.tcx.coverage_ids_info(instance.def) else {
111            debug!("function has a coverage statement but no IDs info");
112            return;
113        };
114
115        match *kind {
116            CoverageKind::SpanMarker | CoverageKind::BlockMarker { .. } => unreachable!(
117                "marker statement {kind:?} should have been removed by CleanupPostBorrowck"
118            ),
119            CoverageKind::VirtualCounter { bcb }
120                if let Some(&id) = ids_info.phys_counter_for_node.get(&bcb) =>
121            {
122                let fn_name = bx.ensure_pgo_func_name_var(instance);
123                let hash = bx.const_u64(function_coverage_info.function_source_hash);
124                let num_counters = bx.const_u32(ids_info.num_counters);
125                let index = bx.const_u32(id.as_u32());
126                debug!(
127                    "codegen intrinsic instrprof.increment(fn_name={:?}, hash={:?}, num_counters={:?}, index={:?})",
128                    fn_name, hash, num_counters, index,
129                );
130                bx.instrprof_increment(fn_name, hash, num_counters, index);
131            }
132            // If a BCB doesn't have an associated physical counter, there's nothing to codegen.
133            CoverageKind::VirtualCounter { .. } => {}
134        }
135    }
136}