Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support MCDC Coverage with LLVM backend. #123358

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3f791cb
mcdc-coverage: Add `mcdc` and `no-mcdc` options for `-Zcoverage-options`
RenjiSann Mar 8, 2024
1782978
mcdc-coverage: Update ffi RegionKind to match LLVM's
RenjiSann Mar 13, 2024
5c5cd19
mcdc-coverage: Add FFI for getting Bitmap IPSK, Bump CoverageMappingV…
RenjiSann Mar 13, 2024
f789616
mcdc-coverage: Add utils for instrprof.mcdc.parameters intrinsic
RenjiSann Mar 14, 2024
7b321ca
mcdc-coverage: Add FFI MCDC Params for coverage mappings encoding
RenjiSann Mar 19, 2024
7d1dc67
mcdc-coverage: Add MCDCBlockMarker and MCDCDecisionMarker to the MIR
RenjiSann Mar 19, 2024
5bdabd0
mcdc-coverage: Add Data in BranchInfo for MCDC Tracability
RenjiSann Mar 19, 2024
e8b9b7c
mcdc-coverage: Add CoverageKind::MCDCBitmapRequire
RenjiSann Mar 20, 2024
7669154
mcdc-coverage: Generate `mcdc.parameters` intrinsic call at the begin…
RenjiSann Mar 21, 2024
1e2afe6
mcdc-coverage: allocate a condition bitmap on the function stackframe…
RenjiSann Mar 21, 2024
a30b4bb
mcdc-coverage: rename Decision marker to MCDCDecisionEntryMarker, add…
RenjiSann Mar 26, 2024
f831496
mcdc-coverage: Refactor Decision markers creation, add outcome marker…
RenjiSann Mar 26, 2024
6e7e2c5
mcdc-coverage: Add CoverageKinds for Bitmap manipulations.
RenjiSann Mar 27, 2024
20cdc51
mcdc-coverage: Add doc comments, move too many conditions error
RenjiSann Mar 27, 2024
cb55ae4
mcdc-coverage: Remove MCDCBlockMarker, Rename DecisionMarkerId, Add C…
RenjiSann Mar 27, 2024
9fea26a
mcdc-coverage: Refactor the MCDC info building
RenjiSann Mar 27, 2024
25768f8
mcdc-coverage: Add FFI equivalents of MCDC bitmap update intrinsics
RenjiSann Mar 28, 2024
83b8166
mcdc-coverage(codegen): Add MCDCCondBitmap(Reset|Update) Handling in …
RenjiSann Mar 28, 2024
33de2bb
mcdc-coverage(instrumentation): Rename Id names, Start instrumentatio…
RenjiSann Mar 29, 2024
e00df5d
mcdc-coverage(codegen): Add MCDCTestVectorBitmapUpdate codegen implem…
RenjiSann Apr 3, 2024
e112dc8
mcdc-coverage(mappings): Add variants for MCDCDecision and MCDCBranch…
RenjiSann Apr 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,122 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
}

fn instrprof_mcdc_parameters(
&mut self,
fn_name: Self::Value,
hash: Self::Value,
num_bitmap_bytes: Self::Value,
) {
debug!(
"instrprof_mcdc_parameters() with args ({:?}, {:?}, {:?})",
fn_name, hash, num_bitmap_bytes
);

let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCParametersIntrinsic(self.cx().llmod) };
let llty = self.cx.type_func(
&[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()],
self.cx.type_void(),
);
let args = &[fn_name, hash, num_bitmap_bytes];
let args = self.check_call("call", llty, llfn, args);

unsafe {
let _ = llvm::LLVMRustBuildCall(
self.llbuilder,
llty,
llfn,
args.as_ptr() as *const &llvm::Value,
args.len() as c_uint,
[].as_ptr(),
0 as c_uint,
);
}
}

fn instrprof_mcdc_condbitmap_update(
&mut self,
fn_name: Self::Value,
hash: Self::Value,
cond_id: Self::Value,
cond_bitmap_addr: Self::Value,
cond_result: Self::Value,
) {
debug!(
"instrprof_mcdc_condbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})",
fn_name, hash, cond_id, cond_bitmap_addr, cond_result
);

let llfn =
unsafe { llvm::LLVMRustGetInstrProfMCDCCondBitmapUpdateIntrinsic(self.cx().llmod) };
let llty = self.cx.type_func(
&[
self.cx.type_ptr(),
self.cx.type_i64(),
self.cx.type_i32(),
self.cx.type_ptr(),
self.cx.type_i1(),
],
self.cx.type_void(),
);

let args = &[fn_name, hash, cond_id, cond_bitmap_addr, cond_result];
let args = self.check_call("call", llty, llfn, args);

unsafe {
let _ = llvm::LLVMRustBuildCall(
self.llbuilder,
llty,
llfn,
args.as_ptr(),
args.len() as c_uint,
[].as_ptr(),
0 as c_uint,
);
}
}

fn instrprof_mcdc_tvbitmap_update(
&mut self,
fn_name: Self::Value,
hash: Self::Value,
needed_bytes: Self::Value,
bitmap_idx: Self::Value,
cond_bitmap_addr: Self::Value,
) {
debug!(
"instrprof_mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})",
fn_name, hash, needed_bytes, bitmap_idx, cond_bitmap_addr
);

let llfn =
unsafe { llvm::LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(self.cx().llmod) };
let llty = self.cx.type_func(
&[
self.cx.type_ptr(),
self.cx.type_i64(),
self.cx.type_i32(),
self.cx.type_i32(),
self.cx.type_ptr(),
],
self.cx.type_void(),
);

let args = &[fn_name, hash, needed_bytes, bitmap_idx, cond_bitmap_addr];
let args = self.check_call("call", llty, llfn, args);

unsafe {
let _ = llvm::LLVMRustBuildCall(
self.llbuilder,
llty,
llfn,
args.as_ptr(),
args.len() as c_uint,
[].as_ptr(),
0 as c_uint,
);
}
}

fn call(
&mut self,
llty: &'ll Type,
Expand Down
96 changes: 95 additions & 1 deletion compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,36 @@ pub enum RegionKind {
/// associated with two counters, each representing the number of times the
/// expression evaluates to true or false.
BranchRegion = 4,

/// A DecisionRegion represents a top-level boolean expression and is
/// associated with a variable length bitmap index and condition number.
MCDCDecisionRegion = 5,

/// A Branch Region can be extended to include IDs to facilitate MC/DC.
#[allow(dead_code)]
MCDCBranchRegion = 6,
}

/// This struct provides LLVM's representation of "MCDCParameters" that may be defined for a
/// Coverage Mapping Region.
///
/// Correspond to struct `llvm::coverage::CounterMappingRegion::MCDCParameters`
///
/// Must match The layout of `LLVMRustMCDCParameters`
#[derive(Copy, Clone, Debug, Default)]
#[repr(C)]
pub struct MCDCParameters {
/// Byte Index of Bitmap Coverage Object for a Decision Region.
bitmap_idx: u32,

/// Number of Conditions used for a Decision Region.
num_conditions: u32,

/// IDs used to represent a branch region and other branch regions
/// evaluated based on True and False branches.
id: u32,
true_id: u32,
false_id: u32,
}

/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
Expand Down Expand Up @@ -146,6 +176,8 @@ pub struct CounterMappingRegion {
end_col: u32,

kind: RegionKind,

mcdc_params: MCDCParameters,
}

impl CounterMappingRegion {
Expand All @@ -172,6 +204,33 @@ impl CounterMappingRegion {
start_col,
end_line,
end_col,
None,
),
MappingKind::MCDCBranch { true_term, false_term, id, true_id, false_id } => {
Self::branch_region(
Counter::from_term(true_term),
Counter::from_term(false_term),
local_file_id,
start_line,
start_col,
end_line,
end_col,
Some(MCDCParameters {
id,
true_id,
false_id,
.. Default::default()
}),
)
}
MappingKind::MCDCDecision { bitmap_idx, num_conditions } => Self::decision_region(
bitmap_idx,
num_conditions,
local_file_id,
start_line,
start_col,
end_line,
end_col,
),
}
}
Expand All @@ -194,9 +253,11 @@ impl CounterMappingRegion {
end_line,
end_col,
kind: RegionKind::CodeRegion,
mcdc_params: Default::default(),
}
}

/// - `mcdc_params` should be None when MCDC is disabled.
pub(crate) fn branch_region(
counter: Counter,
false_counter: Counter,
Expand All @@ -205,7 +266,13 @@ impl CounterMappingRegion {
start_col: u32,
end_line: u32,
end_col: u32,
mcdc_params: Option<MCDCParameters>,
) -> Self {
let (kind, mcdc_params) = match mcdc_params {
None => (RegionKind::BranchRegion, Default::default()),
Some(params) => (RegionKind::MCDCBranchRegion, params),
};

Self {
counter,
false_counter,
Expand All @@ -215,7 +282,31 @@ impl CounterMappingRegion {
start_col,
end_line,
end_col,
kind: RegionKind::BranchRegion,
kind,
mcdc_params,
}
}

pub(crate) fn decision_region(
bitmap_idx: u32,
num_conditions: u32,
file_id: u32,
start_line: u32,
start_col: u32,
end_line: u32,
end_col: u32,
) -> Self {
Self {
counter: Counter::ZERO,
false_counter: Counter::ZERO,
file_id,
expanded_file_id: 0,
start_line,
start_col,
end_line,
end_col,
kind: RegionKind::MCDCDecisionRegion,
mcdc_params: MCDCParameters { bitmap_idx, num_conditions, ..Default::default() },
}
}

Expand All @@ -240,6 +331,7 @@ impl CounterMappingRegion {
end_line,
end_col,
kind: RegionKind::ExpansionRegion,
mcdc_params: Default::default(),
}
}

Expand All @@ -263,6 +355,7 @@ impl CounterMappingRegion {
end_line,
end_col,
kind: RegionKind::SkippedRegion,
mcdc_params: Default::default(),
}
}

Expand All @@ -287,6 +380,7 @@ impl CounterMappingRegion {
end_line,
end_col: (1_u32 << 31) | end_col,
kind: RegionKind::GapRegion,
mcdc_params: Default::default(),
}
}
}
7 changes: 4 additions & 3 deletions compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ use rustc_span::Symbol;
pub fn finalize(cx: &CodegenCx<'_, '_>) {
let tcx = cx.tcx;

// Ensure the installed version of LLVM supports Coverage Map Version 6
// (encoded as a zero-based value: 5), which was introduced with LLVM 13.
// Ensure the installed version of LLVM supports Coverage Map Version 7
// (encoded as a zero-based value: 6), which was introduced with LLVM 13.
let version = coverageinfo::mapping_version();
assert_eq!(version, 5, "The `CoverageMappingVersion` exposed by `llvm-wrapper` is out of sync");
assert_eq!(version, 6, "The `CoverageMappingVersion` exposed by `llvm-wrapper` is out of sync");

debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());

Expand Down Expand Up @@ -276,6 +276,7 @@ fn encode_mappings_for_function(
/// Construct coverage map header and the array of function records, and combine them into the
/// coverage map. Save the coverage map data into the LLVM IR as a static global using a
/// specific, well-known section and name.
/// https://llvm.org/docs/CoverageMappingFormat.html#llvm-ir-representation
fn generate_coverage_map<'ll>(
cx: &CodegenCx<'ll, '_>,
version: u32,
Expand Down
Loading