Skip to content

Commit

Permalink
Generating the coverage map
Browse files Browse the repository at this point in the history
rustc now generates the coverage map and can support (limited)
coverage report generation, at the function level.

Example:

$ BUILD=$HOME/rust/build/x86_64-unknown-linux-gnu
$ $BUILD/stage1/bin/rustc -Zinstrument-coverage \
$HOME/rust/src/test/run-make-fulldeps/instrument-coverage/main.rs
$ LLVM_PROFILE_FILE="main.profraw" ./main
called
$ $BUILD/llvm/bin/llvm-profdata merge -sparse main.profraw -o main.profdata
$ $BUILD/llvm/bin/llvm-cov show --instr-profile=main.profdata main
    1|      1|pub fn will_be_called() {
    2|      1|    println!("called");
    3|      1|}
    4|       |
    5|      0|pub fn will_not_be_called() {
    6|      0|    println!("should not have been called");
    7|      0|}
    8|       |
    9|      1|fn main() {
   10|      1|    let less = 1;
   11|      1|    let more = 100;
   12|      1|
   13|      1|    if less < more {
   14|      1|        will_be_called();
   15|      1|    } else {
   16|      1|        will_not_be_called();
   17|      1|    }
   18|      1|}
  • Loading branch information
richkadel committed Jul 17, 2020
1 parent c2dbebd commit a6f8b8a
Show file tree
Hide file tree
Showing 52 changed files with 1,724 additions and 262 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2788,6 +2788,13 @@ dependencies = [
"rls-span",
]

[[package]]
name = "rust-demangler"
version = "0.0.0"
dependencies = [
"rustc-demangle",
]

[[package]]
name = "rustbook"
version = "0.1.0"
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ members = [
"src/tools/remote-test-client",
"src/tools/remote-test-server",
"src/tools/rust-installer",
"src/tools/rust-demangler",
"src/tools/cargo",
"src/tools/rustdoc",
"src/tools/rls",
Expand Down
1 change: 1 addition & 0 deletions src/bootstrap/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ impl<'a> Builder<'a> {
tool::Cargo,
tool::Rls,
tool::RustAnalyzer,
tool::RustDemangler,
tool::Rustdoc,
tool::Clippy,
tool::CargoClippy,
Expand Down
4 changes: 4 additions & 0 deletions src/bootstrap/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,10 @@ impl Step for Compiletest {
cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler));
}

if mode == "run-make" && suite.ends_with("fulldeps") {
cmd.arg("--rust-demangler-path").arg(builder.tool_exe(Tool::RustDemangler));
}

cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite));
cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target));
Expand Down
1 change: 1 addition & 0 deletions src/bootstrap/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ bootstrap_tool!(
Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true;
BuildManifest, "src/tools/build-manifest", "build-manifest";
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
RustDemangler, "src/tools/rust-demangler", "rust-demangler";
RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
Expand Down
12 changes: 11 additions & 1 deletion src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1957,15 +1957,23 @@ extern "rust-intrinsic" {
/// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
/// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
/// generation.
#[cfg(not(bootstrap))]
#[lang = "count_code_region"]
pub fn count_code_region(index: u32, start_byte_pos: u32, end_byte_pos: u32);
pub fn count_code_region(
function_source_hash: u64,
index: u32,
start_byte_pos: u32,
end_byte_pos: u32,
);

/// Internal marker for code coverage expressions, injected into the MIR when the
/// "instrument-coverage" option is enabled. This intrinsic is not converted into a
/// backend intrinsic call, but its arguments are extracted during the production of a
/// "coverage map", which is injected into the generated code, as additional data.
/// This marker identifies a code region and two other counters or counter expressions
/// whose sum is the number of times the code region was executed.
#[cfg(not(bootstrap))]
#[lang = "coverage_counter_add"]
pub fn coverage_counter_add(
index: u32,
left_index: u32,
Expand All @@ -1977,6 +1985,8 @@ extern "rust-intrinsic" {
/// This marker identifies a code region and two other counters or counter expressions
/// whose difference is the number of times the code region was executed.
/// (See `coverage_counter_add` for more information.)
#[cfg(not(bootstrap))]
#[lang = "coverage_counter_subtract"]
pub fn coverage_counter_subtract(
index: u32,
left_index: u32,
Expand Down
3 changes: 3 additions & 0 deletions src/librustc_codegen_llvm/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,9 @@ fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
return;
}

// FIXME(richkadel): Make sure probestack plays nice with `-Z instrument-coverage`
// or disable it if not, similar to above early exits.

// Flag our internal `__rust_probestack` function as the stack probe symbol.
// This is defined in the `compiler-builtins` crate for each architecture.
llvm::AddFunctionAttrStringValue(
Expand Down
11 changes: 6 additions & 5 deletions src/librustc_codegen_llvm/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,17 +144,18 @@ pub fn compile_codegen_unit(
}
}

// Finalize code coverage by injecting the coverage map. Note, the coverage map will
// also be added to the `llvm.used` variable, created next.
if cx.sess().opts.debugging_opts.instrument_coverage {
cx.coverageinfo_finalize();
}

// Create the llvm.used variable
// This variable has type [N x i8*] and is stored in the llvm.metadata section
if !cx.used_statics().borrow().is_empty() {
cx.create_used_variable()
}

// Finalize code coverage by injecting the coverage map
if cx.sess().opts.debugging_opts.instrument_coverage {
cx.coverageinfo_finalize();
}

// Finalize debuginfo
if cx.sess().opts.debuginfo != DebugInfo::None {
cx.debuginfo_finalize();
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn_name, hash, num_counters, index
);

let llfn = unsafe { llvm::LLVMRustGetInstrprofIncrementIntrinsic(self.cx().llmod) };
let llfn = unsafe { llvm::LLVMRustGetInstrProfIncrementIntrinsic(self.cx().llmod) };
let args = &[fn_name, hash, num_counters, index];
let args = self.check_call("call", llfn, args);

Expand Down
10 changes: 7 additions & 3 deletions src/librustc_codegen_llvm/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,10 +493,14 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
}

if attrs.flags.contains(CodegenFnAttrFlags::USED) {
// This static will be stored in the llvm.used variable which is an array of i8*
let cast = llvm::LLVMConstPointerCast(g, self.type_i8p());
self.used_statics.borrow_mut().push(cast);
self.add_used_global(g);
}
}
}

/// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
fn add_used_global(&self, global: &'ll Value) {
let cast = unsafe { llvm::LLVMConstPointerCast(global, self.type_i8p()) };
self.used_statics.borrow_mut().push(cast);
}
}
Loading

0 comments on commit a6f8b8a

Please sign in to comment.