@@ -223,9 +223,130 @@ Expected<int64_t> CounterMappingContext::evaluate(const Counter &C) const {
223223 return LastPoppedValue;
224224}
225225
226+ mcdc::TVIdxBuilder::TVIdxBuilder (const SmallVectorImpl<ConditionIDs> &NextIDs,
227+ int Offset)
228+ : Indices(NextIDs.size()) {
229+ // Construct Nodes and set up each InCount
230+ auto N = NextIDs.size ();
231+ SmallVector<MCDCNode> Nodes (N);
232+ for (unsigned ID = 0 ; ID < N; ++ID) {
233+ for (unsigned C = 0 ; C < 2 ; ++C) {
234+ #ifndef NDEBUG
235+ Indices[ID][C] = INT_MIN;
236+ #endif
237+ auto NextID = NextIDs[ID][C];
238+ Nodes[ID].NextIDs [C] = NextID;
239+ if (NextID >= 0 )
240+ ++Nodes[NextID].InCount ;
241+ }
242+ }
243+
244+ // Sort key ordered by <-Width, Ord>
245+ SmallVector<std::tuple<int , // / -Width
246+ unsigned , // / Ord
247+ int , // / ID
248+ unsigned // / Cond (0 or 1)
249+ >>
250+ Decisions;
251+
252+ // Traverse Nodes to assign Idx
253+ SmallVector<int > Q;
254+ assert (Nodes[0 ].InCount == 0 );
255+ Nodes[0 ].Width = 1 ;
256+ Q.push_back (0 );
257+
258+ unsigned Ord = 0 ;
259+ while (!Q.empty ()) {
260+ auto IID = Q.begin ();
261+ int ID = *IID;
262+ Q.erase (IID);
263+ auto &Node = Nodes[ID];
264+ assert (Node.Width > 0 );
265+
266+ for (unsigned I = 0 ; I < 2 ; ++I) {
267+ auto NextID = Node.NextIDs [I];
268+ assert (NextID != 0 && " NextID should not point to the top" );
269+ if (NextID < 0 ) {
270+ // Decision
271+ Decisions.emplace_back (-Node.Width , Ord++, ID, I);
272+ assert (Ord == Decisions.size ());
273+ continue ;
274+ }
275+
276+ // Inter Node
277+ auto &NextNode = Nodes[NextID];
278+ assert (NextNode.InCount > 0 );
279+
280+ // Assign Idx
281+ assert (Indices[ID][I] == INT_MIN);
282+ Indices[ID][I] = NextNode.Width ;
283+ auto NextWidth = int64_t (NextNode.Width ) + Node.Width ;
284+ if (NextWidth > HardMaxTVs) {
285+ NumTestVectors = HardMaxTVs; // Overflow
286+ return ;
287+ }
288+ NextNode.Width = NextWidth;
289+
290+ // Ready if all incomings are processed.
291+ // Or NextNode.Width hasn't been confirmed yet.
292+ if (--NextNode.InCount == 0 )
293+ Q.push_back (NextID);
294+ }
295+ }
296+
297+ llvm::sort (Decisions);
298+
299+ // Assign TestVector Indices in Decision Nodes
300+ int64_t CurIdx = 0 ;
301+ for (auto [NegWidth, Ord, ID, C] : Decisions) {
302+ int Width = -NegWidth;
303+ assert (Nodes[ID].Width == Width);
304+ assert (Nodes[ID].NextIDs [C] < 0 );
305+ assert (Indices[ID][C] == INT_MIN);
306+ Indices[ID][C] = Offset + CurIdx;
307+ CurIdx += Width;
308+ if (CurIdx > HardMaxTVs) {
309+ NumTestVectors = HardMaxTVs; // Overflow
310+ return ;
311+ }
312+ }
313+
314+ assert (CurIdx < HardMaxTVs);
315+ NumTestVectors = CurIdx;
316+
317+ #ifndef NDEBUG
318+ for (const auto &Idxs : Indices)
319+ for (auto Idx : Idxs)
320+ assert (Idx != INT_MIN);
321+ SavedNodes = std::move (Nodes);
322+ #endif
323+ }
324+
226325namespace {
227326
228- class MCDCRecordProcessor {
327+ // / Construct this->NextIDs with Branches for TVIdxBuilder to use it
328+ // / before MCDCRecordProcessor().
329+ class NextIDsBuilder {
330+ protected:
331+ SmallVector<mcdc::ConditionIDs> NextIDs;
332+
333+ public:
334+ NextIDsBuilder (const ArrayRef<const CounterMappingRegion *> Branches)
335+ : NextIDs(Branches.size()) {
336+ #ifndef NDEBUG
337+ DenseSet<mcdc::ConditionID> SeenIDs;
338+ #endif
339+ for (const auto *Branch : Branches) {
340+ const auto &BranchParams = Branch->getBranchParams ();
341+ assert (BranchParams.ID >= 0 && " CondID isn't set" );
342+ assert (SeenIDs.insert (BranchParams.ID ).second && " Duplicate CondID" );
343+ NextIDs[BranchParams.ID ] = BranchParams.Conds ;
344+ }
345+ assert (SeenIDs.size () == Branches.size ());
346+ }
347+ };
348+
349+ class MCDCRecordProcessor : NextIDsBuilder, mcdc::TVIdxBuilder {
229350 // / A bitmap representing the executed test vectors for a boolean expression.
230351 // / Each index of the bitmap corresponds to a possible test vector. An index
231352 // / with a bit value of '1' indicates that the corresponding Test Vector
@@ -243,9 +364,6 @@ class MCDCRecordProcessor {
243364 // / Total number of conditions in the boolean expression.
244365 unsigned NumConditions;
245366
246- // / Mapping of a condition ID to its corresponding branch params.
247- llvm::DenseMap<unsigned , mcdc::ConditionIDs> CondsMap;
248-
249367 // / Vector used to track whether a condition is constant folded.
250368 MCDCRecord::BoolVector Folded;
251369
@@ -256,34 +374,43 @@ class MCDCRecordProcessor {
256374 // / ExecutedTestVectorBitmap.
257375 MCDCRecord::TestVectors ExecVectors;
258376
377+ #ifndef NDEBUG
378+ DenseSet<unsigned > TVIdxs;
379+ #endif
380+
259381public:
260382 MCDCRecordProcessor (const BitVector &Bitmap,
261383 const CounterMappingRegion &Region,
262384 ArrayRef<const CounterMappingRegion *> Branches)
263- : Bitmap(Bitmap ), Region(Region ),
264- DecisionParams (Region.getDecisionParams()), Branches(Branches ),
265- NumConditions(DecisionParams.NumConditions),
385+ : NextIDsBuilder(Branches ), TVIdxBuilder( this ->NextIDs), Bitmap(Bitmap ),
386+ Region (Region), DecisionParams(Region.getDecisionParams()),
387+ Branches(Branches), NumConditions(DecisionParams.NumConditions),
266388 Folded(NumConditions, false ), IndependencePairs(NumConditions) {}
267389
268390private:
269391 // Walk the binary decision diagram and try assigning both false and true to
270392 // each node. When a terminal node (ID == 0) is reached, fill in the value in
271393 // the truth table.
272394 void buildTestVector (MCDCRecord::TestVector &TV, mcdc::ConditionID ID,
273- unsigned Index) {
395+ int TVIdx, unsigned Index) {
274396 assert ((Index & (1 << ID)) == 0 );
275397
276398 for (auto MCDCCond : {MCDCRecord::MCDC_False, MCDCRecord::MCDC_True}) {
277399 static_assert (MCDCRecord::MCDC_False == 0 );
278400 static_assert (MCDCRecord::MCDC_True == 1 );
279401 Index |= MCDCCond << ID;
280402 TV[ID] = MCDCCond;
281- auto NextID = CondsMap[ID][MCDCCond];
403+ auto NextID = NextIDs[ID][MCDCCond];
404+ auto NextTVIdx = TVIdx + Indices[ID][MCDCCond];
405+ assert (NextID == SavedNodes[ID].NextIDs [MCDCCond]);
282406 if (NextID >= 0 ) {
283- buildTestVector (TV, NextID, Index);
407+ buildTestVector (TV, NextID, NextTVIdx, Index);
284408 continue ;
285409 }
286410
411+ assert (TVIdx < SavedNodes[ID].Width );
412+ assert (TVIdxs.insert (NextTVIdx).second && " Duplicate TVIdx" );
413+
287414 if (!Bitmap[DecisionParams.BitmapIdx * CHAR_BIT + Index])
288415 continue ;
289416
@@ -304,9 +431,12 @@ class MCDCRecordProcessor {
304431 void findExecutedTestVectors () {
305432 // Walk the binary decision diagram to enumerate all possible test vectors.
306433 // We start at the root node (ID == 0) with all values being DontCare.
434+ // `TVIdx` starts with 0 and is in the traversal.
307435 // `Index` encodes the bitmask of true values and is initially 0.
308436 MCDCRecord::TestVector TV (NumConditions, MCDCRecord::MCDC_DontCare);
309- buildTestVector (TV, 0 , 0 );
437+ buildTestVector (TV, 0 , 0 , 0 );
438+ assert (TVIdxs.size () == unsigned (NumTestVectors) &&
439+ " TVIdxs wasn't fulfilled" );
310440 }
311441
312442 // Find an independence pair for each condition:
@@ -367,7 +497,6 @@ class MCDCRecordProcessor {
367497 // from being measured.
368498 for (const auto *B : Branches) {
369499 const auto &BranchParams = B->getBranchParams ();
370- CondsMap[BranchParams.ID ] = BranchParams.Conds ;
371500 PosToID[I] = BranchParams.ID ;
372501 CondLoc[I] = B->startLoc ();
373502 Folded[I++] = (B->Count .isZero () && B->FalseCount .isZero ());
0 commit comments