Skip to content

Commit

Permalink
coverage. Adapt to mcdc mapping formats introduced by llvm 19
Browse files Browse the repository at this point in the history
  • Loading branch information
zhuyunxing committed Oct 8, 2024
1 parent 99bd601 commit 6e3e19f
Show file tree
Hide file tree
Showing 22 changed files with 493 additions and 488 deletions.
63 changes: 13 additions & 50 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1679,9 +1679,9 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
&mut self,
fn_name: &'ll Value,
hash: &'ll Value,
bitmap_bytes: &'ll Value,
bitmap_bits: &'ll Value,
) {
debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bytes);
debug!("mcdc_parameters() with args ({:?}, {:?}, {:?})", fn_name, hash, bitmap_bits);

assert!(
crate::llvm_util::get_version() >= (19, 0, 0),
Expand All @@ -1693,7 +1693,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
&[self.cx.type_ptr(), self.cx.type_i64(), self.cx.type_i32()],
self.cx.type_void(),
);
let args = &[fn_name, hash, bitmap_bytes];
let args = &[fn_name, hash, bitmap_bits];
let args = self.check_call("call", llty, llfn, args);

unsafe {
Expand All @@ -1713,13 +1713,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
&mut self,
fn_name: &'ll Value,
hash: &'ll Value,
bitmap_bytes: &'ll Value,
bitmap_index: &'ll Value,
mcdc_temp: &'ll Value,
) {
debug!(
"mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})",
fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp
"mcdc_tvbitmap_update() with args ({:?}, {:?}, {:?}, {:?})",
fn_name, hash, bitmap_index, mcdc_temp
);
assert!(
crate::llvm_util::get_version() >= (19, 0, 0),
Expand All @@ -1729,16 +1728,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
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_ptr(), self.cx.type_i64(), self.cx.type_i32(), self.cx.type_ptr()],
self.cx.type_void(),
);
let args = &[fn_name, hash, bitmap_bytes, bitmap_index, mcdc_temp];
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
let args = self.check_call("call", llty, llfn, args);
unsafe {
let _ = llvm::LLVMRustBuildCall(
Expand All @@ -1754,45 +1747,15 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
self.store(self.const_i32(0), mcdc_temp, self.tcx.data_layout.i32_align.abi);
}

pub(crate) fn mcdc_condbitmap_update(
&mut self,
fn_name: &'ll Value,
hash: &'ll Value,
cond_loc: &'ll Value,
mcdc_temp: &'ll Value,
bool_value: &'ll Value,
) {
debug!(
"mcdc_condbitmap_update() with args ({:?}, {:?}, {:?}, {:?}, {:?})",
fn_name, hash, cond_loc, mcdc_temp, bool_value
);
pub(crate) fn mcdc_condbitmap_update(&mut self, cond_index: &'ll Value, mcdc_temp: &'ll Value) {
debug!("mcdc_condbitmap_update() with args ({:?}, {:?})", cond_index, mcdc_temp);
assert!(
crate::llvm_util::get_version() >= (19, 0, 0),
"MCDC intrinsics require LLVM 19 or later"
);
let llfn = unsafe { llvm::LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(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_loc, mcdc_temp, bool_value];
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,
);
}
let align = self.tcx.data_layout.i32_align.abi;
let current_tv_index = self.load(self.cx.type_i32(), mcdc_temp, align);
let new_tv_index = self.add(current_tv_index, cond_index);
self.store(new_tv_index, mcdc_temp, align);
}
}
29 changes: 11 additions & 18 deletions compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,14 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
};

// If there are no MC/DC bitmaps to set up, return immediately.
if function_coverage_info.mcdc_bitmap_bytes == 0 {
if function_coverage_info.mcdc_bitmap_bits == 0 {
return;
}

let fn_name = self.get_pgo_func_name_var(instance);
let hash = self.const_u64(function_coverage_info.function_source_hash);
let bitmap_bytes = self.const_u32(function_coverage_info.mcdc_bitmap_bytes);
self.mcdc_parameters(fn_name, hash, bitmap_bytes);
let bitmap_bits = self.const_u32(function_coverage_info.mcdc_bitmap_bits as u32);
self.mcdc_parameters(fn_name, hash, bitmap_bits);

// Create pointers named `mcdc.addr.{i}` to stack-allocated condition bitmaps.
let mut cond_bitmaps = vec![];
Expand Down Expand Up @@ -185,35 +185,28 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
CoverageKind::ExpressionUsed { id } => {
func_coverage.mark_expression_id_seen(id);
}
CoverageKind::CondBitmapUpdate { id, value, decision_depth } => {
CoverageKind::CondBitmapUpdate { index, decision_depth } => {
drop(coverage_map);
assert_ne!(
id.as_u32(),
0,
"ConditionId of evaluated conditions should never be zero"
);
let cond_bitmap = coverage_context
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
.expect("mcdc cond bitmap should have been allocated for updating");
let cond_loc = bx.const_i32(id.as_u32() as i32 - 1);
let bool_value = bx.const_bool(value);
let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_coverage_info.function_source_hash);
bx.mcdc_condbitmap_update(fn_name, hash, cond_loc, cond_bitmap, bool_value);
let cond_index = bx.const_i32(index as i32);
bx.mcdc_condbitmap_update(cond_index, cond_bitmap);
}
CoverageKind::TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
drop(coverage_map);
let cond_bitmap = coverage_context
.try_get_mcdc_condition_bitmap(&instance, decision_depth)
.expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
let bitmap_bytes = function_coverage_info.mcdc_bitmap_bytes;
assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range");
assert!(
bitmap_idx as usize <= function_coverage_info.mcdc_bitmap_bits,
"bitmap index of the decision out of range"
);

let fn_name = bx.get_pgo_func_name_var(instance);
let hash = bx.const_u64(function_coverage_info.function_source_hash);
let bitmap_bytes = bx.const_u32(bitmap_bytes);
let bitmap_index = bx.const_u32(bitmap_idx);
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_bytes, bitmap_index, cond_bitmap);
bx.mcdc_tvbitmap_update(fn_name, hash, bitmap_index, cond_bitmap);
}
}
}
Expand Down
1 change: 0 additions & 1 deletion compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1614,7 +1614,6 @@ unsafe extern "C" {
pub fn LLVMRustGetInstrProfIncrementIntrinsic(M: &Module) -> &Value;
pub fn LLVMRustGetInstrProfMCDCParametersIntrinsic(M: &Module) -> &Value;
pub fn LLVMRustGetInstrProfMCDCTVBitmapUpdateIntrinsic(M: &Module) -> &Value;
pub fn LLVMRustGetInstrProfMCDCCondBitmapIntrinsic(M: &Module) -> &Value;

pub fn LLVMRustBuildCall<'a>(
B: &Builder<'a>,
Expand Down
29 changes: 11 additions & 18 deletions compiler/rustc_middle/src/mir/coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ pub enum CoverageKind {

/// Marks the point in MIR control flow represented by a evaluated condition.
///
/// This is eventually lowered to `llvm.instrprof.mcdc.condbitmap.update` in LLVM IR.
CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 },
/// This is eventually lowered to instruments updating mcdc temp variables.
CondBitmapUpdate { index: u32, decision_depth: u16 },

/// Marks the point in MIR control flow represented by a evaluated decision.
///
Expand All @@ -145,14 +145,8 @@ impl Debug for CoverageKind {
BlockMarker { id } => write!(fmt, "BlockMarker({:?})", id.index()),
CounterIncrement { id } => write!(fmt, "CounterIncrement({:?})", id.index()),
ExpressionUsed { id } => write!(fmt, "ExpressionUsed({:?})", id.index()),
CondBitmapUpdate { id, value, decision_depth } => {
write!(
fmt,
"CondBitmapUpdate({:?}, {:?}, depth={:?})",
id.index(),
value,
decision_depth
)
CondBitmapUpdate { index, decision_depth } => {
write!(fmt, "CondBitmapUpdate(index={:?}, depth={:?})", index, decision_depth)
}
TestVectorBitmapUpdate { bitmap_idx, decision_depth } => {
write!(fmt, "TestVectorUpdate({:?}, depth={:?})", bitmap_idx, decision_depth)
Expand Down Expand Up @@ -253,7 +247,7 @@ pub struct Mapping {
pub struct FunctionCoverageInfo {
pub function_source_hash: u64,
pub num_counters: usize,
pub mcdc_bitmap_bytes: u32,
pub mcdc_bitmap_bits: usize,
pub expressions: IndexVec<ExpressionId, Expression>,
pub mappings: Vec<Mapping>,
/// The depth of the deepest decision is used to know how many
Expand All @@ -275,8 +269,10 @@ pub struct CoverageInfoHi {
/// data structures without having to scan the entire body first.
pub num_block_markers: usize,
pub branch_spans: Vec<BranchSpan>,
pub mcdc_branch_spans: Vec<MCDCBranchSpan>,
pub mcdc_decision_spans: Vec<MCDCDecisionSpan>,
/// Branch spans generated by mcdc. Because of some limits mcdc builder give up generating
/// decisions including them so that they are handled as normal branch spans.
pub mcdc_degraded_branch_spans: Vec<MCDCBranchSpan>,
pub mcdc_spans: Vec<(MCDCDecisionSpan, Vec<MCDCBranchSpan>)>,
}

#[derive(Clone, Debug)]
Expand All @@ -299,12 +295,9 @@ pub struct ConditionInfo {
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct MCDCBranchSpan {
pub span: Span,
/// If `None`, this actually represents a normal branch span inserted for
/// code that was too complex for MC/DC.
pub condition_info: Option<ConditionInfo>,
pub condition_info: ConditionInfo,
pub true_marker: BlockMarkerId,
pub false_marker: BlockMarkerId,
pub decision_depth: u16,
}

#[derive(Copy, Clone, Debug)]
Expand All @@ -318,7 +311,7 @@ pub struct DecisionInfo {
#[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct MCDCDecisionSpan {
pub span: Span,
pub num_conditions: usize,
pub end_markers: Vec<BlockMarkerId>,
pub decision_depth: u16,
pub num_conditions: usize,
}
32 changes: 19 additions & 13 deletions compiler/rustc_middle/src/mir/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,8 +538,8 @@ fn write_coverage_info_hi(
let coverage::CoverageInfoHi {
num_block_markers: _,
branch_spans,
mcdc_branch_spans,
mcdc_decision_spans,
mcdc_degraded_branch_spans,
mcdc_spans,
} = coverage_info_hi;

// Only add an extra trailing newline if we printed at least one thing.
Expand All @@ -553,29 +553,35 @@ fn write_coverage_info_hi(
did_print = true;
}

for coverage::MCDCBranchSpan {
span,
condition_info,
true_marker,
false_marker,
decision_depth,
} in mcdc_branch_spans
for coverage::MCDCBranchSpan { span, true_marker, false_marker, .. } in
mcdc_degraded_branch_spans
{
writeln!(
w,
"{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?}, depth: {decision_depth:?} }} => {span:?}",
condition_info.map(|info| info.condition_id)
"{INDENT}coverage branch {{ true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
)?;
did_print = true;
}

for coverage::MCDCDecisionSpan { span, num_conditions, end_markers, decision_depth } in
mcdc_decision_spans
for (
coverage::MCDCDecisionSpan { span, end_markers, decision_depth, num_conditions: _ },
conditions,
) in mcdc_spans
{
let num_conditions = conditions.len();
writeln!(
w,
"{INDENT}coverage mcdc decision {{ num_conditions: {num_conditions:?}, end: {end_markers:?}, depth: {decision_depth:?} }} => {span:?}"
)?;
for coverage::MCDCBranchSpan { span, condition_info, true_marker, false_marker } in
conditions
{
writeln!(
w,
"{INDENT}coverage mcdc branch {{ condition_id: {:?}, true: {true_marker:?}, false: {false_marker:?} }} => {span:?}",
condition_info.condition_id
)?;
}
did_print = true;
}

Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_mir_build/src/build/coverageinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,16 +175,16 @@ impl CoverageInfoBuilder {
let branch_spans =
branch_info.map(|branch_info| branch_info.branch_spans).unwrap_or_default();

let (mcdc_decision_spans, mcdc_branch_spans) =
let (mcdc_spans, mcdc_degraded_branch_spans) =
mcdc_info.map(MCDCInfoBuilder::into_done).unwrap_or_default();

// For simplicity, always return an info struct (without Option), even
// if there's nothing interesting in it.
Box::new(CoverageInfoHi {
num_block_markers,
branch_spans,
mcdc_branch_spans,
mcdc_decision_spans,
mcdc_degraded_branch_spans,
mcdc_spans,
})
}
}
Expand Down
Loading

0 comments on commit 6e3e19f

Please sign in to comment.