Skip to content

Commit a433777

Browse files
committed
Added codegen_llvm/coverageinfo mod for upcoming coverage map
1 parent d38359d commit a433777

File tree

12 files changed

+144
-72
lines changed

12 files changed

+144
-72
lines changed

src/librustc_codegen_llvm/base.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ pub fn compile_codegen_unit(
150150
cx.create_used_variable()
151151
}
152152

153+
// Finalize code coverage by injecting the coverage map
154+
if cx.sess().opts.debugging_opts.instrument_coverage {
155+
cx.coverageinfo_finalize();
156+
}
157+
153158
// Finalize debuginfo
154159
if cx.sess().opts.debuginfo != DebugInfo::None {
155160
cx.debuginfo_finalize();
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use crate::common::CodegenCx;
2+
use log::debug;
3+
use rustc_codegen_ssa::traits::CoverageInfoMethods;
4+
use rustc_hir::def_id::LOCAL_CRATE;
5+
6+
// FIXME(richkadel): This might not be where I put the coverage map generation, but it's a
7+
// placeholder for now.
8+
//
9+
// I need to inject the coverage map into the LLVM IR. This is one possible place to do it.
10+
//
11+
// The code below is here, at least temporarily, to verify that the `CoverageRegion`s are
12+
// available, to produce the coverage map.
13+
14+
/// Generates and exports the Coverage Map.
15+
pub fn finalize(cx: &CodegenCx<'_, '_>) {
16+
let instances = &*cx.instances.borrow();
17+
for instance in instances.keys() {
18+
if instance.def_id().krate == LOCAL_CRATE {
19+
// FIXME(richkadel): Is this check `krate == LOCAL_CRATE` right?
20+
//
21+
// NOTE: I'm considering at least one alternative to this loop on `instances`,
22+
// But if I do go with this, make sure the check on LOCAL_CRATE works for all cases.
23+
//
24+
//
25+
// Without it, I was crashing on some of the instances, with:
26+
//
27+
// src/librustc_metadata/rmeta/decoder.rs:1127:17: get_optimized_mir: missing MIR for `DefId(1:2867 ~ std[70cc]::io[0]::stdio[0]::_print[0])`
28+
//
29+
// This check avoids it, but still works for the very limited testing I've done so far.
30+
let coverageinfo = cx.tcx.coverageinfo(instance.def_id());
31+
if coverageinfo.num_counters > 0 {
32+
debug!(
33+
"Generate coverage map for: {}, hash: {:?}, num_counters: {}\n{}",
34+
instance,
35+
coverageinfo.hash,
36+
coverageinfo.num_counters,
37+
{
38+
let regions = &coverageinfo.coverage_regions;
39+
(0..regions.len() as u32)
40+
.map(|counter_index| {
41+
let region = &regions[counter_index];
42+
format!(
43+
" counter_index {} byte range: {}..{}",
44+
counter_index, region.start_byte_pos, region.end_byte_pos
45+
)
46+
})
47+
.collect::<Vec<String>>()
48+
.join("\n")
49+
}
50+
);
51+
}
52+
}
53+
}
54+
}
55+
56+
impl CoverageInfoMethods for CodegenCx<'ll, 'tcx> {
57+
fn coverageinfo_finalize(&self) {
58+
finalize(self)
59+
}
60+
}

src/librustc_codegen_llvm/intrinsic.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef;
1919
use rustc_codegen_ssa::traits::*;
2020
use rustc_codegen_ssa::MemFlags;
2121
use rustc_hir as hir;
22+
use rustc_middle::mir::coverage;
2223
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
2324
use rustc_middle::ty::{self, Ty};
2425
use rustc_middle::{bug, span_bug};
@@ -140,27 +141,24 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
140141
self.call(llfn, &[], None)
141142
}
142143
"count_code_region" => {
143-
use rustc_middle::mir::count_code_region_args::{
144-
COUNTER_INDEX, END_BYTE_POS, START_BYTE_POS,
145-
};
144+
use coverage::count_code_region_args::*;
146145
// FIXME(richkadel): The current implementation assumes the MIR for the given
147146
// caller_instance represents a single function. Validate and/or correct if inlining
148147
// and/or monomorphization invalidates these assumptions.
149-
let coverage_data = tcx.coverage_data(caller_instance.def_id());
148+
let coverageinfo = tcx.coverageinfo(caller_instance.def_id());
150149
let mangled_fn = tcx.symbol_name(caller_instance);
151150
let (mangled_fn_name, _len_val) = self.const_str(mangled_fn.name);
152-
let hash = self.const_u64(coverage_data.hash);
153-
let num_counters = self.const_u32(coverage_data.num_counters);
151+
let hash = self.const_u64(coverageinfo.hash);
152+
let num_counters = self.const_u32(coverageinfo.num_counters);
154153
let index = args[COUNTER_INDEX].immediate();
155154
debug!(
156-
"count_code_region to LLVM intrinsic instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?}), byte range {:?}..{:?}, coverage_regions: {:?}",
155+
"count_code_region to LLVM intrinsic instrprof.increment(fn_name={}, hash={:?}, num_counters={:?}, index={:?}), byte range {:?}..{:?}",
157156
mangled_fn.name,
158157
hash,
159158
num_counters,
160159
index,
161160
args[START_BYTE_POS].immediate(),
162161
args[END_BYTE_POS].immediate(),
163-
coverage_data.coverage_regions,
164162
);
165163
self.instrprof_increment(mangled_fn_name, hash, num_counters, index)
166164
}

src/librustc_codegen_llvm/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ mod callee;
5555
mod common;
5656
mod consts;
5757
mod context;
58+
mod coverageinfo;
5859
mod debuginfo;
5960
mod declare;
6061
mod intrinsic;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
use super::BackendTypes;
2+
3+
pub trait CoverageInfoMethods: BackendTypes {
4+
fn coverageinfo_finalize(&self);
5+
}

src/librustc_codegen_ssa/traits/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ mod asm;
1919
mod backend;
2020
mod builder;
2121
mod consts;
22+
mod coverageinfo;
2223
mod debuginfo;
2324
mod declare;
2425
mod intrinsic;
@@ -32,6 +33,7 @@ pub use self::asm::{AsmBuilderMethods, AsmMethods, InlineAsmOperandRef};
3233
pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods};
3334
pub use self::builder::{BuilderMethods, OverflowOp};
3435
pub use self::consts::ConstMethods;
36+
pub use self::coverageinfo::CoverageInfoMethods;
3537
pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods};
3638
pub use self::declare::{DeclareMethods, PreDefineMethods};
3739
pub use self::intrinsic::IntrinsicCallMethods;
@@ -56,6 +58,7 @@ pub trait CodegenMethods<'tcx>:
5658
+ MiscMethods<'tcx>
5759
+ ConstMethods<'tcx>
5860
+ StaticMethods
61+
+ CoverageInfoMethods
5962
+ DebugInfoMethods<'tcx>
6063
+ DeclareMethods<'tcx>
6164
+ AsmMethods
@@ -72,6 +75,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where
7275
+ MiscMethods<'tcx>
7376
+ ConstMethods<'tcx>
7477
+ StaticMethods
78+
+ CoverageInfoMethods
7579
+ DebugInfoMethods<'tcx>
7680
+ DeclareMethods<'tcx>
7781
+ AsmMethods

src/librustc_middle/arena.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ macro_rules! arena_types {
9494
[] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>, rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>;
9595
[] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, rustc_middle::traits::ObjectSafetyViolation;
9696
[] codegen_unit: rustc_middle::mir::mono::CodegenUnit<$tcx>, rustc_middle::mir::mono::CodegenUnit<'_x>;
97-
[] coverage_data: rustc_middle::mir::CoverageData, rustc_middle::mir::CoverageData;
97+
[] coverageinfo: rustc_middle::mir::coverage::CoverageInfo, rustc_middle::mir::coverage::CoverageInfo;
9898
[] attribute: rustc_ast::ast::Attribute, rustc_ast::ast::Attribute;
9999
[] name_set: rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>, rustc_data_structures::fx::FxHashSet<rustc_span::symbol::Symbol>;
100100
[] hir_id_set: rustc_hir::HirIdSet, rustc_hir::HirIdSet;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//! Metadata from source code coverage analysis and instrumentation.
2+
3+
use rustc_index::vec::IndexVec;
4+
5+
/// Coverage information associated with each function (MIR) instrumented with coverage counters, when
6+
/// compiled with `-Zinstrument_coverage`. The query `tcx.coverageinfo(DefId)` computes these
7+
/// values on demand (during code generation). This query is only valid after executing the MIR pass
8+
/// `InstrumentCoverage`.
9+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
10+
pub struct CoverageInfo {
11+
/// A hash value that can be used by the consumer of the coverage profile data to detect
12+
/// changes to the instrumented source of the associated MIR body (typically, for an
13+
/// individual function).
14+
pub hash: u64,
15+
16+
/// The total number of coverage region counters added to the MIR `Body`.
17+
pub num_counters: u32,
18+
19+
/// The start and end positions within a source file for the region of source code counted by
20+
/// the given counter index.
21+
pub coverage_regions: IndexVec<u32, CoverageRegion>,
22+
}
23+
24+
/// Defines the region, within the source code, where a counter is optionally injected (if compiled
25+
/// with `-Zinstrument_coverage`), to count the number of times this code region is executed.
26+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
27+
pub struct CoverageRegion {
28+
/// The code region's starting position within the source code file.
29+
pub start_byte_pos: u32,
30+
31+
/// The code region's ending position within the source code file.
32+
pub end_byte_pos: u32,
33+
}
34+
35+
/// Positional arguments to `libcore::count_code_region()`
36+
pub mod count_code_region_args {
37+
pub const COUNTER_INDEX: usize = 0;
38+
pub const START_BYTE_POS: usize = 1;
39+
pub const END_BYTE_POS: usize = 2;
40+
}

src/librustc_middle/mir/mod.rs

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use std::{iter, mem, option};
4242
use self::predecessors::{PredecessorCache, Predecessors};
4343
pub use self::query::*;
4444

45+
pub mod coverage;
4546
pub mod interpret;
4647
pub mod mono;
4748
mod predecessors;
@@ -2993,44 +2994,3 @@ impl Location {
29932994
}
29942995
}
29952996
}
2996-
2997-
///////////////////////////////////////////////////////////////////////////
2998-
// Source code coverage
2999-
3000-
/// Coverage data associated with each function (MIR) instrumented with coverage counters, when
3001-
/// compiled with `-Zinstrument_coverage`. The query `tcx.coverage_data(DefId)` computes these
3002-
/// values on demand (during code generation). This query is only valid after executing the MIR pass
3003-
/// `InstrumentCoverage`.
3004-
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
3005-
pub struct CoverageRegion {
3006-
/// The code region's starting position within the source code file.
3007-
pub start_byte_pos: u32,
3008-
3009-
/// The code region's ending position within the source code file.
3010-
pub end_byte_pos: u32,
3011-
}
3012-
3013-
/// Coverage data associated with each function (MIR) instrumented with coverage counters, when
3014-
/// compiled with `-Zinstrument_coverage`. The query `tcx.coverage_data(DefId)` computes these
3015-
/// values on demand (during code generation). This query is only valid after executing the MIR pass
3016-
/// `InstrumentCoverage`.
3017-
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
3018-
pub struct CoverageData {
3019-
/// A hash value that can be used by the consumer of the coverage profile data to detect
3020-
/// changes to the instrumented source of the associated MIR body (typically, for an
3021-
/// individual function).
3022-
pub hash: u64,
3023-
3024-
/// The total number of coverage region counters added to the MIR `Body`.
3025-
pub num_counters: u32,
3026-
3027-
/// The start and end positions within a source file for the region of source code counted by
3028-
/// the given counter index.
3029-
pub coverage_regions: IndexVec<u32, CoverageRegion>,
3030-
}
3031-
3032-
pub mod count_code_region_args {
3033-
pub const COUNTER_INDEX: usize = 0;
3034-
pub const START_BYTE_POS: usize = 1;
3035-
pub const END_BYTE_POS: usize = 2;
3036-
}

src/librustc_middle/query/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,8 @@ rustc_queries! {
231231
cache_on_disk_if { key.is_local() }
232232
}
233233

234-
query coverage_data(key: DefId) -> &'tcx mir::CoverageData {
235-
desc { |tcx| "retrieving coverage data from MIR for `{}`", tcx.def_path_str(key) }
234+
query coverageinfo(key: DefId) -> &'tcx mir::coverage::CoverageInfo {
235+
desc { |tcx| "retrieving coverageinfo from MIR for `{}`", tcx.def_path_str(key) }
236236
storage(ArenaCacheSelector<'tcx>)
237237
cache_on_disk_if { key.is_local() }
238238
}

src/librustc_mir/transform/inline.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ impl<'tcx> MirPass<'tcx> for Inline {
4040
fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
4141
if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
4242
if tcx.sess.opts.debugging_opts.instrument_coverage {
43+
// The current implementation of source code coverage injects code region counters
44+
// into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code-
45+
// based function.
4346
debug!("function inlining is disabled when compiling with `instrument_coverage`");
44-
// The current implementation of source code coverage injects code region counters
45-
// into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code-
46-
// based function.
4747
} else {
4848
Inliner { tcx, source }.run_pass(body);
4949
}

src/librustc_mir/transform/instrument_coverage.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ use rustc_hir::lang_items;
66
use rustc_index::vec::IndexVec;
77
use rustc_middle::hir;
88
use rustc_middle::ich::StableHashingContext;
9+
use rustc_middle::mir::coverage::count_code_region_args::*;
10+
use rustc_middle::mir::coverage::{CoverageInfo, CoverageRegion};
911
use rustc_middle::mir::interpret::{ConstValue, InterpResult, Scalar};
1012
use rustc_middle::mir::{
11-
self, traversal, BasicBlock, BasicBlockData, CoverageData, CoverageRegion, Operand, Place,
12-
SourceInfo, StatementKind, Terminator, TerminatorKind, START_BLOCK,
13+
self, traversal, BasicBlock, BasicBlockData, Operand, Place, SourceInfo, StatementKind,
14+
Terminator, TerminatorKind, START_BLOCK,
1315
};
1416
use rustc_middle::ty;
1517
use rustc_middle::ty::query::Providers;
@@ -18,19 +20,17 @@ use rustc_middle::ty::{ConstKind, FnDef};
1820
use rustc_span::def_id::DefId;
1921
use rustc_span::{Pos, Span};
2022

21-
use rustc_middle::mir::count_code_region_args::{COUNTER_INDEX, END_BYTE_POS, START_BYTE_POS};
22-
2323
/// Inserts call to count_code_region() as a placeholder to be replaced during code generation with
2424
/// the intrinsic llvm.instrprof.increment.
2525
pub struct InstrumentCoverage;
2626

27-
/// The `query` provider for `CoverageData`, requested by `codegen_intrinsic_call()` when
27+
/// The `query` provider for `CoverageInfo`, requested by `codegen_intrinsic_call()` when
2828
/// constructing the arguments for `llvm.instrprof.increment`.
2929
pub(crate) fn provide(providers: &mut Providers<'_>) {
30-
providers.coverage_data = |tcx, def_id| coverage_data_from_mir(tcx, def_id);
30+
providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id);
3131
}
3232

33-
fn coverage_data_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> &'tcx CoverageData {
33+
fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> &'tcx CoverageInfo {
3434
let mir_body = tcx.optimized_mir(mir_def_id);
3535
// FIXME(richkadel): The current implementation assumes the MIR for the given DefId
3636
// represents a single function. Validate and/or correct if inlining and/or monomorphization
@@ -44,7 +44,6 @@ fn coverage_data_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> &'tcx C
4444
// instrumented function) is valid.
4545
let mut indexed_regions = vec![];
4646
let mut num_counters: u32 = 0;
47-
//for terminator in count_code_region_terminators(tcx, mir_body) {
4847
for terminator in traversal::preorder(mir_body)
4948
.map(|(_, data)| (data, count_code_region_fn))
5049
.filter_map(count_code_region_terminator_filter)
@@ -77,7 +76,7 @@ fn coverage_data_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> &'tcx C
7776
for (index, region) in indexed_regions {
7877
coverage_regions[index] = region;
7978
}
80-
tcx.arena.alloc(CoverageData { num_counters, hash, coverage_regions })
79+
tcx.arena.alloc(CoverageInfo { num_counters, hash, coverage_regions })
8180
}
8281

8382
fn count_code_region_terminator_filter(
@@ -95,18 +94,18 @@ fn count_code_region_terminator_filter(
9594
None
9695
}
9796

98-
fn arg<T, F>(to_val: F, args: &Vec<Operand<'tcx>>, pos: usize) -> T
97+
fn arg<T, F>(to_val: F, args: &Vec<Operand<'tcx>>, arg_index: usize) -> T
9998
where
10099
F: FnOnce(Scalar) -> InterpResult<'static, T>,
101100
{
102-
match args.get(pos).unwrap_or_else(|| bug!("count_code_region arg{} not found", pos)) {
101+
match args.get(arg_index).unwrap_or_else(|| bug!("arg{} not found", arg_index)) {
103102
Operand::Constant(constant) => match constant.literal.val {
104103
ConstKind::Value(ConstValue::Scalar(scalar)) => to_val(scalar).unwrap_or_else(|err| {
105-
bug!("count_code_region arg{}, {:?}: {:?}", pos, scalar, err);
104+
bug!("count_code_region arg{}, {:?}: {:?}", arg_index, scalar, err);
106105
}),
107-
_ => bug!("count_code_region arg{}: ConstKind::Value expected", pos),
106+
_ => bug!("count_code_region arg{}: ConstKind::Value expected", arg_index),
108107
},
109-
_ => bug!("count_code_region arg{}: Operand::Constant expected", pos),
108+
_ => bug!("count_code_region arg{}: Operand::Constant expected", arg_index),
110109
}
111110
}
112111

@@ -178,13 +177,13 @@ impl<'tcx> Instrumentor<'tcx> {
178177

179178
let mut args = Vec::new();
180179

181-
assert_eq!(COUNTER_INDEX, args.len());
180+
debug_assert_eq!(COUNTER_INDEX, args.len());
182181
args.push(self.const_u32(index, injection_point));
183182

184-
assert_eq!(START_BYTE_POS, args.len());
183+
debug_assert_eq!(START_BYTE_POS, args.len());
185184
args.push(self.const_u32(code_region.lo().to_u32(), injection_point));
186185

187-
assert_eq!(END_BYTE_POS, args.len());
186+
debug_assert_eq!(END_BYTE_POS, args.len());
188187
args.push(self.const_u32(code_region.hi().to_u32(), injection_point));
189188

190189
let mut patch = MirPatch::new(mir_body);

0 commit comments

Comments
 (0)