Pass coverage mappings to LLVM as separate structs

This commit is contained in:
Zalathar 2024-10-19 22:22:43 +11:00
parent 98c4d96957
commit d1bf77eb34
5 changed files with 207 additions and 431 deletions

View file

@ -1,6 +1,4 @@
use rustc_middle::mir::coverage::{ use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId, SourceRegion};
ConditionInfo, CounterId, CovTerm, DecisionInfo, ExpressionId, MappingKind, SourceRegion,
};
/// Must match the layout of `LLVMRustCounterKind`. /// Must match the layout of `LLVMRustCounterKind`.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -75,42 +73,7 @@ pub(crate) struct CounterExpression {
pub(crate) rhs: Counter, pub(crate) rhs: Counter,
} }
/// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`. pub(crate) mod mcdc {
///
/// Must match the layout of `LLVMRustCounterMappingRegionKind`.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
enum RegionKind {
/// A CodeRegion associates some code with a counter
CodeRegion = 0,
/// An ExpansionRegion represents a file expansion region that associates
/// a source range with the expansion of a virtual source file, such as
/// for a macro instantiation or #include file.
ExpansionRegion = 1,
/// A SkippedRegion represents a source range with code that was skipped
/// by a preprocessor or similar means.
SkippedRegion = 2,
/// A GapRegion is like a CodeRegion, but its count is only set as the
/// line execution count when its the only region in the line.
GapRegion = 3,
/// A BranchRegion represents leaf-level boolean expressions and is
/// 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.
MCDCBranchRegion = 6,
}
mod mcdc {
use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo}; use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo};
/// Must match the layout of `LLVMRustMCDCDecisionParameters`. /// Must match the layout of `LLVMRustMCDCDecisionParameters`.
@ -121,8 +84,6 @@ mod mcdc {
num_conditions: u16, num_conditions: u16,
} }
// ConditionId in llvm is `unsigned int` at 18 while `int16_t` at
// [19](https://github.com/llvm/llvm-project/pull/81257).
type LLVMConditionId = i16; type LLVMConditionId = i16;
/// Must match the layout of `LLVMRustMCDCBranchParameters`. /// Must match the layout of `LLVMRustMCDCBranchParameters`.
@ -133,38 +94,6 @@ mod mcdc {
condition_ids: [LLVMConditionId; 2], condition_ids: [LLVMConditionId; 2],
} }
#[repr(C)]
#[derive(Clone, Copy, Debug)]
enum ParameterTag {
None = 0,
Decision = 1,
Branch = 2,
}
/// Same layout with `LLVMRustMCDCParameters`
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub(crate) struct Parameters {
tag: ParameterTag,
decision_params: DecisionParameters,
branch_params: BranchParameters,
}
impl Parameters {
pub(crate) fn none() -> Self {
Self {
tag: ParameterTag::None,
decision_params: Default::default(),
branch_params: Default::default(),
}
}
pub(crate) fn decision(decision_params: DecisionParameters) -> Self {
Self { tag: ParameterTag::Decision, decision_params, branch_params: Default::default() }
}
pub(crate) fn branch(branch_params: BranchParameters) -> Self {
Self { tag: ParameterTag::Branch, decision_params: Default::default(), branch_params }
}
}
impl From<ConditionInfo> for BranchParameters { impl From<ConditionInfo> for BranchParameters {
fn from(value: ConditionInfo) -> Self { fn from(value: ConditionInfo) -> Self {
let to_llvm_cond_id = |cond_id: Option<ConditionId>| { let to_llvm_cond_id = |cond_id: Option<ConditionId>| {
@ -186,267 +115,68 @@ mod mcdc {
} }
} }
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the /// A span of source code coordinates to be embedded in coverage metadata.
/// coverage map, in accordance with the
/// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
/// The struct composes fields representing the `Counter` type and value(s) (injected counter
/// ID, or expression type and operands), the source file (an indirect index into a "filenames
/// array", encoded separately), and source location (start and end positions of the represented
/// code region).
/// ///
/// Corresponds to struct `llvm::coverage::CounterMappingRegion`. /// Must match the layout of `LLVMRustCoverageSpan`.
/// #[derive(Clone, Debug)]
/// Must match the layout of `LLVMRustCounterMappingRegion`.
#[derive(Copy, Clone, Debug)]
#[repr(C)] #[repr(C)]
pub(crate) struct CounterMappingRegion { pub(crate) struct CoverageSpan {
/// The counter type and type-dependent counter data, if any. /// Local index into the function's local-to-global file ID table.
counter: Counter, /// The value at that index is itself an index into the coverage filename
/// table in the CGU's `__llvm_covmap` section.
/// If the `RegionKind` is a `BranchRegion`, this represents the counter
/// for the false branch of the region.
false_counter: Counter,
mcdc_params: mcdc::Parameters,
/// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
/// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
/// that, in turn, are used to look up the filename for this region.
file_id: u32, file_id: u32,
/// If the `RegionKind` is an `ExpansionRegion`, the `expanded_file_id` can be used to find /// 1-based starting line of the source code span.
/// the mapping regions created as a result of macro expansion, by checking if their file id
/// matches the expanded file id.
expanded_file_id: u32,
/// 1-based starting line of the mapping region.
start_line: u32, start_line: u32,
/// 1-based starting column of the source code span.
/// 1-based starting column of the mapping region.
start_col: u32, start_col: u32,
/// 1-based ending line of the source code span.
/// 1-based ending line of the mapping region.
end_line: u32, end_line: u32,
/// 1-based ending column of the source code span. High bit must be unset.
/// 1-based ending column of the mapping region. If the high bit is set, the current
/// mapping region is a gap area.
end_col: u32, end_col: u32,
kind: RegionKind,
} }
impl CounterMappingRegion { impl CoverageSpan {
pub(crate) fn from_mapping( pub(crate) fn from_source_region(file_id: u32, code_region: &SourceRegion) -> Self {
mapping_kind: &MappingKind, let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = code_region;
local_file_id: u32, // Internally, LLVM uses the high bit of `end_col` to distinguish between
source_region: &SourceRegion, // code regions and gap regions, so it can't be used by the column number.
) -> Self { assert!(end_col & (1u32 << 31) == 0, "high bit of `end_col` must be unset: {end_col:#X}");
let &SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = Self { file_id, start_line, start_col, end_line, end_col }
source_region;
match *mapping_kind {
MappingKind::Code(term) => Self::code_region(
Counter::from_term(term),
local_file_id,
start_line,
start_col,
end_line,
end_col,
),
MappingKind::Branch { true_term, false_term } => Self::branch_region(
Counter::from_term(true_term),
Counter::from_term(false_term),
local_file_id,
start_line,
start_col,
end_line,
end_col,
),
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
Self::mcdc_branch_region(
Counter::from_term(true_term),
Counter::from_term(false_term),
mcdc_params,
local_file_id,
start_line,
start_col,
end_line,
end_col,
)
}
MappingKind::MCDCDecision(decision_info) => Self::decision_region(
decision_info,
local_file_id,
start_line,
start_col,
end_line,
end_col,
),
}
}
pub(crate) fn code_region(
counter: Counter,
file_id: u32,
start_line: u32,
start_col: u32,
end_line: u32,
end_col: u32,
) -> Self {
Self {
counter,
false_counter: Counter::ZERO,
mcdc_params: mcdc::Parameters::none(),
file_id,
expanded_file_id: 0,
start_line,
start_col,
end_line,
end_col,
kind: RegionKind::CodeRegion,
}
}
pub(crate) fn branch_region(
counter: Counter,
false_counter: Counter,
file_id: u32,
start_line: u32,
start_col: u32,
end_line: u32,
end_col: u32,
) -> Self {
Self {
counter,
false_counter,
mcdc_params: mcdc::Parameters::none(),
file_id,
expanded_file_id: 0,
start_line,
start_col,
end_line,
end_col,
kind: RegionKind::BranchRegion,
}
}
pub(crate) fn mcdc_branch_region(
counter: Counter,
false_counter: Counter,
condition_info: ConditionInfo,
file_id: u32,
start_line: u32,
start_col: u32,
end_line: u32,
end_col: u32,
) -> Self {
Self {
counter,
false_counter,
mcdc_params: mcdc::Parameters::branch(condition_info.into()),
file_id,
expanded_file_id: 0,
start_line,
start_col,
end_line,
end_col,
kind: RegionKind::MCDCBranchRegion,
}
}
pub(crate) fn decision_region(
decision_info: DecisionInfo,
file_id: u32,
start_line: u32,
start_col: u32,
end_line: u32,
end_col: u32,
) -> Self {
let mcdc_params = mcdc::Parameters::decision(decision_info.into());
Self {
counter: Counter::ZERO,
false_counter: Counter::ZERO,
mcdc_params,
file_id,
expanded_file_id: 0,
start_line,
start_col,
end_line,
end_col,
kind: RegionKind::MCDCDecisionRegion,
}
}
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
pub(crate) fn expansion_region(
file_id: u32,
expanded_file_id: u32,
start_line: u32,
start_col: u32,
end_line: u32,
end_col: u32,
) -> Self {
Self {
counter: Counter::ZERO,
false_counter: Counter::ZERO,
mcdc_params: mcdc::Parameters::none(),
file_id,
expanded_file_id,
start_line,
start_col,
end_line,
end_col,
kind: RegionKind::ExpansionRegion,
}
}
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
pub(crate) fn skipped_region(
file_id: u32,
start_line: u32,
start_col: u32,
end_line: u32,
end_col: u32,
) -> Self {
Self {
counter: Counter::ZERO,
false_counter: Counter::ZERO,
mcdc_params: mcdc::Parameters::none(),
file_id,
expanded_file_id: 0,
start_line,
start_col,
end_line,
end_col,
kind: RegionKind::SkippedRegion,
}
}
// This function might be used in the future; the LLVM API is still evolving, as is coverage
// support.
#[allow(dead_code)]
pub(crate) fn gap_region(
counter: Counter,
file_id: u32,
start_line: u32,
start_col: u32,
end_line: u32,
end_col: u32,
) -> Self {
Self {
counter,
false_counter: Counter::ZERO,
mcdc_params: mcdc::Parameters::none(),
file_id,
expanded_file_id: 0,
start_line,
start_col,
end_line,
end_col: (1_u32 << 31) | end_col,
kind: RegionKind::GapRegion,
}
} }
} }
/// Must match the layout of `LLVMRustCoverageCodeRegion`.
#[derive(Clone, Debug)]
#[repr(C)]
pub(crate) struct CodeRegion {
pub(crate) span: CoverageSpan,
pub(crate) counter: Counter,
}
/// Must match the layout of `LLVMRustCoverageBranchRegion`.
#[derive(Clone, Debug)]
#[repr(C)]
pub(crate) struct BranchRegion {
pub(crate) span: CoverageSpan,
pub(crate) true_counter: Counter,
pub(crate) false_counter: Counter,
}
/// Must match the layout of `LLVMRustCoverageMCDCBranchRegion`.
#[derive(Clone, Debug)]
#[repr(C)]
pub(crate) struct MCDCBranchRegion {
pub(crate) span: CoverageSpan,
pub(crate) true_counter: Counter,
pub(crate) false_counter: Counter,
pub(crate) mcdc_branch_params: mcdc::BranchParameters,
}
/// Must match the layout of `LLVMRustCoverageMCDCDecisionRegion`.
#[derive(Clone, Debug)]
#[repr(C)]
pub(crate) struct MCDCDecisionRegion {
pub(crate) span: CoverageSpan,
pub(crate) mcdc_decision_params: mcdc::DecisionParameters,
}

View file

@ -3,6 +3,7 @@ use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::mir::coverage::MappingKind;
use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::{bug, mir}; use rustc_middle::{bug, mir};
use rustc_span::Symbol; use rustc_span::Symbol;
@ -10,7 +11,7 @@ use rustc_span::def_id::DefIdSet;
use tracing::debug; use tracing::debug;
use crate::common::CodegenCx; use crate::common::CodegenCx;
use crate::coverageinfo::ffi::CounterMappingRegion; use crate::coverageinfo::ffi;
use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector}; use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector};
use crate::{coverageinfo, llvm}; use crate::{coverageinfo, llvm};
@ -235,7 +236,10 @@ fn encode_mappings_for_function(
let expressions = function_coverage.counter_expressions().collect::<Vec<_>>(); let expressions = function_coverage.counter_expressions().collect::<Vec<_>>();
let mut virtual_file_mapping = VirtualFileMapping::default(); let mut virtual_file_mapping = VirtualFileMapping::default();
let mut mapping_regions = Vec::with_capacity(counter_regions.len()); let mut code_regions = vec![];
let mut branch_regions = vec![];
let mut mcdc_branch_regions = vec![];
let mut mcdc_decision_regions = vec![];
// Group mappings into runs with the same filename, preserving the order // Group mappings into runs with the same filename, preserving the order
// yielded by `FunctionCoverage`. // yielded by `FunctionCoverage`.
@ -255,11 +259,36 @@ fn encode_mappings_for_function(
// form suitable for FFI. // form suitable for FFI.
for (mapping_kind, region) in counter_regions_for_file { for (mapping_kind, region) in counter_regions_for_file {
debug!("Adding counter {mapping_kind:?} to map for {region:?}"); debug!("Adding counter {mapping_kind:?} to map for {region:?}");
mapping_regions.push(CounterMappingRegion::from_mapping( let span = ffi::CoverageSpan::from_source_region(local_file_id.as_u32(), region);
&mapping_kind, match mapping_kind {
local_file_id.as_u32(), MappingKind::Code(term) => {
region, code_regions
)); .push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) });
}
MappingKind::Branch { true_term, false_term } => {
branch_regions.push(ffi::BranchRegion {
span,
true_counter: ffi::Counter::from_term(true_term),
false_counter: ffi::Counter::from_term(false_term),
});
}
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
mcdc_branch_regions.push(ffi::MCDCBranchRegion {
span,
true_counter: ffi::Counter::from_term(true_term),
false_counter: ffi::Counter::from_term(false_term),
mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params),
});
}
MappingKind::MCDCDecision(mcdc_decision_params) => {
mcdc_decision_regions.push(ffi::MCDCDecisionRegion {
span,
mcdc_decision_params: ffi::mcdc::DecisionParameters::from(
mcdc_decision_params,
),
});
}
}
} }
} }
@ -268,7 +297,10 @@ fn encode_mappings_for_function(
coverageinfo::write_mapping_to_buffer( coverageinfo::write_mapping_to_buffer(
virtual_file_mapping.into_vec(), virtual_file_mapping.into_vec(),
expressions, expressions,
mapping_regions, &code_regions,
&branch_regions,
&mcdc_branch_regions,
&mcdc_decision_regions,
buffer, buffer,
); );
}) })

View file

@ -16,7 +16,6 @@ use tracing::{debug, instrument};
use crate::builder::Builder; use crate::builder::Builder;
use crate::common::CodegenCx; use crate::common::CodegenCx;
use crate::coverageinfo::ffi::{CounterExpression, CounterMappingRegion};
use crate::coverageinfo::map_data::FunctionCoverageCollector; use crate::coverageinfo::map_data::FunctionCoverageCollector;
use crate::llvm; use crate::llvm;
@ -255,8 +254,11 @@ pub(crate) fn write_filenames_section_to_buffer<'a>(
pub(crate) fn write_mapping_to_buffer( pub(crate) fn write_mapping_to_buffer(
virtual_file_mapping: Vec<u32>, virtual_file_mapping: Vec<u32>,
expressions: Vec<CounterExpression>, expressions: Vec<ffi::CounterExpression>,
mapping_regions: Vec<CounterMappingRegion>, code_regions: &[ffi::CodeRegion],
branch_regions: &[ffi::BranchRegion],
mcdc_branch_regions: &[ffi::MCDCBranchRegion],
mcdc_decision_regions: &[ffi::MCDCDecisionRegion],
buffer: &RustString, buffer: &RustString,
) { ) {
unsafe { unsafe {
@ -265,8 +267,14 @@ pub(crate) fn write_mapping_to_buffer(
virtual_file_mapping.len() as c_uint, virtual_file_mapping.len() as c_uint,
expressions.as_ptr(), expressions.as_ptr(),
expressions.len() as c_uint, expressions.len() as c_uint,
mapping_regions.as_ptr(), code_regions.as_ptr(),
mapping_regions.len() as c_uint, code_regions.len() as c_uint,
branch_regions.as_ptr(),
branch_regions.len() as c_uint,
mcdc_branch_regions.as_ptr(),
mcdc_branch_regions.len() as c_uint,
mcdc_decision_regions.as_ptr(),
mcdc_decision_regions.len() as c_uint,
buffer, buffer,
); );
} }

View file

@ -1754,8 +1754,14 @@ unsafe extern "C" {
NumVirtualFileMappingIDs: c_uint, NumVirtualFileMappingIDs: c_uint,
Expressions: *const crate::coverageinfo::ffi::CounterExpression, Expressions: *const crate::coverageinfo::ffi::CounterExpression,
NumExpressions: c_uint, NumExpressions: c_uint,
MappingRegions: *const crate::coverageinfo::ffi::CounterMappingRegion, CodeRegions: *const crate::coverageinfo::ffi::CodeRegion,
NumMappingRegions: c_uint, NumCodeRegions: c_uint,
BranchRegions: *const crate::coverageinfo::ffi::BranchRegion,
NumBranchRegions: c_uint,
MCDCBranchRegions: *const crate::coverageinfo::ffi::MCDCBranchRegion,
NumMCDCBranchRegions: c_uint,
MCDCDecisionRegions: *const crate::coverageinfo::ffi::MCDCDecisionRegion,
NumMCDCDecisionRegions: c_uint,
BufferOut: &RustString, BufferOut: &RustString,
); );

View file

@ -33,45 +33,6 @@ static coverage::Counter fromRust(LLVMRustCounter Counter) {
report_fatal_error("Bad LLVMRustCounterKind!"); report_fatal_error("Bad LLVMRustCounterKind!");
} }
// FFI equivalent of enum `llvm::coverage::CounterMappingRegion::RegionKind`
// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L213-L234
enum class LLVMRustCounterMappingRegionKind {
CodeRegion = 0,
ExpansionRegion = 1,
SkippedRegion = 2,
GapRegion = 3,
BranchRegion = 4,
MCDCDecisionRegion = 5,
MCDCBranchRegion = 6
};
static coverage::CounterMappingRegion::RegionKind
fromRust(LLVMRustCounterMappingRegionKind Kind) {
switch (Kind) {
case LLVMRustCounterMappingRegionKind::CodeRegion:
return coverage::CounterMappingRegion::CodeRegion;
case LLVMRustCounterMappingRegionKind::ExpansionRegion:
return coverage::CounterMappingRegion::ExpansionRegion;
case LLVMRustCounterMappingRegionKind::SkippedRegion:
return coverage::CounterMappingRegion::SkippedRegion;
case LLVMRustCounterMappingRegionKind::GapRegion:
return coverage::CounterMappingRegion::GapRegion;
case LLVMRustCounterMappingRegionKind::BranchRegion:
return coverage::CounterMappingRegion::BranchRegion;
case LLVMRustCounterMappingRegionKind::MCDCDecisionRegion:
return coverage::CounterMappingRegion::MCDCDecisionRegion;
case LLVMRustCounterMappingRegionKind::MCDCBranchRegion:
return coverage::CounterMappingRegion::MCDCBranchRegion;
}
report_fatal_error("Bad LLVMRustCounterMappingRegionKind!");
}
enum LLVMRustMCDCParametersTag {
None = 0,
Decision = 1,
Branch = 2,
};
struct LLVMRustMCDCDecisionParameters { struct LLVMRustMCDCDecisionParameters {
uint32_t BitmapIdx; uint32_t BitmapIdx;
uint16_t NumConditions; uint16_t NumConditions;
@ -82,47 +43,58 @@ struct LLVMRustMCDCBranchParameters {
int16_t ConditionIDs[2]; int16_t ConditionIDs[2];
}; };
struct LLVMRustMCDCParameters {
LLVMRustMCDCParametersTag Tag;
LLVMRustMCDCDecisionParameters DecisionParameters;
LLVMRustMCDCBranchParameters BranchParameters;
};
#if LLVM_VERSION_GE(19, 0) #if LLVM_VERSION_GE(19, 0)
static coverage::mcdc::Parameters fromRust(LLVMRustMCDCParameters Params) { static coverage::mcdc::BranchParameters
switch (Params.Tag) { fromRust(LLVMRustMCDCBranchParameters Params) {
case LLVMRustMCDCParametersTag::None: return coverage::mcdc::BranchParameters(
return std::monostate(); Params.ConditionID, {Params.ConditionIDs[0], Params.ConditionIDs[1]});
case LLVMRustMCDCParametersTag::Decision: }
return coverage::mcdc::DecisionParameters(
Params.DecisionParameters.BitmapIdx, static coverage::mcdc::DecisionParameters
Params.DecisionParameters.NumConditions); fromRust(LLVMRustMCDCDecisionParameters Params) {
case LLVMRustMCDCParametersTag::Branch: return coverage::mcdc::DecisionParameters(Params.BitmapIdx,
return coverage::mcdc::BranchParameters( Params.NumConditions);
static_cast<coverage::mcdc::ConditionID>(
Params.BranchParameters.ConditionID),
{static_cast<coverage::mcdc::ConditionID>(
Params.BranchParameters.ConditionIDs[0]),
static_cast<coverage::mcdc::ConditionID>(
Params.BranchParameters.ConditionIDs[1])});
}
report_fatal_error("Bad LLVMRustMCDCParametersTag!");
} }
#endif #endif
// FFI equivalent of struct `llvm::coverage::CounterMappingRegion` // Must match the layout of
// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L211-L304 // `rustc_codegen_llvm::coverageinfo::ffi::CoverageSpan`.
struct LLVMRustCounterMappingRegion { struct LLVMRustCoverageSpan {
LLVMRustCounter Count;
LLVMRustCounter FalseCount;
LLVMRustMCDCParameters MCDCParameters;
uint32_t FileID; uint32_t FileID;
uint32_t ExpandedFileID;
uint32_t LineStart; uint32_t LineStart;
uint32_t ColumnStart; uint32_t ColumnStart;
uint32_t LineEnd; uint32_t LineEnd;
uint32_t ColumnEnd; uint32_t ColumnEnd;
LLVMRustCounterMappingRegionKind Kind; };
// Must match the layout of `rustc_codegen_llvm::coverageinfo::ffi::CodeRegion`.
struct LLVMRustCoverageCodeRegion {
LLVMRustCoverageSpan Span;
LLVMRustCounter Count;
};
// Must match the layout of
// `rustc_codegen_llvm::coverageinfo::ffi::BranchRegion`.
struct LLVMRustCoverageBranchRegion {
LLVMRustCoverageSpan Span;
LLVMRustCounter TrueCount;
LLVMRustCounter FalseCount;
};
// Must match the layout of
// `rustc_codegen_llvm::coverageinfo::ffi::MCDCBranchRegion`.
struct LLVMRustCoverageMCDCBranchRegion {
LLVMRustCoverageSpan Span;
LLVMRustCounter TrueCount;
LLVMRustCounter FalseCount;
LLVMRustMCDCBranchParameters MCDCBranchParams;
};
// Must match the layout of
// `rustc_codegen_llvm::coverageinfo::ffi::MCDCDecisionRegion`.
struct LLVMRustCoverageMCDCDecisionRegion {
LLVMRustCoverageSpan Span;
LLVMRustMCDCDecisionParameters MCDCDecisionParams;
}; };
// FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind` // FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind`
@ -174,28 +146,16 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
extern "C" void LLVMRustCoverageWriteMappingToBuffer( extern "C" void LLVMRustCoverageWriteMappingToBuffer(
const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs, const unsigned *VirtualFileMappingIDs, unsigned NumVirtualFileMappingIDs,
const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions, const LLVMRustCounterExpression *RustExpressions, unsigned NumExpressions,
const LLVMRustCounterMappingRegion *RustMappingRegions, const LLVMRustCoverageCodeRegion *CodeRegions, unsigned NumCodeRegions,
unsigned NumMappingRegions, RustStringRef BufferOut) { const LLVMRustCoverageBranchRegion *BranchRegions,
unsigned NumBranchRegions,
const LLVMRustCoverageMCDCBranchRegion *MCDCBranchRegions,
unsigned NumMCDCBranchRegions,
const LLVMRustCoverageMCDCDecisionRegion *MCDCDecisionRegions,
unsigned NumMCDCDecisionRegions, RustStringRef BufferOut) {
// Convert from FFI representation to LLVM representation. // Convert from FFI representation to LLVM representation.
SmallVector<coverage::CounterMappingRegion, 0> MappingRegions;
MappingRegions.reserve(NumMappingRegions);
for (const auto &Region : ArrayRef<LLVMRustCounterMappingRegion>(
RustMappingRegions, NumMappingRegions)) {
MappingRegions.emplace_back(
fromRust(Region.Count), fromRust(Region.FalseCount),
#if LLVM_VERSION_LT(19, 0)
coverage::CounterMappingRegion::MCDCParameters{},
#endif
Region.FileID, Region.ExpandedFileID, // File IDs, then region info.
Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
fromRust(Region.Kind)
#if LLVM_VERSION_GE(19, 0)
,
fromRust(Region.MCDCParameters)
#endif
);
}
// Expressions:
std::vector<coverage::CounterExpression> Expressions; std::vector<coverage::CounterExpression> Expressions;
Expressions.reserve(NumExpressions); Expressions.reserve(NumExpressions);
for (const auto &Expression : for (const auto &Expression :
@ -205,6 +165,46 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
fromRust(Expression.RHS)); fromRust(Expression.RHS));
} }
std::vector<coverage::CounterMappingRegion> MappingRegions;
MappingRegions.reserve(NumCodeRegions + NumBranchRegions +
NumMCDCBranchRegions + NumMCDCDecisionRegions);
// Code regions:
for (const auto &Region : ArrayRef(CodeRegions, NumCodeRegions)) {
MappingRegions.push_back(coverage::CounterMappingRegion::makeRegion(
fromRust(Region.Count), Region.Span.FileID, Region.Span.LineStart,
Region.Span.ColumnStart, Region.Span.LineEnd, Region.Span.ColumnEnd));
}
// Branch regions:
for (const auto &Region : ArrayRef(BranchRegions, NumBranchRegions)) {
MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
fromRust(Region.TrueCount), fromRust(Region.FalseCount),
Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
Region.Span.LineEnd, Region.Span.ColumnEnd));
}
#if LLVM_VERSION_GE(19, 0)
// MC/DC branch regions:
for (const auto &Region : ArrayRef(MCDCBranchRegions, NumMCDCBranchRegions)) {
MappingRegions.push_back(coverage::CounterMappingRegion::makeBranchRegion(
fromRust(Region.TrueCount), fromRust(Region.FalseCount),
Region.Span.FileID, Region.Span.LineStart, Region.Span.ColumnStart,
Region.Span.LineEnd, Region.Span.ColumnEnd,
fromRust(Region.MCDCBranchParams)));
}
// MC/DC decision regions:
for (const auto &Region :
ArrayRef(MCDCDecisionRegions, NumMCDCDecisionRegions)) {
MappingRegions.push_back(coverage::CounterMappingRegion::makeDecisionRegion(
fromRust(Region.MCDCDecisionParams), Region.Span.FileID,
Region.Span.LineStart, Region.Span.ColumnStart, Region.Span.LineEnd,
Region.Span.ColumnEnd));
}
#endif
// Write the converted expressions and mappings to a byte buffer.
auto CoverageMappingWriter = coverage::CoverageMappingWriter( auto CoverageMappingWriter = coverage::CoverageMappingWriter(
ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs), ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
Expressions, MappingRegions); Expressions, MappingRegions);