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, 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); } }