use rustc_middle::mir::coverage::{CounterId, CovTerm, ExpressionId}; /// Must match the layout of `LLVMRustCounterKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) enum CounterKind { Zero = 0, CounterValueReference = 1, Expression = 2, } /// A reference to an instance of an abstract "counter" that will yield a value in a coverage /// report. Note that `id` has different interpretations, depending on the `kind`: /// * For `CounterKind::Zero`, `id` is assumed to be `0` /// * For `CounterKind::CounterValueReference`, `id` matches the `counter_id` of the injected /// instrumentation counter (the `index` argument to the LLVM intrinsic /// `instrprof.increment()`) /// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of /// counter expressions. /// /// Corresponds to struct `llvm::coverage::Counter`. /// /// Must match the layout of `LLVMRustCounter`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) struct Counter { // Important: The layout (order and types of fields) must match its C++ counterpart. pub(crate) kind: CounterKind, id: u32, } impl Counter { /// A `Counter` of kind `Zero`. For this counter kind, the `id` is not used. pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 }; /// Constructs a new `Counter` of kind `CounterValueReference`. pub(crate) fn counter_value_reference(counter_id: CounterId) -> Self { Self { kind: CounterKind::CounterValueReference, id: counter_id.as_u32() } } /// Constructs a new `Counter` of kind `Expression`. pub(crate) fn expression(expression_id: ExpressionId) -> Self { Self { kind: CounterKind::Expression, id: expression_id.as_u32() } } pub(crate) fn from_term(term: CovTerm) -> Self { match term { CovTerm::Zero => Self::ZERO, CovTerm::Counter(id) => Self::counter_value_reference(id), CovTerm::Expression(id) => Self::expression(id), } } } /// Corresponds to enum `llvm::coverage::CounterExpression::ExprKind`. /// /// Must match the layout of `LLVMRustCounterExprKind`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) enum ExprKind { Subtract = 0, Add = 1, } /// Corresponds to struct `llvm::coverage::CounterExpression`. /// /// Must match the layout of `LLVMRustCounterExpression`. #[derive(Copy, Clone, Debug)] #[repr(C)] pub(crate) struct CounterExpression { pub(crate) kind: ExprKind, pub(crate) lhs: Counter, pub(crate) rhs: Counter, } pub(crate) mod mcdc { use rustc_middle::mir::coverage::{ConditionId, ConditionInfo, DecisionInfo}; /// Must match the layout of `LLVMRustMCDCDecisionParameters`. #[repr(C)] #[derive(Clone, Copy, Debug, Default)] pub(crate) struct DecisionParameters { bitmap_idx: u32, num_conditions: u16, } type LLVMConditionId = i16; /// Must match the layout of `LLVMRustMCDCBranchParameters`. #[repr(C)] #[derive(Clone, Copy, Debug, Default)] pub(crate) struct BranchParameters { condition_id: LLVMConditionId, condition_ids: [LLVMConditionId; 2], } impl From for BranchParameters { fn from(value: ConditionInfo) -> Self { let to_llvm_cond_id = |cond_id: Option| { cond_id.and_then(|id| LLVMConditionId::try_from(id.as_usize()).ok()).unwrap_or(-1) }; let ConditionInfo { condition_id, true_next_id, false_next_id } = value; Self { condition_id: to_llvm_cond_id(Some(condition_id)), condition_ids: [to_llvm_cond_id(false_next_id), to_llvm_cond_id(true_next_id)], } } } impl From for DecisionParameters { fn from(info: DecisionInfo) -> Self { let DecisionInfo { bitmap_idx, num_conditions } = info; Self { bitmap_idx, num_conditions } } } } /// A span of source code coordinates to be embedded in coverage metadata. /// /// Must match the layout of `LLVMRustCoverageSpan`. #[derive(Clone, Debug)] #[repr(C)] pub(crate) struct CoverageSpan { /// Local index into the function's local-to-global file ID table. /// The value at that index is itself an index into the coverage filename /// table in the CGU's `__llvm_covmap` section. pub(crate) file_id: u32, /// 1-based starting line of the source code span. pub(crate) start_line: u32, /// 1-based starting column of the source code span. pub(crate) start_col: u32, /// 1-based ending line of the source code span. pub(crate) end_line: u32, /// 1-based ending column of the source code span. High bit must be unset. pub(crate) end_col: u32, } /// Holds tables of the various region types in one struct. /// /// Don't pass this struct across FFI; pass the individual region tables as /// pointer/length pairs instead. /// /// Each field name has a `_regions` suffix for improved readability after /// exhaustive destructing, which ensures that all region types are handled. #[derive(Clone, Debug, Default)] pub(crate) struct Regions { pub(crate) code_regions: Vec, pub(crate) expansion_regions: Vec, pub(crate) branch_regions: Vec, pub(crate) mcdc_branch_regions: Vec, pub(crate) mcdc_decision_regions: Vec, } impl Regions { /// Returns true if none of this structure's tables contain any regions. pub(crate) fn has_no_regions(&self) -> bool { let Self { code_regions, expansion_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions, } = self; code_regions.is_empty() && expansion_regions.is_empty() && branch_regions.is_empty() && mcdc_branch_regions.is_empty() && mcdc_decision_regions.is_empty() } } /// Must match the layout of `LLVMRustCoverageCodeRegion`. #[derive(Clone, Debug)] #[repr(C)] pub(crate) struct CodeRegion { pub(crate) cov_span: CoverageSpan, pub(crate) counter: Counter, } /// Must match the layout of `LLVMRustCoverageExpansionRegion`. #[derive(Clone, Debug)] #[repr(C)] pub(crate) struct ExpansionRegion { pub(crate) cov_span: CoverageSpan, pub(crate) expanded_file_id: u32, } /// Must match the layout of `LLVMRustCoverageBranchRegion`. #[derive(Clone, Debug)] #[repr(C)] pub(crate) struct BranchRegion { pub(crate) cov_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) cov_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) cov_span: CoverageSpan, pub(crate) mcdc_decision_params: mcdc::DecisionParameters, }