From 5d9de08db9025b67aecfcce65cee0d866759ce06 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Sun, 21 Jan 2024 20:02:13 +0900 Subject: [PATCH 01/12] [Coverage] Rework Decision/Expansion/Branch (#77871) --- .../ProfileData/Coverage/CoverageMapping.cpp | 112 +++++++++++++++--- 1 file changed, 97 insertions(+), 15 deletions(-) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 9c95cd5d76d21..d8e1af84e898a 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -14,6 +14,7 @@ #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" @@ -582,6 +583,72 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx, return MaxBitmapID + (SizeInBits / CHAR_BIT); } +struct DecisionRow { + const CounterMappingRegion *DecisionRegion; + LineColPair DecisionStartLoc; + LineColPair DecisionEndLoc; + + SmallVector Branches; + DenseSet IDs; + SmallVector Expansions; + + DecisionRow(const CounterMappingRegion &Decision) + : DecisionRegion(&Decision), DecisionStartLoc(Decision.startLoc()), + DecisionEndLoc(Decision.endLoc()) {} + + bool insert(const CounterMappingRegion &Branch) { + auto ID = Branch.MCDCParams.ID; + if (ID == 1) + Branches.insert(Branches.begin(), &Branch); + else + Branches.push_back(&Branch); + IDs.insert(ID); + return (Branches.size() == DecisionRegion->MCDCParams.NumConditions); + } + + enum class UpdateResult { + NotFound = 0, + Updated, + Committed, + }; + + UpdateResult updateBranch(const CounterMappingRegion &Branch) { + if (IDs.contains(Branch.MCDCParams.ID)) + return UpdateResult::NotFound; + + if (Branch.FileID == DecisionRegion->FileID && + Branch.startLoc() >= DecisionStartLoc && + Branch.endLoc() <= DecisionEndLoc) + return (insert(Branch) ? UpdateResult::Committed : UpdateResult::Updated); + + for (const auto *R : Expansions) { + if (Branch.FileID == R->ExpandedFileID) + return (insert(Branch) ? UpdateResult::Committed + : UpdateResult::Updated); + } + + return UpdateResult::NotFound; + } + + bool updateExpansion(const CounterMappingRegion &Expansion) { + if (Expansion.FileID == DecisionRegion->FileID && + Expansion.startLoc() >= DecisionStartLoc && + Expansion.endLoc() <= DecisionEndLoc) { + Expansions.push_back(&Expansion); + return true; + } + + for (const auto *R : Expansions) { + if (Expansion.FileID == R->ExpandedFileID) { + Expansions.push_back(&Expansion); + return true; + } + } + + return false; + } +}; + Error CoverageMapping::loadFunctionRecord( const CoverageMappingRecord &Record, IndexedInstrProfReader &ProfileReader) { @@ -638,18 +705,11 @@ Error CoverageMapping::loadFunctionRecord( Record.MappingRegions[0].Count.isZero() && Counts[0] > 0) return Error::success(); - unsigned NumConds = 0; - const CounterMappingRegion *MCDCDecision; - std::vector MCDCBranches; - + SmallVector Decisions; FunctionRecord Function(OrigFuncName, Record.Filenames); for (const auto &Region : Record.MappingRegions) { - // If an MCDCDecisionRegion is seen, track the BranchRegions that follow - // it according to Region.NumConditions. if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) { - assert(NumConds == 0); - MCDCDecision = &Region; - NumConds = Region.MCDCParams.NumConditions; + Decisions.emplace_back(Region); continue; } Expected ExecutionCount = Ctx.evaluate(Region.Count); @@ -664,23 +724,39 @@ Error CoverageMapping::loadFunctionRecord( } Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount); + if (Region.Kind == CounterMappingRegion::ExpansionRegion) { + for (auto &Decision : reverse(Decisions)) { + if (Decision.updateExpansion(Region)) + break; + } + continue; + } + + if (Region.Kind != CounterMappingRegion::MCDCBranchRegion) + continue; + // If a MCDCDecisionRegion was seen, store the BranchRegions that // correspond to it in a vector, according to the number of conditions // recorded for the region (tracked by NumConds). - if (NumConds > 0 && Region.Kind == CounterMappingRegion::MCDCBranchRegion) { - MCDCBranches.push_back(&Region); + for (int I = Decisions.size() - 1; I >= 0; --I) { + auto &Decision = Decisions[I]; // As we move through all of the MCDCBranchRegions that follow the // MCDCDecisionRegion, decrement NumConds to make sure we account for // them all before we calculate the bitmap of executed test vectors. - if (--NumConds == 0) { + switch (Decision.updateBranch(Region)) { + case DecisionRow::UpdateResult::NotFound: + continue; + case DecisionRow::UpdateResult::Updated: + goto branch_found; + case DecisionRow::UpdateResult::Committed: // Evaluating the test vector bitmap for the decision region entails // calculating precisely what bits are pertinent to this region alone. // This is calculated based on the recorded offset into the global // profile bitmap; the length is calculated based on the recorded // number of conditions. Expected ExecutedTestVectorBitmap = - Ctx.evaluateBitmap(MCDCDecision); + Ctx.evaluateBitmap(Decision.DecisionRegion); if (auto E = ExecutedTestVectorBitmap.takeError()) { consumeError(std::move(E)); return Error::success(); @@ -690,7 +766,8 @@ Error CoverageMapping::loadFunctionRecord( // DecisionRegion, all of the information is now available to process. // This is where the bulk of the MC/DC progressing takes place. Expected Record = Ctx.evaluateMCDCRegion( - *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches); + *Decision.DecisionRegion, *ExecutedTestVectorBitmap, + Decision.Branches); if (auto E = Record.takeError()) { consumeError(std::move(E)); return Error::success(); @@ -698,9 +775,14 @@ Error CoverageMapping::loadFunctionRecord( // Save the MC/DC Record so that it can be visualized later. Function.pushMCDCRecord(*Record); - MCDCBranches.clear(); + + Decisions.erase(Decisions.begin() + I); + goto branch_found; } } + llvm_unreachable("Branch not found in Decisions"); + + branch_found:; } // Don't create records for (filenames, function) pairs we've already seen. From 1564424ec4018fc2a26a3263cbabba2a4a6cbec7 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Tue, 23 Jan 2024 14:48:36 +0900 Subject: [PATCH 02/12] Confirm that all Decisions have not been resolved. --- llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index d8e1af84e898a..b8bff6df4ab0e 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -785,6 +785,8 @@ Error CoverageMapping::loadFunctionRecord( branch_found:; } + assert(Decisions.empty() && "All Decisions have not been resolved"); + // Don't create records for (filenames, function) pairs we've already seen. auto FilenamesHash = hash_combine_range(Record.Filenames.begin(), Record.Filenames.end()); From f74dec7611aa997bb7973589aef06ef17d0dad11 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Tue, 23 Jan 2024 14:35:09 +0900 Subject: [PATCH 03/12] DecisionRow: Rework to reflect reviews --- .../ProfileData/Coverage/CoverageMapping.cpp | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index b8bff6df4ab0e..5aa25c8b8b11b 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -596,56 +596,49 @@ struct DecisionRow { : DecisionRegion(&Decision), DecisionStartLoc(Decision.startLoc()), DecisionEndLoc(Decision.endLoc()) {} - bool insert(const CounterMappingRegion &Branch) { - auto ID = Branch.MCDCParams.ID; - if (ID == 1) - Branches.insert(Branches.begin(), &Branch); - else - Branches.push_back(&Branch); - IDs.insert(ID); - return (Branches.size() == DecisionRegion->MCDCParams.NumConditions); + bool inDecisionRegion(const CounterMappingRegion &R) { + return (R.FileID == DecisionRegion->FileID && + R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc); + } + + bool inExpansions(const CounterMappingRegion &R) { + return any_of(Expansions, [&](const auto &Expansion) { + return (Expansion->ExpandedFileID == R.FileID); + }); } enum class UpdateResult { NotFound = 0, Updated, - Committed, + Completed, }; UpdateResult updateBranch(const CounterMappingRegion &Branch) { - if (IDs.contains(Branch.MCDCParams.ID)) - return UpdateResult::NotFound; + auto ID = Branch.MCDCParams.ID; - if (Branch.FileID == DecisionRegion->FileID && - Branch.startLoc() >= DecisionStartLoc && - Branch.endLoc() <= DecisionEndLoc) - return (insert(Branch) ? UpdateResult::Committed : UpdateResult::Updated); + if (!IDs.contains(ID) && + (inDecisionRegion(Branch) || inExpansions(Branch))) { + assert(Branches.size() < DecisionRegion->MCDCParams.NumConditions); - for (const auto *R : Expansions) { - if (Branch.FileID == R->ExpandedFileID) - return (insert(Branch) ? UpdateResult::Committed - : UpdateResult::Updated); - } + if (ID == 1) + Branches.insert(Branches.begin(), &Branch); + else + Branches.push_back(&Branch); - return UpdateResult::NotFound; + IDs.insert(ID); + return (Branches.size() == DecisionRegion->MCDCParams.NumConditions + ? UpdateResult::Completed + : UpdateResult::Updated); + } else + return UpdateResult::NotFound; } bool updateExpansion(const CounterMappingRegion &Expansion) { - if (Expansion.FileID == DecisionRegion->FileID && - Expansion.startLoc() >= DecisionStartLoc && - Expansion.endLoc() <= DecisionEndLoc) { + if (inDecisionRegion(Expansion) || inExpansions(Expansion)) { Expansions.push_back(&Expansion); return true; - } - - for (const auto *R : Expansions) { - if (Expansion.FileID == R->ExpandedFileID) { - Expansions.push_back(&Expansion); - return true; - } - } - - return false; + } else + return false; } }; @@ -749,7 +742,7 @@ Error CoverageMapping::loadFunctionRecord( continue; case DecisionRow::UpdateResult::Updated: goto branch_found; - case DecisionRow::UpdateResult::Committed: + case DecisionRow::UpdateResult::Completed: // Evaluating the test vector bitmap for the decision region entails // calculating precisely what bits are pertinent to this region alone. // This is calculated based on the recorded offset into the global From 425185ce38676d6b5ccd0e18c70038b28771291b Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Tue, 23 Jan 2024 21:46:06 +0900 Subject: [PATCH 04/12] Add comments to the upper half. --- .../ProfileData/Coverage/CoverageMapping.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 5aa25c8b8b11b..61984adae3f20 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -583,24 +583,37 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx, return MaxBitmapID + (SizeInBits / CHAR_BIT); } +/// This holds the DecisionRegion and MCDCBranch(es) under it. +/// Also traverses Expansion(s). struct DecisionRow { + /// The subject const CounterMappingRegion *DecisionRegion; + + /// They are reflected from `DecisionRegion` for convenience. LineColPair DecisionStartLoc; LineColPair DecisionEndLoc; + /// This is passed to `MCDCRecordProcessor`, so this should be compatible to + /// `ArrayRef`. SmallVector Branches; + + /// Each `ID` in `Branches` should be unique. DenseSet IDs; + + /// Relevant `Expansion`(s) should be caught to find expanded Branches. SmallVector Expansions; DecisionRow(const CounterMappingRegion &Decision) : DecisionRegion(&Decision), DecisionStartLoc(Decision.startLoc()), DecisionEndLoc(Decision.endLoc()) {} + /// Determine whether `R` is included in `DecisionRegion`. bool inDecisionRegion(const CounterMappingRegion &R) { return (R.FileID == DecisionRegion->FileID && R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc); } + /// Determin whether `R` is pointed by any of Expansions. bool inExpansions(const CounterMappingRegion &R) { return any_of(Expansions, [&](const auto &Expansion) { return (Expansion->ExpandedFileID == R.FileID); @@ -613,19 +626,26 @@ struct DecisionRow { Completed, }; + /// Add `Branch` into the Decision UpdateResult updateBranch(const CounterMappingRegion &Branch) { auto ID = Branch.MCDCParams.ID; + assert(ID > 0 && "MCDCBranch.ID should begin with 1"); if (!IDs.contains(ID) && (inDecisionRegion(Branch) || inExpansions(Branch))) { assert(Branches.size() < DecisionRegion->MCDCParams.NumConditions); + // Put `ID=1` in front of `Branches` for convenience + // even if `Branches` is not topological. if (ID == 1) Branches.insert(Branches.begin(), &Branch); else Branches.push_back(&Branch); + // Mark `ID` as `assigned`. IDs.insert(ID); + + // `Completed` when `Branches` is full return (Branches.size() == DecisionRegion->MCDCParams.NumConditions ? UpdateResult::Completed : UpdateResult::Updated); @@ -633,6 +653,8 @@ struct DecisionRow { return UpdateResult::NotFound; } + /// Record `Expansion` if it is dominated to the Decision. + /// Each `Expansion` may nest. bool updateExpansion(const CounterMappingRegion &Expansion) { if (inDecisionRegion(Expansion) || inExpansions(Expansion)) { Expansions.push_back(&Expansion); @@ -702,6 +724,7 @@ Error CoverageMapping::loadFunctionRecord( FunctionRecord Function(OrigFuncName, Record.Filenames); for (const auto &Region : Record.MappingRegions) { if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) { + // Start recording `Region` as the `Decision` Decisions.emplace_back(Region); continue; } From 2fda236c5fe68fd16b0f35ff0e6e1719d8157219 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Thu, 25 Jan 2024 20:01:20 +0900 Subject: [PATCH 05/12] Fill up comments and revise * Introduce `MCDCDecisionRecorder`. * Sink `DecisionRecord` (was `DecisionRow`) into `MCDCDecisionRecorder` and make it private. * Rename identifiers. * Replace `Expansions` with `ExpandedFileIDs` * Seek `Decisions` in ascent order. --- .../ProfileData/Coverage/CoverageMapping.cpp | 310 ++++++++++-------- 1 file changed, 182 insertions(+), 128 deletions(-) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 61984adae3f20..da28affa788bb 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -583,84 +583,169 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx, return MaxBitmapID + (SizeInBits / CHAR_BIT); } -/// This holds the DecisionRegion and MCDCBranch(es) under it. -/// Also traverses Expansion(s). -struct DecisionRow { - /// The subject - const CounterMappingRegion *DecisionRegion; - - /// They are reflected from `DecisionRegion` for convenience. - LineColPair DecisionStartLoc; - LineColPair DecisionEndLoc; - - /// This is passed to `MCDCRecordProcessor`, so this should be compatible to - /// `ArrayRef`. - SmallVector Branches; - - /// Each `ID` in `Branches` should be unique. - DenseSet IDs; - - /// Relevant `Expansion`(s) should be caught to find expanded Branches. - SmallVector Expansions; - - DecisionRow(const CounterMappingRegion &Decision) - : DecisionRegion(&Decision), DecisionStartLoc(Decision.startLoc()), - DecisionEndLoc(Decision.endLoc()) {} - - /// Determine whether `R` is included in `DecisionRegion`. - bool inDecisionRegion(const CounterMappingRegion &R) { - return (R.FileID == DecisionRegion->FileID && - R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc); - } +/// Collect Decisions, Branchs, and Expansions and associate them. +class MCDCDecisionRecorder { - /// Determin whether `R` is pointed by any of Expansions. - bool inExpansions(const CounterMappingRegion &R) { - return any_of(Expansions, [&](const auto &Expansion) { - return (Expansion->ExpandedFileID == R.FileID); - }); - } +private: + /// This holds the DecisionRegion and MCDCBranches under it. + /// Also traverses Expansion(s). + /// The Decision has the number of MCDCBranches and + struct DecisionRecord { + const CounterMappingRegion *DecisionRegion; + + /// They are reflected from DecisionRegion for convenience. + LineColPair DecisionStartLoc; + LineColPair DecisionEndLoc; + + /// This is passed to `MCDCRecordProcessor`, so this should be compatible + /// to`ArrayRef`. + SmallVector MCDCBranches; + + /// IDs that are stored in MCDCBranches + /// Complete when all IDs (1 to NumConditions) are met. + DenseSet ConditionIDs; + + /// Set of IDs of Expansion(s) that are relevant to DecisionRegion + /// and its children (via expansions). + /// FileID pointed by ExpandedFileID is dedicated to the expansion, so + /// the location in the expansion doesn't matter. + DenseSet ExpandedFileIDs; + + DecisionRecord(const CounterMappingRegion &Decision) + : DecisionRegion(&Decision), DecisionStartLoc(Decision.startLoc()), + DecisionEndLoc(Decision.endLoc()) { + assert(Decision.Kind == CounterMappingRegion::MCDCDecisionRegion); + } - enum class UpdateResult { - NotFound = 0, - Updated, - Completed, - }; + /// Determine whether DecisionRecord dominates `R`. + bool dominates(const CounterMappingRegion &R) { + // Determine whether `R` is included in `DecisionRegion`. + if (R.FileID == DecisionRegion->FileID && + R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc) + return true; + + // Determine whether `R` is pointed by any of Expansions. + return ExpandedFileIDs.contains(R.FileID); + } + + enum Result { + NotProcessed = 0, /// Irrelevant to this Decision + Processed, /// Added to this Decision + Completed, /// Added and filled this Decision + }; - /// Add `Branch` into the Decision - UpdateResult updateBranch(const CounterMappingRegion &Branch) { - auto ID = Branch.MCDCParams.ID; - assert(ID > 0 && "MCDCBranch.ID should begin with 1"); + /// Add Branch into the Decision + /// \param Branch expects MCDCBranchRegion + /// \returns NotProcessed/Processed/Completed + Result addBranch(const CounterMappingRegion &Branch) { + assert(Branch.Kind == CounterMappingRegion::MCDCBranchRegion); - if (!IDs.contains(ID) && - (inDecisionRegion(Branch) || inExpansions(Branch))) { - assert(Branches.size() < DecisionRegion->MCDCParams.NumConditions); + auto ConditionID = Branch.MCDCParams.ID; + assert(ConditionID > 0 && "ConditionID should begin with 1"); - // Put `ID=1` in front of `Branches` for convenience - // even if `Branches` is not topological. - if (ID == 1) - Branches.insert(Branches.begin(), &Branch); + if (ConditionIDs.contains(ConditionID) || + ConditionID > DecisionRegion->MCDCParams.NumConditions) + return NotProcessed; + + if (!this->dominates(Branch)) + return NotProcessed; + + assert(MCDCBranches.size() < DecisionRegion->MCDCParams.NumConditions); + + // Put `ID=1` in front of `MCDCBranches` for convenience + // even if `MCDCBranches` is not topological. + if (ConditionID == 1) + MCDCBranches.insert(MCDCBranches.begin(), &Branch); else - Branches.push_back(&Branch); + MCDCBranches.push_back(&Branch); // Mark `ID` as `assigned`. - IDs.insert(ID); - - // `Completed` when `Branches` is full - return (Branches.size() == DecisionRegion->MCDCParams.NumConditions - ? UpdateResult::Completed - : UpdateResult::Updated); - } else - return UpdateResult::NotFound; - } + ConditionIDs.insert(ConditionID); + + // `Completed` when `MCDCBranches` is full + return (MCDCBranches.size() == DecisionRegion->MCDCParams.NumConditions + ? Completed + : Processed); + } + + /// Record Expansion if it is relevant to this Decision. + /// Each `Expansion` may nest. + /// \returns true if recorded. + bool recordExpansion(const CounterMappingRegion &Expansion) { + if (!this->dominates(Expansion)) + return false; - /// Record `Expansion` if it is dominated to the Decision. - /// Each `Expansion` may nest. - bool updateExpansion(const CounterMappingRegion &Expansion) { - if (inDecisionRegion(Expansion) || inExpansions(Expansion)) { - Expansions.push_back(&Expansion); + ExpandedFileIDs.insert(Expansion.ExpandedFileID); return true; - } else + } + }; + +private: + /// Decisions in progress + /// DecisionRecord is added for each MCDCDecisionRegion. + /// DecisionRecord is removed when Decision is completed. + SmallVector Decisions; + +public: + ~MCDCDecisionRecorder() { + assert(Decisions.empty() && "All Decisions have not been resolved"); + } + + /// Register Region and start recording if it is MCDCDecisionRegion. + /// \param Region to be inspected + /// \returns true if recording started. + bool registerDecision(const CounterMappingRegion &Region) { + if (Region.Kind != CounterMappingRegion::MCDCDecisionRegion) return false; + + // Start recording Region to create DecisionRecord + Decisions.emplace_back(Region); + return true; + } + + using DecisionAndBranches = + std::pair /// Branches + >; + + /// If Region is ExpansionRegion, record it. + /// If Region is MCDCBranchRegion, add it to DecisionRecord. + /// \param Region to be inspected + /// \returns DecisionsAndBranches if DecisionRecord completed. + /// Or returns nullopt. + std::optional + processRegion(const CounterMappingRegion &Region) { + + // Record ExpansionRegion. + if (Region.Kind == CounterMappingRegion::ExpansionRegion) { + for (auto &Decision : reverse(Decisions)) { + if (Decision.recordExpansion(Region)) + break; + } + return std::nullopt; // It doesn't complete. + } + + // Do nothing unless MCDCBranchRegion. + if (Region.Kind != CounterMappingRegion::MCDCBranchRegion) + return std::nullopt; + + // Seek each Decision and apply Region to it. + for (auto DecisionIter = Decisions.begin(), DecisionEnd = Decisions.end(); + DecisionIter != DecisionEnd; ++DecisionIter) + switch (DecisionIter->addBranch(Region)) { + case DecisionRecord::NotProcessed: + continue; + case DecisionRecord::Processed: + return std::nullopt; + case DecisionRecord::Completed: + DecisionAndBranches Result = + std::make_pair(DecisionIter->DecisionRegion, + std::move(DecisionIter->MCDCBranches)); + Decisions.erase(DecisionIter); // No longer used. + return Result; + } + + llvm_unreachable("Branch not found in Decisions"); } }; @@ -720,14 +805,13 @@ Error CoverageMapping::loadFunctionRecord( Record.MappingRegions[0].Count.isZero() && Counts[0] > 0) return Error::success(); - SmallVector Decisions; + MCDCDecisionRecorder MCDCDecisions; FunctionRecord Function(OrigFuncName, Record.Filenames); for (const auto &Region : Record.MappingRegions) { - if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) { - // Start recording `Region` as the `Decision` - Decisions.emplace_back(Region); + // MCDCDecisionRegion should be handled first since it overlaps with + // others inside. + if (MCDCDecisions.registerDecision(Region)) continue; - } Expected ExecutionCount = Ctx.evaluate(Region.Count); if (auto E = ExecutionCount.takeError()) { consumeError(std::move(E)); @@ -740,69 +824,39 @@ Error CoverageMapping::loadFunctionRecord( } Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount); - if (Region.Kind == CounterMappingRegion::ExpansionRegion) { - for (auto &Decision : reverse(Decisions)) { - if (Decision.updateExpansion(Region)) - break; - } + auto Result = MCDCDecisions.processRegion(Region); + if (!Result) // Any Decision doesn't complete. continue; - } - if (Region.Kind != CounterMappingRegion::MCDCBranchRegion) - continue; - - // If a MCDCDecisionRegion was seen, store the BranchRegions that - // correspond to it in a vector, according to the number of conditions - // recorded for the region (tracked by NumConds). - for (int I = Decisions.size() - 1; I >= 0; --I) { - auto &Decision = Decisions[I]; - - // As we move through all of the MCDCBranchRegions that follow the - // MCDCDecisionRegion, decrement NumConds to make sure we account for - // them all before we calculate the bitmap of executed test vectors. - switch (Decision.updateBranch(Region)) { - case DecisionRow::UpdateResult::NotFound: - continue; - case DecisionRow::UpdateResult::Updated: - goto branch_found; - case DecisionRow::UpdateResult::Completed: - // Evaluating the test vector bitmap for the decision region entails - // calculating precisely what bits are pertinent to this region alone. - // This is calculated based on the recorded offset into the global - // profile bitmap; the length is calculated based on the recorded - // number of conditions. - Expected ExecutedTestVectorBitmap = - Ctx.evaluateBitmap(Decision.DecisionRegion); - if (auto E = ExecutedTestVectorBitmap.takeError()) { - consumeError(std::move(E)); - return Error::success(); - } - - // Since the bitmap identifies the executed test vectors for an MC/DC - // DecisionRegion, all of the information is now available to process. - // This is where the bulk of the MC/DC progressing takes place. - Expected Record = Ctx.evaluateMCDCRegion( - *Decision.DecisionRegion, *ExecutedTestVectorBitmap, - Decision.Branches); - if (auto E = Record.takeError()) { - consumeError(std::move(E)); - return Error::success(); - } - - // Save the MC/DC Record so that it can be visualized later. - Function.pushMCDCRecord(*Record); + auto MCDCDecision = Result->first; + auto &MCDCBranches = Result->second; + + // Evaluating the test vector bitmap for the decision region entails + // calculating precisely what bits are pertinent to this region alone. + // This is calculated based on the recorded offset into the global + // profile bitmap; the length is calculated based on the recorded + // number of conditions. + Expected ExecutedTestVectorBitmap = + Ctx.evaluateBitmap(MCDCDecision); + if (auto E = ExecutedTestVectorBitmap.takeError()) { + consumeError(std::move(E)); + return Error::success(); + } - Decisions.erase(Decisions.begin() + I); - goto branch_found; - } + // Since the bitmap identifies the executed test vectors for an MC/DC + // DecisionRegion, all of the information is now available to process. + // This is where the bulk of the MC/DC progressing takes place. + Expected Record = Ctx.evaluateMCDCRegion( + *MCDCDecision, *ExecutedTestVectorBitmap, MCDCBranches); + if (auto E = Record.takeError()) { + consumeError(std::move(E)); + return Error::success(); } - llvm_unreachable("Branch not found in Decisions"); - branch_found:; + // Save the MC/DC Record so that it can be visualized later. + Function.pushMCDCRecord(*Record); } - assert(Decisions.empty() && "All Decisions have not been resolved"); - // Don't create records for (filenames, function) pairs we've already seen. auto FilenamesHash = hash_combine_range(Record.Filenames.begin(), Record.Filenames.end()); From 133bd019a7a945d64207fa4ebe00d048743e2083 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Fri, 26 Jan 2024 09:02:03 +0900 Subject: [PATCH 06/12] Update comments --- llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index da28affa788bb..ef4d8d5349cb0 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -589,7 +589,8 @@ class MCDCDecisionRecorder { private: /// This holds the DecisionRegion and MCDCBranches under it. /// Also traverses Expansion(s). - /// The Decision has the number of MCDCBranches and + /// The Decision has the number of MCDCBranches and will complete + /// when it is filled with unique ConditionID of MCDCBranches. struct DecisionRecord { const CounterMappingRegion *DecisionRegion; From 2b6edff7f3e68a64e02ee5972b7f9533aa150443 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Fri, 26 Jan 2024 09:02:27 +0900 Subject: [PATCH 07/12] Make the class local --- llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index ef4d8d5349cb0..60ec2fad9f08e 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -583,6 +583,8 @@ static unsigned getMaxBitmapSize(const CounterMappingContext &Ctx, return MaxBitmapID + (SizeInBits / CHAR_BIT); } +namespace { + /// Collect Decisions, Branchs, and Expansions and associate them. class MCDCDecisionRecorder { @@ -750,6 +752,8 @@ class MCDCDecisionRecorder { } }; +} // namespace + Error CoverageMapping::loadFunctionRecord( const CoverageMappingRecord &Record, IndexedInstrProfReader &ProfileReader) { From 9e0f60f3b0a9750e280723ab9de94215093dbb17 Mon Sep 17 00:00:00 2001 From: Alan Phipps Date: Thu, 18 Jan 2024 10:29:50 -0600 Subject: [PATCH 08/12] Import Alan's testcase from #78819 --- llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c | 20 ++++ llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o | Bin 0 -> 81624 bytes .../tools/llvm-cov/Inputs/mcdc-macro.proftext | 62 ++++++++++++ llvm/test/tools/llvm-cov/mcdc-macro.test | 92 ++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c create mode 100755 llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o create mode 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext create mode 100644 llvm/test/tools/llvm-cov/mcdc-macro.test diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c new file mode 100644 index 0000000000000..bd2b979bd257f --- /dev/null +++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.c @@ -0,0 +1,20 @@ +#define C c +#define D 1 +#define E (C != a) && (C > a) +#define F E + +void __attribute__((noinline)) func1(void) { return; } + +void __attribute__((noinline)) func(int a, int b, int c) { + if (a && D && E || b) + func1(); + if (b && D) + func1(); + if (a && (b && C) || (D && F)) + func1(); +} + +int main() { + func(2, 3, 3); + return 0; +} diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o new file mode 100755 index 0000000000000000000000000000000000000000..f10c849b844bd2b7aa325531d8f2f978b62097c2 GIT binary patch literal 81624 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 literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext new file mode 100644 index 0000000000000..952f161f56c58 --- /dev/null +++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext @@ -0,0 +1,62 @@ +main +# Func Hash: +24 +# Num Counters: +1 +# Counter Values: +1 + +foo +# Func Hash: +395201011017399473 +# Num Counters: +22 +# Counter Values: +1 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +1 +1 +1 +0 +0 +0 +0 +# Num Bitmap Bytes: +$13 +# Bitmap Byte Values: +0x0 +0x0 +0x0 +0x20 +0x8 +0x0 +0x20 +0x0 +0x0 +0x0 +0x0 +0x0 +0x0 + + +bar +# Func Hash: +24 +# Num Counters: +1 +# Counter Values: +3 + diff --git a/llvm/test/tools/llvm-cov/mcdc-macro.test b/llvm/test/tools/llvm-cov/mcdc-macro.test new file mode 100644 index 0000000000000..d59055ad2c29b --- /dev/null +++ b/llvm/test/tools/llvm-cov/mcdc-macro.test @@ -0,0 +1,92 @@ +// Test visualization of MC/DC constructs for branches in macro expansions. + +// RUN: llvm-profdata merge %S/Inputs/mcdc-macro.proftext -o %t.profdata +// RUN: llvm-cov show --show-expansions --show-branches=count --show-mcdc %S/Inputs/mcdc-macro.o -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/mcdc-macro.c | FileCheck %s + +// CHECK: | | | Branch (2:11): [Folded - Ignored] +// CHECK: | | | Branch (3:11): [True: 0, False: 0] +// CHECK: | | | Branch (3:23): [True: 0, False: 0] +// CHECK: | Branch (9:7): [True: 0, False: 0] +// CHECK-NEXT: | Branch (9:22): [True: 0, False: 0] +// CHECK-NEXT: ------------------ +// CHECK-NEXT: |---> MC/DC Decision Region (9:7) to (9:23) +// CHECK-NEXT: | +// CHECK-NEXT: | Number of Conditions: 5 +// CHECK-NEXT: | Condition C1 --> (9:7) +// CHECK-NEXT: | Condition C2 --> (2:11) +// CHECK-NEXT: | Condition C3 --> (3:11) +// CHECK-NEXT: | Condition C4 --> (3:23) +// CHECK-NEXT: | Condition C5 --> (9:22) +// CHECK-NEXT: | +// CHECK-NEXT: | Executed MC/DC Test Vectors: +// CHECK-NEXT: | +// CHECK-NEXT: | None. +// CHECK-NEXT: | +// CHECK-NEXT: | C1-Pair: not covered +// CHECK-NEXT: | C2-Pair: constant folded +// CHECK-NEXT: | C3-Pair: not covered +// CHECK-NEXT: | C4-Pair: not covered +// CHECK-NEXT: | C5-Pair: not covered +// CHECK-NEXT: | MC/DC Coverage for Decision: 0.00% +// CHECK-NEXT: | +// CHECK-NEXT: ------------------ + +// CHECK: | | | Branch (2:11): [Folded - Ignored] +// CHECK: | Branch (11:7): [True: 0, False: 0] +// CHECK-NEXT: ------------------ +// CHECK-NEXT: |---> MC/DC Decision Region (11:7) to (11:13) +// CHECK-NEXT: | +// CHECK-NEXT: | Number of Conditions: 2 +// CHECK-NEXT: | Condition C1 --> (11:7) +// CHECK-NEXT: | Condition C2 --> (2:11) +// CHECK-NEXT: | +// CHECK-NEXT: | Executed MC/DC Test Vectors: +// CHECK-NEXT: | +// CHECK-NEXT: | None. +// CHECK-NEXT: | +// CHECK-NEXT: | C1-Pair: not covered +// CHECK-NEXT: | C2-Pair: constant folded +// CHECK-NEXT: | MC/DC Coverage for Decision: 0.00% +// CHECK-NEXT: | +// CHECK-NEXT: ------------------ + +// CHECK: | | | Branch (1:11): [True: 0, False: 0] +// CHECK: | | | Branch (2:11): [Folded - Ignored] +// CHECK: | | | | | Branch (3:11): [True: 0, False: 0] +// CHECK: | | | | | Branch (3:23): [True: 0, False: 0] +// CHECK: | Branch (13:7): [True: 0, False: 0] +// CHECK-NEXT: | Branch (13:13): [True: 0, False: 0] +// CHECK-NEXT: ------------------ +// CHECK-NEXT: |---> MC/DC Decision Region (13:7) to (13:32) +// CHECK-NEXT: | +// CHECK-NEXT: | Number of Conditions: 6 +// CHECK-NEXT: | Condition C1 --> (13:7) +// CHECK-NEXT: | Condition C2 --> (13:13) +// CHECK-NEXT: | Condition C3 --> (1:11) +// CHECK-NEXT: | Condition C4 --> (2:11) +// CHECK-NEXT: | Condition C5 --> (3:11) +// CHECK-NEXT: | Condition C6 --> (3:23) +// CHECK-NEXT: | +// CHECK-NEXT: | Executed MC/DC Test Vectors: +// CHECK-NEXT: | +// CHECK-NEXT: | None. +// CHECK-NEXT: | +// CHECK-NEXT: | C1-Pair: not covered +// CHECK-NEXT: | C2-Pair: not covered +// CHECK-NEXT: | C3-Pair: not covered +// CHECK-NEXT: | C4-Pair: constant folded +// CHECK-NEXT: | C5-Pair: not covered +// CHECK-NEXT: | C6-Pair: not covered +// CHECK-NEXT: | MC/DC Coverage for Decision: 0.00% +// CHECK-NEXT: | +// CHECK-NEXT: ------------------ + +Instructions for regenerating the test: + +# cd %S/Inputs +cp mcdc-macro.c /tmp + +clang -fcoverage-mcdc -fprofile-instr-generate -fcoverage-compilation-dir=. \ + -fcoverage-mapping /tmp/mcdc-macro.c -o /tmp/mcdc-macro.o + +mv /tmp/mcdc-macro.o %S/Inputs From 83a0ff8e7f735d6d09fb0287cfe173bbab480f09 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Sun, 28 Jan 2024 11:18:11 +0900 Subject: [PATCH 09/12] Update test for my impl --- llvm/test/tools/llvm-cov/mcdc-macro.test | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/test/tools/llvm-cov/mcdc-macro.test b/llvm/test/tools/llvm-cov/mcdc-macro.test index d59055ad2c29b..3d45e3a38d409 100644 --- a/llvm/test/tools/llvm-cov/mcdc-macro.test +++ b/llvm/test/tools/llvm-cov/mcdc-macro.test @@ -13,18 +13,18 @@ // CHECK-NEXT: | // CHECK-NEXT: | Number of Conditions: 5 // CHECK-NEXT: | Condition C1 --> (9:7) -// CHECK-NEXT: | Condition C2 --> (2:11) -// CHECK-NEXT: | Condition C3 --> (3:11) -// CHECK-NEXT: | Condition C4 --> (3:23) -// CHECK-NEXT: | Condition C5 --> (9:22) +// CHECK-NEXT: | Condition C2 --> (9:22) +// CHECK-NEXT: | Condition C3 --> (2:11) +// CHECK-NEXT: | Condition C4 --> (3:11) +// CHECK-NEXT: | Condition C5 --> (3:23) // CHECK-NEXT: | // CHECK-NEXT: | Executed MC/DC Test Vectors: // CHECK-NEXT: | // CHECK-NEXT: | None. // CHECK-NEXT: | // CHECK-NEXT: | C1-Pair: not covered -// CHECK-NEXT: | C2-Pair: constant folded -// CHECK-NEXT: | C3-Pair: not covered +// CHECK-NEXT: | C2-Pair: not covered +// CHECK-NEXT: | C3-Pair: constant folded // CHECK-NEXT: | C4-Pair: not covered // CHECK-NEXT: | C5-Pair: not covered // CHECK-NEXT: | MC/DC Coverage for Decision: 0.00% From 200a32f784bbbde9c0b8991c878adc9a3b89b2b4 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Sun, 28 Jan 2024 16:55:20 +0900 Subject: [PATCH 10/12] Reflect @MaskRay's suggestions --- .../ProfileData/Coverage/CoverageMapping.cpp | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index 60ec2fad9f08e..a211097f335e4 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -587,7 +587,6 @@ namespace { /// Collect Decisions, Branchs, and Expansions and associate them. class MCDCDecisionRecorder { - private: /// This holds the DecisionRegion and MCDCBranches under it. /// Also traverses Expansion(s). @@ -694,16 +693,15 @@ class MCDCDecisionRecorder { assert(Decisions.empty() && "All Decisions have not been resolved"); } - /// Register Region and start recording if it is MCDCDecisionRegion. - /// \param Region to be inspected - /// \returns true if recording started. - bool registerDecision(const CounterMappingRegion &Region) { - if (Region.Kind != CounterMappingRegion::MCDCDecisionRegion) - return false; + /// Register Region and start recording. + void registerDecision(const CounterMappingRegion &Decision) { + Decisions.emplace_back(Decision); + } - // Start recording Region to create DecisionRecord - Decisions.emplace_back(Region); - return true; + void recordExpansion(const CounterMappingRegion &Expansion) { + any_of(Decisions, [&Expansion](auto &Decision) { + return Decision.recordExpansion(Expansion); + }); } using DecisionAndBranches = @@ -711,31 +709,16 @@ class MCDCDecisionRecorder { SmallVector /// Branches >; - /// If Region is ExpansionRegion, record it. - /// If Region is MCDCBranchRegion, add it to DecisionRecord. - /// \param Region to be inspected + /// Add MCDCBranchRegion to DecisionRecord. + /// \param Branch to be processed /// \returns DecisionsAndBranches if DecisionRecord completed. /// Or returns nullopt. std::optional - processRegion(const CounterMappingRegion &Region) { - - // Record ExpansionRegion. - if (Region.Kind == CounterMappingRegion::ExpansionRegion) { - for (auto &Decision : reverse(Decisions)) { - if (Decision.recordExpansion(Region)) - break; - } - return std::nullopt; // It doesn't complete. - } - - // Do nothing unless MCDCBranchRegion. - if (Region.Kind != CounterMappingRegion::MCDCBranchRegion) - return std::nullopt; - + processBranch(const CounterMappingRegion &Branch) { // Seek each Decision and apply Region to it. for (auto DecisionIter = Decisions.begin(), DecisionEnd = Decisions.end(); DecisionIter != DecisionEnd; ++DecisionIter) - switch (DecisionIter->addBranch(Region)) { + switch (DecisionIter->addBranch(Branch)) { case DecisionRecord::NotProcessed: continue; case DecisionRecord::Processed: @@ -815,8 +798,10 @@ Error CoverageMapping::loadFunctionRecord( for (const auto &Region : Record.MappingRegions) { // MCDCDecisionRegion should be handled first since it overlaps with // others inside. - if (MCDCDecisions.registerDecision(Region)) + if (Region.Kind == CounterMappingRegion::MCDCDecisionRegion) { + MCDCDecisions.registerDecision(Region); continue; + } Expected ExecutionCount = Ctx.evaluate(Region.Count); if (auto E = ExecutionCount.takeError()) { consumeError(std::move(E)); @@ -829,7 +814,17 @@ Error CoverageMapping::loadFunctionRecord( } Function.pushRegion(Region, *ExecutionCount, *AltExecutionCount); - auto Result = MCDCDecisions.processRegion(Region); + // Record ExpansionRegion. + if (Region.Kind == CounterMappingRegion::ExpansionRegion) { + MCDCDecisions.recordExpansion(Region); + continue; + } + + // Do nothing unless MCDCBranchRegion. + if (Region.Kind != CounterMappingRegion::MCDCBranchRegion) + continue; + + auto Result = MCDCDecisions.processBranch(Region); if (!Result) // Any Decision doesn't complete. continue; From 0e4b05b4cc97ce77d456002c6d84401b9ae03b10 Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Sun, 28 Jan 2024 16:56:37 +0900 Subject: [PATCH 11/12] Mark `dominates()` const --- llvm/lib/ProfileData/Coverage/CoverageMapping.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp index a211097f335e4..d596d0d9d206a 100644 --- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -620,7 +620,7 @@ class MCDCDecisionRecorder { } /// Determine whether DecisionRecord dominates `R`. - bool dominates(const CounterMappingRegion &R) { + bool dominates(const CounterMappingRegion &R) const { // Determine whether `R` is included in `DecisionRegion`. if (R.FileID == DecisionRegion->FileID && R.startLoc() >= DecisionStartLoc && R.endLoc() <= DecisionEndLoc) From c889c04386895ed0901dc6b4b806668272b9d76d Mon Sep 17 00:00:00 2001 From: NAKAMURA Takumi Date: Fri, 2 Feb 2024 17:28:02 +0900 Subject: [PATCH 12/12] Update mcdc-macro.test --- llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o | Bin 81624 -> 6424 bytes .../tools/llvm-cov/Inputs/mcdc-macro.proftext | 20 +++++----- llvm/test/tools/llvm-cov/mcdc-macro.test | 37 +++++++++++------- 3 files changed, 32 insertions(+), 25 deletions(-) mode change 100755 => 100644 llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.o old mode 100755 new mode 100644 index f10c849b844bd2b7aa325531d8f2f978b62097c2..667ccd132d2fb848ae86b9bbbc72f7b3a917feab GIT binary patch literal 6424 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 G=l?hL>vwAa literal 81624 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 diff --git a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext index 952f161f56c58..35ecc42b5802a 100644 --- a/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext +++ b/llvm/test/tools/llvm-cov/Inputs/mcdc-macro.proftext @@ -1,12 +1,4 @@ -main -# Func Hash: -24 -# Num Counters: -1 -# Counter Values: -1 - -foo +func # Func Hash: 395201011017399473 # Num Counters: @@ -52,7 +44,7 @@ $13 0x0 -bar +func1 # Func Hash: 24 # Num Counters: @@ -60,3 +52,11 @@ bar # Counter Values: 3 +main +# Func Hash: +24 +# Num Counters: +1 +# Counter Values: +1 + diff --git a/llvm/test/tools/llvm-cov/mcdc-macro.test b/llvm/test/tools/llvm-cov/mcdc-macro.test index 3d45e3a38d409..339284bba2c9b 100644 --- a/llvm/test/tools/llvm-cov/mcdc-macro.test +++ b/llvm/test/tools/llvm-cov/mcdc-macro.test @@ -1,12 +1,12 @@ // Test visualization of MC/DC constructs for branches in macro expansions. // RUN: llvm-profdata merge %S/Inputs/mcdc-macro.proftext -o %t.profdata -// RUN: llvm-cov show --show-expansions --show-branches=count --show-mcdc %S/Inputs/mcdc-macro.o -instr-profile %t.profdata -path-equivalence=/tmp,%S/Inputs %S/Inputs/mcdc-macro.c | FileCheck %s +// RUN: llvm-cov show --show-expansions --show-branches=count --show-mcdc %S/Inputs/mcdc-macro.o -instr-profile %t.profdata --compilation-dir=%S/Inputs | FileCheck %s // CHECK: | | | Branch (2:11): [Folded - Ignored] -// CHECK: | | | Branch (3:11): [True: 0, False: 0] -// CHECK: | | | Branch (3:23): [True: 0, False: 0] -// CHECK: | Branch (9:7): [True: 0, False: 0] +// CHECK: | | | Branch (3:11): [True: 1, False: 0] +// CHECK: | | | Branch (3:23): [True: 1, False: 0] +// CHECK: | Branch (9:7): [True: 1, False: 0] // CHECK-NEXT: | Branch (9:22): [True: 0, False: 0] // CHECK-NEXT: ------------------ // CHECK-NEXT: |---> MC/DC Decision Region (9:7) to (9:23) @@ -20,7 +20,8 @@ // CHECK-NEXT: | // CHECK-NEXT: | Executed MC/DC Test Vectors: // CHECK-NEXT: | -// CHECK-NEXT: | None. +// CHECK-NEXT: | C1, C2, C3, C4, C5 Result +// CHECK-NEXT: | 1 { T, -, C, T, T = T } // CHECK-NEXT: | // CHECK-NEXT: | C1-Pair: not covered // CHECK-NEXT: | C2-Pair: not covered @@ -32,7 +33,7 @@ // CHECK-NEXT: ------------------ // CHECK: | | | Branch (2:11): [Folded - Ignored] -// CHECK: | Branch (11:7): [True: 0, False: 0] +// CHECK: | Branch (11:7): [True: 1, False: 0] // CHECK-NEXT: ------------------ // CHECK-NEXT: |---> MC/DC Decision Region (11:7) to (11:13) // CHECK-NEXT: | @@ -42,7 +43,8 @@ // CHECK-NEXT: | // CHECK-NEXT: | Executed MC/DC Test Vectors: // CHECK-NEXT: | -// CHECK-NEXT: | None. +// CHECK-NEXT: | C1, C2 Result +// CHECK-NEXT: | 1 { T, C = T } // CHECK-NEXT: | // CHECK-NEXT: | C1-Pair: not covered // CHECK-NEXT: | C2-Pair: constant folded @@ -50,12 +52,12 @@ // CHECK-NEXT: | // CHECK-NEXT: ------------------ -// CHECK: | | | Branch (1:11): [True: 0, False: 0] +// CHECK: | | | Branch (1:11): [True: 1, False: 0] // CHECK: | | | Branch (2:11): [Folded - Ignored] // CHECK: | | | | | Branch (3:11): [True: 0, False: 0] // CHECK: | | | | | Branch (3:23): [True: 0, False: 0] -// CHECK: | Branch (13:7): [True: 0, False: 0] -// CHECK-NEXT: | Branch (13:13): [True: 0, False: 0] +// CHECK: | Branch (13:7): [True: 1, False: 0] +// CHECK-NEXT: | Branch (13:13): [True: 1, False: 0] // CHECK-NEXT: ------------------ // CHECK-NEXT: |---> MC/DC Decision Region (13:7) to (13:32) // CHECK-NEXT: | @@ -69,7 +71,8 @@ // CHECK-NEXT: | // CHECK-NEXT: | Executed MC/DC Test Vectors: // CHECK-NEXT: | -// CHECK-NEXT: | None. +// CHECK-NEXT: | C1, C2, C3, C4, C5, C6 Result +// CHECK-NEXT: | 1 { T, T, T, C, -, - = T } // CHECK-NEXT: | // CHECK-NEXT: | C1-Pair: not covered // CHECK-NEXT: | C2-Pair: not covered @@ -83,10 +86,14 @@ Instructions for regenerating the test: -# cd %S/Inputs -cp mcdc-macro.c /tmp +cd %S/Inputs # Or copy mcdc-macro.c into the working directory clang -fcoverage-mcdc -fprofile-instr-generate -fcoverage-compilation-dir=. \ - -fcoverage-mapping /tmp/mcdc-macro.c -o /tmp/mcdc-macro.o + -O3 -mllvm -enable-name-compression=false \ + -fcoverage-mapping mcdc-macro.c -c -mv /tmp/mcdc-macro.o %S/Inputs +# Instructions for generating proftext +clang -fprofile-instr-generate mcdc-macro.o +./a.out +llvm-profdata merge --sparse -o default.profdata default.profraw +llvm-profdata merge --text -o mcdc-macro.proftext default.profdata