Skip to content

Commit cf6b6cb

Browse files
author
zhuyunxing
committed
coverage. Generate Mappings of decisions and conditions for MC/DC
1 parent 68f8638 commit cf6b6cb

File tree

10 files changed

+779
-41
lines changed

10 files changed

+779
-41
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs

+157-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use rustc_middle::mir::coverage::{CodeRegion, CounterId, CovTerm, ExpressionId, MappingKind};
1+
use rustc_middle::mir::coverage::{
2+
CodeRegion, ConditionInfo, CounterId, CovTerm, DecisionInfo, ExpressionId, MappingKind,
3+
};
24

35
/// Must match the layout of `LLVMRustCounterKind`.
46
#[derive(Copy, Clone, Debug)]
@@ -99,6 +101,86 @@ pub enum RegionKind {
99101
/// associated with two counters, each representing the number of times the
100102
/// expression evaluates to true or false.
101103
BranchRegion = 4,
104+
105+
/// A DecisionRegion represents a top-level boolean expression and is
106+
/// associated with a variable length bitmap index and condition number.
107+
MCDCDecisionRegion = 5,
108+
109+
/// A Branch Region can be extended to include IDs to facilitate MC/DC.
110+
MCDCBranchRegion = 6,
111+
}
112+
113+
pub mod mcdc {
114+
use rustc_middle::mir::coverage::{ConditionInfo, DecisionInfo};
115+
116+
/// Must match the layout of `LLVMRustMCDCDecisionParameters`.
117+
#[repr(C)]
118+
#[derive(Clone, Copy, Debug, Default)]
119+
pub struct DecisionParameters {
120+
bitmap_idx: u32,
121+
conditions_num: u16,
122+
}
123+
124+
// ConditionId in llvm is `unsigned int` at 18 while `int16_t` at [19](https://github.com/llvm/llvm-project/pull/81257)
125+
type LLVMConditionId = i16;
126+
127+
/// Must match the layout of `LLVMRustMCDCBranchParameters`.
128+
#[repr(C)]
129+
#[derive(Clone, Copy, Debug, Default)]
130+
pub struct BranchParameters {
131+
condition_id: LLVMConditionId,
132+
condition_ids: [LLVMConditionId; 2],
133+
}
134+
135+
#[repr(C)]
136+
#[derive(Clone, Copy, Debug)]
137+
pub enum ParameterTag {
138+
None = 0,
139+
Decision = 1,
140+
Branch = 2,
141+
}
142+
/// Same layout with `LLVMRustMCDCParameters`
143+
#[repr(C)]
144+
#[derive(Clone, Copy, Debug)]
145+
pub struct Parameters {
146+
tag: ParameterTag,
147+
decision_params: DecisionParameters,
148+
branch_params: BranchParameters,
149+
}
150+
151+
impl Parameters {
152+
pub fn none() -> Self {
153+
Self {
154+
tag: ParameterTag::None,
155+
decision_params: Default::default(),
156+
branch_params: Default::default(),
157+
}
158+
}
159+
pub fn decision(decision_params: DecisionParameters) -> Self {
160+
Self { tag: ParameterTag::Decision, decision_params, branch_params: Default::default() }
161+
}
162+
pub fn branch(branch_params: BranchParameters) -> Self {
163+
Self { tag: ParameterTag::Branch, decision_params: Default::default(), branch_params }
164+
}
165+
}
166+
167+
impl From<ConditionInfo> for BranchParameters {
168+
fn from(value: ConditionInfo) -> Self {
169+
Self {
170+
condition_id: value.condition_id.as_u32() as LLVMConditionId,
171+
condition_ids: [
172+
value.false_next_id.as_u32() as LLVMConditionId,
173+
value.true_next_id.as_u32() as LLVMConditionId,
174+
],
175+
}
176+
}
177+
}
178+
179+
impl From<DecisionInfo> for DecisionParameters {
180+
fn from(value: DecisionInfo) -> Self {
181+
Self { bitmap_idx: value.bitmap_idx, conditions_num: value.conditions_num }
182+
}
183+
}
102184
}
103185

104186
/// This struct provides LLVM's representation of a "CoverageMappingRegion", encoded into the
@@ -122,6 +204,7 @@ pub struct CounterMappingRegion {
122204
/// for the false branch of the region.
123205
false_counter: Counter,
124206

207+
mcdc_params: mcdc::Parameters,
125208
/// An indirect reference to the source filename. In the LLVM Coverage Mapping Format, the
126209
/// file_id is an index into a function-specific `virtual_file_mapping` array of indexes
127210
/// that, in turn, are used to look up the filename for this region.
@@ -173,6 +256,26 @@ impl CounterMappingRegion {
173256
end_line,
174257
end_col,
175258
),
259+
MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => {
260+
Self::mcdc_branch_region(
261+
Counter::from_term(true_term),
262+
Counter::from_term(false_term),
263+
mcdc_params,
264+
local_file_id,
265+
start_line,
266+
start_col,
267+
end_line,
268+
end_col,
269+
)
270+
}
271+
MappingKind::MCDCDecision(decision_info) => Self::decision_region(
272+
decision_info,
273+
local_file_id,
274+
start_line,
275+
start_col,
276+
end_line,
277+
end_col,
278+
),
176279
}
177280
}
178281

@@ -187,6 +290,7 @@ impl CounterMappingRegion {
187290
Self {
188291
counter,
189292
false_counter: Counter::ZERO,
293+
mcdc_params: mcdc::Parameters::none(),
190294
file_id,
191295
expanded_file_id: 0,
192296
start_line,
@@ -209,6 +313,7 @@ impl CounterMappingRegion {
209313
Self {
210314
counter,
211315
false_counter,
316+
mcdc_params: mcdc::Parameters::none(),
212317
file_id,
213318
expanded_file_id: 0,
214319
start_line,
@@ -219,6 +324,54 @@ impl CounterMappingRegion {
219324
}
220325
}
221326

327+
pub(crate) fn mcdc_branch_region(
328+
counter: Counter,
329+
false_counter: Counter,
330+
condition_info: ConditionInfo,
331+
file_id: u32,
332+
start_line: u32,
333+
start_col: u32,
334+
end_line: u32,
335+
end_col: u32,
336+
) -> Self {
337+
Self {
338+
counter,
339+
false_counter,
340+
mcdc_params: mcdc::Parameters::branch(condition_info.into()),
341+
file_id,
342+
expanded_file_id: 0,
343+
start_line,
344+
start_col,
345+
end_line,
346+
end_col,
347+
kind: RegionKind::MCDCBranchRegion,
348+
}
349+
}
350+
351+
pub(crate) fn decision_region(
352+
decision_info: DecisionInfo,
353+
file_id: u32,
354+
start_line: u32,
355+
start_col: u32,
356+
end_line: u32,
357+
end_col: u32,
358+
) -> Self {
359+
let mcdc_params = mcdc::Parameters::decision(decision_info.into());
360+
361+
Self {
362+
counter: Counter::ZERO,
363+
false_counter: Counter::ZERO,
364+
mcdc_params,
365+
file_id,
366+
expanded_file_id: 0,
367+
start_line,
368+
start_col,
369+
end_line,
370+
end_col,
371+
kind: RegionKind::MCDCDecisionRegion,
372+
}
373+
}
374+
222375
// This function might be used in the future; the LLVM API is still evolving, as is coverage
223376
// support.
224377
#[allow(dead_code)]
@@ -233,6 +386,7 @@ impl CounterMappingRegion {
233386
Self {
234387
counter: Counter::ZERO,
235388
false_counter: Counter::ZERO,
389+
mcdc_params: mcdc::Parameters::none(),
236390
file_id,
237391
expanded_file_id,
238392
start_line,
@@ -256,6 +410,7 @@ impl CounterMappingRegion {
256410
Self {
257411
counter: Counter::ZERO,
258412
false_counter: Counter::ZERO,
413+
mcdc_params: mcdc::Parameters::none(),
259414
file_id,
260415
expanded_file_id: 0,
261416
start_line,
@@ -280,6 +435,7 @@ impl CounterMappingRegion {
280435
Self {
281436
counter,
282437
false_counter: Counter::ZERO,
438+
mcdc_params: mcdc::Parameters::none(),
283439
file_id,
284440
expanded_file_id: 0,
285441
start_line,

compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp

+91-3
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
#include "llvm/ProfileData/Coverage/CoverageMappingWriter.h"
55
#include "llvm/ProfileData/InstrProf.h"
66

7-
#include <iostream>
8-
97
using namespace llvm;
108

119
// FFI equivalent of enum `llvm::coverage::Counter::CounterKind`
@@ -43,6 +41,8 @@ enum class LLVMRustCounterMappingRegionKind {
4341
SkippedRegion = 2,
4442
GapRegion = 3,
4543
BranchRegion = 4,
44+
MCDCDecisionRegion = 5,
45+
MCDCBranchRegion = 6
4646
};
4747

4848
static coverage::CounterMappingRegion::RegionKind
@@ -58,15 +58,102 @@ fromRust(LLVMRustCounterMappingRegionKind Kind) {
5858
return coverage::CounterMappingRegion::GapRegion;
5959
case LLVMRustCounterMappingRegionKind::BranchRegion:
6060
return coverage::CounterMappingRegion::BranchRegion;
61+
#if LLVM_VERSION_GE(18, 0)
62+
case LLVMRustCounterMappingRegionKind::MCDCDecisionRegion:
63+
return coverage::CounterMappingRegion::MCDCDecisionRegion;
64+
case LLVMRustCounterMappingRegionKind::MCDCBranchRegion:
65+
return coverage::CounterMappingRegion::MCDCBranchRegion;
66+
#else
67+
case LLVMRustCounterMappingRegionKind::MCDCDecisionRegion:
68+
break;
69+
case LLVMRustCounterMappingRegionKind::MCDCBranchRegion:
70+
break;
71+
#endif
6172
}
6273
report_fatal_error("Bad LLVMRustCounterMappingRegionKind!");
6374
}
6475

76+
enum LLVMRustMCDCParametersTag {
77+
None = 0,
78+
Decision = 1,
79+
Branch = 2,
80+
};
81+
82+
struct LLVMRustMCDCDecisionParameters {
83+
uint32_t BitmapIdx;
84+
uint16_t NumConditions;
85+
};
86+
87+
struct LLVMRustMCDCBranchParameters {
88+
int16_t ConditionID;
89+
int16_t ConditionIDs[2];
90+
};
91+
92+
struct LLVMRustMCDCParameters {
93+
LLVMRustMCDCParametersTag Tag;
94+
LLVMRustMCDCDecisionParameters DecisionParameters;
95+
LLVMRustMCDCBranchParameters BranchParameters;
96+
};
97+
98+
// LLVM representations for `MCDCParameters` evolved from LLVM 18 to 19.
99+
// Look at representations in 18
100+
// https://github.com/rust-lang/llvm-project/blob/66a2881a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L253-L263
101+
// and representations in 19
102+
// https://github.com/llvm/llvm-project/blob/843cc474faefad1d639f4c44c1cf3ad7dbda76c8/llvm/include/llvm/ProfileData/Coverage/MCDCTypes.h
103+
#if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0)
104+
static coverage::CounterMappingRegion::MCDCParameters
105+
fromRust(LLVMRustMCDCParameters Params) {
106+
auto parameter = coverage::CounterMappingRegion::MCDCParameters{};
107+
switch (Params.Tag) {
108+
case LLVMRustMCDCParametersTag::None:
109+
return parameter;
110+
case LLVMRustMCDCParametersTag::Decision:
111+
parameter.BitmapIdx =
112+
static_cast<unsigned>(Params.DecisionParameters.BitmapIdx),
113+
parameter.NumConditions =
114+
static_cast<unsigned>(Params.DecisionParameters.NumConditions);
115+
return parameter;
116+
case LLVMRustMCDCParametersTag::Branch:
117+
parameter.ID = static_cast<coverage::CounterMappingRegion::MCDCConditionID>(
118+
Params.BranchParameters.ConditionID),
119+
parameter.FalseID =
120+
static_cast<coverage::CounterMappingRegion::MCDCConditionID>(
121+
Params.BranchParameters.ConditionIDs[0]),
122+
parameter.TrueID =
123+
static_cast<coverage::CounterMappingRegion::MCDCConditionID>(
124+
Params.BranchParameters.ConditionIDs[1]);
125+
return parameter;
126+
}
127+
report_fatal_error("Bad LLVMRustMCDCParametersTag!");
128+
}
129+
#elif LLVM_VERSION_GE(19, 0)
130+
static coverage::mcdc::Parameters fromRust(LLVMRustMCDCParameters Params) {
131+
switch (Params.Tag) {
132+
case LLVMRustMCDCParametersTag::None:
133+
return std::monostate();
134+
case LLVMRustMCDCParametersTag::Decision:
135+
return coverage::mcdc::DecisionParameters(
136+
Params.DecisionParameters.BitmapIdx,
137+
Params.DecisionParameters.NumConditions);
138+
case LLVMRustMCDCParametersTag::Branch:
139+
return coverage::mcdc::BranchParameters(
140+
static_cast<coverage::mcdc::ConditionID>(
141+
Params.BranchParameters.ConditionID),
142+
{static_cast<coverage::mcdc::ConditionID>(
143+
Params.BranchParameters.ConditionIDs[0]),
144+
static_cast<coverage::mcdc::ConditionID>(
145+
Params.BranchParameters.ConditionIDs[1])});
146+
}
147+
report_fatal_error("Bad LLVMRustMCDCParametersTag!");
148+
}
149+
#endif
150+
65151
// FFI equivalent of struct `llvm::coverage::CounterMappingRegion`
66152
// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L211-L304
67153
struct LLVMRustCounterMappingRegion {
68154
LLVMRustCounter Count;
69155
LLVMRustCounter FalseCount;
156+
LLVMRustMCDCParameters MCDCParameters;
70157
uint32_t FileID;
71158
uint32_t ExpandedFileID;
72159
uint32_t LineStart;
@@ -135,7 +222,8 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
135222
MappingRegions.emplace_back(
136223
fromRust(Region.Count), fromRust(Region.FalseCount),
137224
#if LLVM_VERSION_GE(18, 0) && LLVM_VERSION_LT(19, 0)
138-
coverage::CounterMappingRegion::MCDCParameters{},
225+
// LLVM 19 may move this argument to last.
226+
fromRust(Region.MCDCParameters),
139227
#endif
140228
Region.FileID, Region.ExpandedFileID, // File IDs, then region info.
141229
Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,

0 commit comments

Comments
 (0)