summary refs log tree commit diff
path: root/src/librustc_codegen_llvm/coverageinfo/mod.rs
blob: ff9f8f7aeaa544ec591697a2528c5383edc037bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::builder::Builder;
use crate::common::CodegenCx;
use log::debug;
use rustc_codegen_ssa::coverageinfo::map::*;
use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::Instance;

use std::cell::RefCell;

/// A context object for maintaining all state needed by the coverageinfo module.
pub struct CrateCoverageContext<'tcx> {
    // Coverage region data for each instrumented function identified by DefId.
    pub(crate) coverage_regions: RefCell<FxHashMap<Instance<'tcx>, FunctionCoverageRegions>>,
}

impl<'tcx> CrateCoverageContext<'tcx> {
    pub fn new() -> Self {
        Self { coverage_regions: Default::default() }
    }
}

/// Generates and exports the Coverage Map.
// FIXME(richkadel): Actually generate and export the coverage map to LLVM.
// The current implementation is actually just debug messages to show the data is available.
pub fn finalize(cx: &CodegenCx<'_, '_>) {
    let coverage_regions = &*cx.coverage_context().coverage_regions.borrow();
    for instance in coverage_regions.keys() {
        let coverageinfo = cx.tcx.coverageinfo(instance.def_id());
        debug_assert!(coverageinfo.num_counters > 0);
        debug!(
            "Generate coverage map for: {:?}, hash: {}, num_counters: {}",
            instance, coverageinfo.hash, coverageinfo.num_counters
        );
        let function_coverage_regions = &coverage_regions[instance];
        for (index, region) in function_coverage_regions.indexed_regions() {
            match region.kind {
                CoverageKind::Counter => debug!(
                    "  Counter {}, for {}..{}",
                    index, region.coverage_span.start_byte_pos, region.coverage_span.end_byte_pos
                ),
                CoverageKind::CounterExpression(lhs, op, rhs) => debug!(
                    "  CounterExpression {} = {} {:?} {}, for {}..{}",
                    index,
                    lhs,
                    op,
                    rhs,
                    region.coverage_span.start_byte_pos,
                    region.coverage_span.end_byte_pos
                ),
            }
        }
        for unreachable in function_coverage_regions.unreachable_regions() {
            debug!(
                "  Unreachable code region: {}..{}",
                unreachable.start_byte_pos, unreachable.end_byte_pos
            );
        }
    }
}

impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> {
    fn coverageinfo_finalize(&self) {
        finalize(self)
    }
}

impl CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
    fn add_counter_region(
        &mut self,
        instance: Instance<'tcx>,
        index: u32,
        start_byte_pos: u32,
        end_byte_pos: u32,
    ) {
        debug!(
            "adding counter to coverage map: instance={:?}, index={}, byte range {}..{}",
            instance, index, start_byte_pos, end_byte_pos,
        );
        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
        coverage_regions.entry(instance).or_default().add_counter(
            index,
            start_byte_pos,
            end_byte_pos,
        );
    }

    fn add_counter_expression_region(
        &mut self,
        instance: Instance<'tcx>,
        index: u32,
        lhs: u32,
        op: CounterOp,
        rhs: u32,
        start_byte_pos: u32,
        end_byte_pos: u32,
    ) {
        debug!(
            "adding counter expression to coverage map: instance={:?}, index={}, {} {:?} {}, byte range {}..{}",
            instance, index, lhs, op, rhs, start_byte_pos, end_byte_pos,
        );
        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
        coverage_regions.entry(instance).or_default().add_counter_expression(
            index,
            lhs,
            op,
            rhs,
            start_byte_pos,
            end_byte_pos,
        );
    }

    fn add_unreachable_region(
        &mut self,
        instance: Instance<'tcx>,
        start_byte_pos: u32,
        end_byte_pos: u32,
    ) {
        debug!(
            "adding unreachable code to coverage map: instance={:?}, byte range {}..{}",
            instance, start_byte_pos, end_byte_pos,
        );
        let mut coverage_regions = self.coverage_context().coverage_regions.borrow_mut();
        coverage_regions.entry(instance).or_default().add_unreachable(start_byte_pos, end_byte_pos);
    }
}