From 376a71785da94f0d64cc5729f180c0e84ff2eb28 Mon Sep 17 00:00:00 2001 From: Clark Coleman <clc@zephyr-software.com> Date: Wed, 25 Nov 2020 10:11:48 -0500 Subject: [PATCH] SPARK: Continue improvements to new FindConditionalFollowNode() algorithm. --- include/base/SMPBasicBlock.h | 5 +- include/base/SMPFunction.h | 6 +- src/base/SMPBasicBlock.cpp | 54 +++--- src/base/SMPFunction.cpp | 353 +++++++++++++++++++++++++++-------- src/base/SMPProgram.cpp | 2 +- 5 files changed, 313 insertions(+), 107 deletions(-) diff --git a/include/base/SMPBasicBlock.h b/include/base/SMPBasicBlock.h index 458d4e07..bba1ebec 100644 --- a/include/base/SMPBasicBlock.h +++ b/include/base/SMPBasicBlock.h @@ -394,7 +394,10 @@ public: bool AllPredecessorsProcessed(void); void DepthFirstMark(bool MarkIBTBlocks); // Depth-first traversal, mark as processed. void DepthFirstMarkNonBackEdgeSuccessors(void); // Depth-first, but do not follow back edges. - bool IsBlockReachableWithoutBackEdges(const int DestBlockNum) const; // path without back edges? + + // NOTE: Call SMPFunction::ResetSCCPVisitedBlocks() before calling SMPBasicBlock::isBlockReachableWithoutBackEdges(). + bool IsBlockReachableWithoutBackEdges(const int DestBlockNum, bool &HitDeadEnd) const; // path without back edges? + std::size_t GetNumPredsMinusBackEdges(void) const; // Compute predecessor count, excluding loop-back edges. Loop ID must occur first. STARS_ea_t GetUltimateOperandSource(STARS_ea_t UseAddr, const STARSOpndTypePtr &UseOp, int UseSSANum); // trace through move and Phi defs to some defining operation. bool GetUltimateInitValue(const STARSOpndTypePtr &UseOp, STARS_ea_t InstAddr, int SSANum, bool LocalName, STARSOpndTypePtr &DefMoveOp, STARS_uval_t &InitValue); diff --git a/include/base/SMPFunction.h b/include/base/SMPFunction.h index 9c79a723..3b9224d3 100644 --- a/include/base/SMPFunction.h +++ b/include/base/SMPFunction.h @@ -609,6 +609,7 @@ public: bool DoesEdgeExitLoop(const int BlockNum1, const int BlockNum2) const; // Does going from BlockNum1 to BlockNum2 exit a loop? void BuildLoopList(int BlockNum, std::list<std::size_t> &LoopList) const; // build list of loop numbers that BlockNum is part of. void BuildLoopBlockList(const size_t LoopNum, std::list<std::size_t> &BlockList); // build list of Block numbers contained in LoopNum. + void BuildBlockListFromBitset(const STARSBitSet &CurrBitSet, std::list<std::size_t> &BlockList) const; // each bit set in CurrBitSet is a block # for BlockList void AnalyzeLoopIterations(void); // analyze how many times each loop iterates STARSExpression *CreateMemoryAddressExpr(const STARSOpndTypePtr &MemDefOp, SMPInstr *WriteInst); // create expression for the memory address computation in MemDefOp void AliasAnalysis(void); // Find memory writes with possible aliases @@ -1035,10 +1036,13 @@ private: int FindConditionalFollowNode(int HeadBlockNum); // Find candidate block # for if-else follow node for HeadBlockNum; return -1 otherwise int FindConditionalFollowNode2(int HeadBlockNum); // Find candidate block # for if-else follow node for HeadBlockNum; return -1 otherwise int FindConditionalFollowNode3(int HeadBlockNum); // Find candidate block # for if-else follow node for HeadBlockNum; return -1 otherwise + bool FindNextBlockAfterReachableBlocks(const int ContainingLoopNum, const STARSBitSet &BlocksSeen, int &NextBlockNum); // Get unique successor to BlocksSeen; return false if unable to do so. int TrackConditionalBranchTerminus(int BranchHeadBlockNum, int CurrBlockNum, STARSBitSet &BlocksSeen, int &BlockAlreadySeenCounter); // Track CurrBlockNum until we reach block that BranchHeadBlockNum doesn't dominate, or dead end. Return block num, possibly SMP_BLOCKNUM_COMMON_RETURN. - bool FindUnstructuredIfThenElse(const int HeadBlockNum, const int ThenBlockNum, const int ElseBlockNum, const int FollowBlockNum) const; // Do IF and ELSE branches merge before FollowBlockNum? + bool FindUnstructuredIfThenElse(const int HeadBlockNum, const int ThenBlockNum, const int ElseBlockNum, const int FollowBlockNum); // Do IF and ELSE branches merge before FollowBlockNum? + bool FindUnstructuredBlockList(const std::list<std::size_t> &BlockList, const int CondHeadBlockNum, const int FollowBlockNum); // Do any blocks fail to reach their FollowBlockNum? bool FindMultiLoopContinue(const int BranchBlockNum); // Does COND_BRANCH behave as an unstructured multi-level loop continue statement? bool DetectConditionalReachabilityErrors(const int HeadBlockNum, const int FTBlockNum, const int NFTBlockNum, const STARSBitSet &FTBlocksSeen, const STARSBitSet &NFTBlocksSeen, const STARSBitSet &CommonBlocksSeen); + bool ConditionalReachabilityLoopErrorHelper(const int CondHeadBlockNum, const int BlockNum) const; // Back door edge into loop exit targets (for multi-exit loops)? void FindGuardedLoops(void); // Find guarded loops and fill the GuardToLoopMap and LoopToGuardMap bool IsSPARKLoopInTranslationStack(void) const; // Are we already translating a SPARK_LOOP when we encounter another loop? diff --git a/src/base/SMPBasicBlock.cpp b/src/base/SMPBasicBlock.cpp index 2912fe70..52079071 100644 --- a/src/base/SMPBasicBlock.cpp +++ b/src/base/SMPBasicBlock.cpp @@ -384,11 +384,16 @@ void SMPBasicBlock::DepthFirstMarkNonBackEdgeSuccessors(void) { return; } // end of SMPBasicBlock::DepthFirstMark() +// NOTE: Call SMPFunction::ResetSCCPVisitedBlocks() before calling SMPBasicBlock::isBlockReachableWithoutBackEdges(). // Mark as processed, recurse into successors depth-first, do not follow back edges. -bool SMPBasicBlock::IsBlockReachableWithoutBackEdges(const int DestBlockNum) const { +bool SMPBasicBlock::IsBlockReachableWithoutBackEdges(const int DestBlockNum, bool &HitDeadEnd) const { bool Found = false; list<SMPBasicBlock *>::const_iterator CurrSucc; int CurrBlockNum = this->GetNumber(); + if (CurrBlockNum == DestBlockNum) { + Found = true; + return Found; + } // See if we can get lucky by finding the block in the DomFrontier. // This search is more breadth-first; combining breadth-first checks @@ -400,28 +405,33 @@ bool SMPBasicBlock::IsBlockReachableWithoutBackEdges(const int DestBlockNum) con } } // end for all DomFrontier blocks - for (CurrSucc = this->GetFirstConstSucc(); !Found && (CurrSucc != this->GetLastConstSucc()); ++CurrSucc) { - SMPBasicBlock *SuccBlock = (*CurrSucc); - int SuccBlockNum = SuccBlock->GetNumber(); - if (SuccBlockNum > CurrBlockNum) { // not back edge - if (SuccBlockNum == DestBlockNum) { - Found = true; - SuccBlock->SetSCCPVisited(true); - } - else if (SuccBlock->IsSCCPVisited()) { // already hit this block on our search - break; // return false - } - else if (SuccBlockNum > DestBlockNum) { - // RPO ordering means we can no longer reach DestBlockNum without a back edge. - SuccBlock->SetSCCPVisited(true); - break; // return false - } - else { - SuccBlock->SetSCCPVisited(true); - Found = SuccBlock->IsBlockReachableWithoutBackEdges(DestBlockNum); // recurse, depth-first + if (0 == this->GetNumSuccessors()) { + HitDeadEnd = true; + } + else { + for (CurrSucc = this->GetFirstConstSucc(); !Found && (CurrSucc != this->GetLastConstSucc()); ++CurrSucc) { + SMPBasicBlock *SuccBlock = (*CurrSucc); + int SuccBlockNum = SuccBlock->GetNumber(); + if (SuccBlockNum > CurrBlockNum) { // not back edge + if (SuccBlockNum == DestBlockNum) { + Found = true; + SuccBlock->SetSCCPVisited(true); + } + else if (SuccBlock->IsSCCPVisited()) { // already hit this block on our search + break; // return false + } + else if (SuccBlockNum > DestBlockNum) { + // RPO ordering means we can no longer reach DestBlockNum without a back edge. + SuccBlock->SetSCCPVisited(true); + break; // return false + } + else { + SuccBlock->SetSCCPVisited(true); + Found = SuccBlock->IsBlockReachableWithoutBackEdges(DestBlockNum, HitDeadEnd); // recurse, depth-first + } } - } - } // end for all successor blocks + } // end for all successor blocks + } return Found; } // end of SMPBasicBlock::IsBlockReachableWithoutBackEdges() diff --git a/src/base/SMPFunction.cpp b/src/base/SMPFunction.cpp index 98841957..2ed179d5 100644 --- a/src/base/SMPFunction.cpp +++ b/src/base/SMPFunction.cpp @@ -7394,29 +7394,44 @@ void SMPFunction::ComputeLoopFollowNodesReachability(const std::size_t LoopNum) assert(LoopNum < this->GetNumLoops()); assert(LoopNum < this->LoopExitTargets.size()); int LoopHeadBlockNum = this->LoopHeadBlockNumbers[LoopNum]; + bool Unstructured = false; for (int FollowNodeNum : this->LoopExitTargets[LoopNum]) { STARSBitSet Reachable; Reachable.AllocateBits(this->GetNumBlocks()); this->MarkReachableBlocks(FollowNodeNum, (int)LoopNum, LoopHeadBlockNum, Reachable); - pair<int, STARSBitSet> MapItem(FollowNodeNum, Reachable); - this->LoopExitTargetsReachabilitySets[LoopNum].insert(MapItem); + if (Reachable.IsAnyBitSet()) { + pair<int, STARSBitSet> MapItem(FollowNodeNum, Reachable); + this->LoopExitTargetsReachabilitySets[LoopNum].insert(MapItem); + } + else { + Unstructured = true; + if (!this->PrintedSPARKUnstructuredMsg) { + SMP_msg("ERROR: SPARK: Unstructured due to no loop head dominance of follow node %d from loop %zu ", FollowNodeNum, LoopNum); + this->DumpFuncNameAndAddr(); + this->PrintedSPARKUnstructuredMsg = true; + } + this->HasStructuredCFG = false; + break; + } } - // Find out where the multiple follow nodes converge, if they do. If they all hit separate return blocks, - // we use the code of -2 to signify it. - if (this->MultiLoopExitTargetsConvergenceMap[LoopNum].empty()) { - // Must have hit return blocks. - this->MultiLoopExitTargetsConvergenceMap[LoopNum].insert(SMP_BLOCKNUM_COMMON_RETURN); - } - else if (1 != this->MultiLoopExitTargetsConvergenceMap[LoopNum].size()) { - if (!this->PrintedSPARKUnstructuredMsg) { - SMP_msg("ERROR: SPARK: Unstructured due to no convergence of multiple follow nodes from loop %zu ", LoopNum); - this->DumpFuncNameAndAddr(); - this->PrintedSPARKUnstructuredMsg = true; + if (!Unstructured) { + // Find out where the multiple follow nodes converge, if they do. If they all hit separate return blocks, + // we use the code of -2 to signify it. + if (this->MultiLoopExitTargetsConvergenceMap[LoopNum].empty()) { + // Must have hit return blocks. + this->MultiLoopExitTargetsConvergenceMap[LoopNum].insert(SMP_BLOCKNUM_COMMON_RETURN); + } + else if (1 != this->MultiLoopExitTargetsConvergenceMap[LoopNum].size()) { + if (!this->PrintedSPARKUnstructuredMsg) { + SMP_msg("ERROR: SPARK: Unstructured due to no convergence of multiple follow nodes from loop %zu ", LoopNum); + this->DumpFuncNameAndAddr(); + this->PrintedSPARKUnstructuredMsg = true; + } + this->HasStructuredCFG = false; // multi-exit loop has no single convergence point of follow nodes. + // TODO: If the multiple termination blocks all loop back to the same outer loop head block, this + // is structured code and can be translated. !!!!****!!!! } - this->HasStructuredCFG = false; // multi-exit loop has no single convergence point of follow nodes. - // TODO: If the multiple termination blocks all loop back to the same outer loop head block, this - // is structured code and can be translated. !!!!****!!!! } return; @@ -12130,7 +12145,7 @@ int SMPFunction::FindConditionalFollowNode(int HeadBlockNum) { else { if (BadNew) { SMP_msg("INFO: SPARK: Success on old version, failure on new version of FindConditionalFollowNode at block %d Follow: %d ", HeadBlockNum, OldAlgorithmFollowNode); - ReturnFollowBlockNum = OldAlgorithmFollowNode; + // ReturnFollowBlockNum = OldAlgorithmFollowNode; this->DumpDotCFG(); } else { @@ -12440,15 +12455,16 @@ int SMPFunction::FindConditionalFollowNode2(int HeadBlockNum) { // Screen out remaining if-then cases by ensuring that neither branch // can reach the other without following a back edge. It is sufficient // to check whether the lower RPO-numbered block can reach the other. + bool HitDeadEnd = false; if (ThenBlockNum < ElseBlockNum) { SMPBasicBlock *ThenBlock = this->GetBlockByNum(ThenBlockNum); this->ResetSCCPVisitedBlocks(); // SCCP is long since done; reuse its visited flag in each block - IfThenElseCase = (!ThenBlock->IsBlockReachableWithoutBackEdges(ElseBlockNum)); + IfThenElseCase = (!ThenBlock->IsBlockReachableWithoutBackEdges(ElseBlockNum, HitDeadEnd)); } else { SMPBasicBlock *ElseBlock = this->GetBlockByNum(ElseBlockNum); this->ResetSCCPVisitedBlocks(); // SCCP is long since done; reuse its visited flag in each block - IfThenElseCase = (!ElseBlock->IsBlockReachableWithoutBackEdges(ThenBlockNum)); + IfThenElseCase = (!ElseBlock->IsBlockReachableWithoutBackEdges(ThenBlockNum, HitDeadEnd)); } } if (!IfThenElseCase) { @@ -12614,6 +12630,11 @@ int SMPFunction::FindConditionalFollowNode3(int HeadBlockNum) { // 1. No intersection of the two bitsets. FollowBlockNum is -2 (SMP_BLOCKNUM_COMMON_RETURN) // indicating the lack of intersection, with each trace ending in a block with no successors // (e.g. return instructions or calls to non-returning functions or halt instructions or LOOP_BACKs). + // + // If NFTBlockNum is not dominated by HeadBlockNum, but FTBlockNum is dominated by HeadBlockNum, + // then the FTBlockNum branch is part of an IF-THEN. If vice versa, the NFTBlockNum is part of an OddIfThenCase. + // If neither FTBlockNum nor NFTBlockNum is dominated by HeadBlockNum, the code is unstructured. + // // EXCEPTION: Intersection point was about to happen, but it is just out of the region dominated // by HeadBlockNum, e.g. conditional join point is also a loop follow block for an enclosing loop or // is a join point for an enclosing conditional. This can be detected by seeing if the end of each @@ -12658,12 +12679,16 @@ int SMPFunction::FindConditionalFollowNode3(int HeadBlockNum) { CommonBlocksSeen = STARSBitSetIntersection(FTBlocksSeen, NFTBlocksSeen); size_t CommonBlocksCount = CommonBlocksSeen.CountSetBits(); int FirstCommonBlockNum = CommonBlocksSeen.FindLowestBitSet(); - int LastFTReachableBlockNum = FTBlocksSeen.FindHighestBitSet(); - int LastNFTReachableBlockNum = NFTBlocksSeen.FindHighestBitSet(); - bool IfThenElseCase = true; + bool IntersectionSeen = (0 < CommonBlocksCount); + bool FTNotDominated = (!this->DoesBlockDominateBlock(HeadBlockNum, FTBlockNum)); bool NFTNotDominated = (!this->DoesBlockDominateBlock(HeadBlockNum, NFTBlockNum)); bool DominanceProblem = (FTNotDominated || NFTNotDominated); + + int LastFTReachableBlockNum = FTBlocksSeen.FindHighestBitSet(); + int LastNFTReachableBlockNum = NFTBlocksSeen.FindHighestBitSet(); + int LastBlockNumReached = (LastFTReachableBlockNum >= LastNFTReachableBlockNum) ? LastFTReachableBlockNum : LastNFTReachableBlockNum; + bool IfThenElseCase = true; bool Case0 = false; // Find CFG problems that are obvious just from the reachability bitsets. @@ -12673,29 +12698,29 @@ int SMPFunction::FindConditionalFollowNode3(int HeadBlockNum) { // Based on CommonBlocksCount, FirstCommonBlockNum, FTBlockNum, and NFTBlockNum, we // can find which case in the comment above applies. - if (0 == CommonBlocksCount) { // Case 1 or Case 0. + if (!IntersectionSeen) { // Case 1 or Case 0. FollowBlockNum = SMP_BLOCKNUM_COMMON_RETURN; // Case 1 // Detect the Case 1 exception subcase. int NextFTBlockNum = SMP_BLOCKNUM_UNINIT; int NextNFTBlockNum = SMP_BLOCKNUM_UNINIT; if (0 <= LastFTReachableBlockNum) { // FTBlock was dominated by HeadBlock - SMPBasicBlock *LastFTBlockReached = this->GetBlockByNum((size_t)LastFTReachableBlockNum); - if (1 == LastFTBlockReached->GetNumSuccessors()) { - NextFTBlockNum = (*(LastFTBlockReached->GetFirstConstSucc()))->GetNumber(); + bool ErrorSeen = this->FindNextBlockAfterReachableBlocks(InnerMostLoopNum, FTBlocksSeen, NextFTBlockNum); + if (ErrorSeen) { + FollowBlockNum = SMP_BLOCKNUM_UNINIT; } } else { // FTBlock was outside region dominated by HeadBlock NextFTBlockNum = FTBlockNum; // First block outside dominated region IfThenElseCase = false; } - if (0 <= LastNFTReachableBlockNum) { // FTBlock was dominated by HeadBlock - SMPBasicBlock *LastNFTBlockReached = this->GetBlockByNum((size_t)LastNFTReachableBlockNum); - if (1 == LastNFTBlockReached->GetNumSuccessors()) { - NextNFTBlockNum = (*(LastNFTBlockReached->GetFirstConstSucc()))->GetNumber(); + if (0 <= LastNFTReachableBlockNum) { // NFTBlock was dominated by HeadBlock + bool ErrorSeen = this->FindNextBlockAfterReachableBlocks(InnerMostLoopNum, NFTBlocksSeen, NextNFTBlockNum); + if (ErrorSeen) { + FollowBlockNum = SMP_BLOCKNUM_UNINIT; } } - else { // FTBlock was outside region dominated by HeadBlock + else { // NFTBlock was outside region dominated by HeadBlock NextNFTBlockNum = NFTBlockNum; // First block outside dominated region IfThenElseCase = false; } @@ -12790,10 +12815,95 @@ int SMPFunction::FindConditionalFollowNode3(int HeadBlockNum) { } } } + // All THEN and ELSE blocks should be able to reach the FollowBlockNum. + if (0 <= FollowBlockNum) { + // Eliminate blocks after the FollowBlockNum from the bitsets. + for (int BlockIndex = FollowBlockNum; BlockIndex <= LastBlockNumReached; ++BlockIndex) { + FTBlocksSeen.ResetBit((size_t)BlockIndex); + NFTBlocksSeen.ResetBit((size_t)BlockIndex); + } + list<size_t> ReachedBlocksList; + this->BuildBlockListFromBitset(FTBlocksSeen, ReachedBlocksList); + this->BuildBlockListFromBitset(NFTBlocksSeen, ReachedBlocksList); + this->ResetSCCPVisitedBlocks(); + if (this->FindUnstructuredBlockList(ReachedBlocksList, HeadBlockNum, FollowBlockNum)) { + FollowBlockNum = SMP_BLOCKNUM_UNINIT; // error + } + } return FollowBlockNum; } // end of SMPFunction::FindConditionalFollowNode3() +// Get unique successor to BlocksSeen; return false if unable to do so. +bool SMPFunction::FindNextBlockAfterReachableBlocks(const int ContainingLoopNum, const STARSBitSet &BlocksSeen, int &NextBlockNum) { + // If we don't encounter any loops, we just go to the end of the BlocksSeen trace and + // get the unique successor to the last block. If we see a loop along the way, we + // look at the exit targets. All exit targets must be in the BlocksSeen trace. If + // the LoopFollowNode is also in the trace, continue with it and skip over the blocks + // within the loop. If not, then the LoopFollowNode is the NextBlockNum we are searching for. + int LowestBlockNum = BlocksSeen.FindLowestBitSet(); + int HighestBlockNum = BlocksSeen.FindHighestBitSet(); + int HighestNonLoopBlockNum = 0; + bool ErrorSeen = (0 > LowestBlockNum); + int BlockNum = LowestBlockNum; + bool UsedLoopFollowBlock = false; + while (BlockNum <= HighestBlockNum) { + size_t BlockIndex = (size_t)BlockNum; + int InnermostLoopNum = this->GetInnermostLoopNum(BlockNum); + if (BlocksSeen.GetBit(BlockIndex)) { + SMPBasicBlock *CurrBlock = this->GetBlockByNum(BlockIndex); + if (InnermostLoopNum != ContainingLoopNum) { // Entered into loop within conditional statement + if (CurrBlock->IsLoopHeaderBlock()) { // jump to follow block + int LoopNum = this->GetLoopNumFromHeaderBlockNum(BlockNum); + int LoopFollowBlockNum; + bool MultiExitTargetLoop = this->GetLoopFollowBlockNum((size_t)LoopNum, LoopFollowBlockNum); + if (0 > LoopFollowBlockNum) { + ErrorSeen = true; + break; + } + if (BlocksSeen.GetBit((size_t)LoopFollowBlockNum)) { + // Loop and its follow node are contained inside the current conditional branch. Continue + // with the follow node and beyond. + BlockNum = LoopFollowBlockNum; + } + else { + // Loop is in current conditional branch, but its follow block is not. If the + // code is structured, it will be the case that the loop follow block is also + // the follow block for the containing conditional statement, and the SPARK Ada + // decompilation will have "end loop;" falling directly into "end if;". + NextBlockNum = LoopFollowBlockNum; + UsedLoopFollowBlock = true; + break; + } + } + else { + ++BlockNum; // Don't bother with loop blocks other than the header block + } + } + else { + HighestNonLoopBlockNum = BlockNum; + ++BlockNum; + } + } + else { + ++BlockNum; + } + } // end while (BlockNum <= HighestBlockNum) + + if (!ErrorSeen) { + if (!UsedLoopFollowBlock) { + // Still need convergence point. + SMPBasicBlock *LastBlock = this->GetBlockByNum((size_t)HighestNonLoopBlockNum); + assert(nullptr != LastBlock); + if (1 == LastBlock->GetNumSuccessors()) { + NextBlockNum = (*(LastBlock->GetFirstConstSucc()))->GetNumber(); + ErrorSeen = (0 > NextBlockNum); + } + } + } + + return ErrorSeen; +} // end of SMPFunction::FindNextBlockAfterReachableBlocks() // Track CurrBlockNum until we reach block that BranchHeadBlockNum doesn't dominate, or dead end. Return block num, possibly SMP_BLOCKNUM_COMMON_RETURN. // A dead end is a block that returns or that calls a non-returning function. @@ -12947,8 +13057,8 @@ int SMPFunction::TrackConditionalBranchTerminus(int BranchHeadBlockNum, int Curr return TerminusBlockNum; } // end of SMPFunction::TrackConditionalBranchTerminus() -// Do IF and ELSE branches merge before FollowBlockNum? -bool SMPFunction::FindUnstructuredIfThenElse(const int HeadBlockNum, const int ThenBlockNum, const int ElseBlockNum, const int FollowBlockNum) const { +// Do IF and ELSE branches merge before FollowBlockNum? Do all IF and ELSE blocks reach FollowBlockNum? +bool SMPFunction::FindUnstructuredIfThenElse(const int HeadBlockNum, const int ThenBlockNum, const int ElseBlockNum, const int FollowBlockNum) { bool UnstructuredClauses = false; if ((SMP_BLOCKNUM_UNINIT != ElseBlockNum) && (SMP_BLOCKNUM_UNINIT != ThenBlockNum)) { @@ -13009,11 +13119,62 @@ bool SMPFunction::FindUnstructuredIfThenElse(const int HeadBlockNum, const int T break; } } + if (!UnstructuredClauses && (0 < FollowBlockNum)) { + // Every block in the THEN clause should reach the follow block. Ditto for every + // block in the ELSE clause. + list<size_t> BlockNumList; + this->BuildBlockListFromBitset(ThenBlocksSeen, BlockNumList); + this->BuildBlockListFromBitset(ElseBlocksSeen, BlockNumList); + UnstructuredClauses = this->FindUnstructuredBlockList(BlockNumList, HeadBlockNum, FollowBlockNum); + } } return UnstructuredClauses; } // end of SMPFunction::FindUnstructuredIfThenElse() +// Do any blocks fail to reach their FollowBlockNum? +bool SMPFunction::FindUnstructuredBlockList(const list<size_t> &BlockList, const int CondHeadBlockNum, const int FollowBlockNum) { + assert(0 < FollowBlockNum); + bool Unstructured = false; + int InnermostContainingLoopNum = this->GetInnermostLoopNum(CondHeadBlockNum); + + for (size_t BlockNum : BlockList) { + SMPBasicBlock *CurrBlock = this->GetBlockByNum(BlockNum); + bool HitDeadEnd = false; + + // Every block in a loop can make it back to the header block. If the header + // block can reach FollowBlockNum, then all blocks in the loop can also reach + // FollowBlockNum, but some might have to follow a back edge to the loop header + // block in order to do so. We can save time and avoid special-case following of + // back edges by only testing the header blocks. + // NOTE: If the header block is not inside the conditional statement, meaning that the + // conditional statement is contained in the block, then we would ignore all blocks in + // the conditional statement and analyze nothing. We need to separate internal loops from + // containing loops. For internal loops, the header block should reach the conditional + // follow node and other loop blocks can be ignored. For containing loops, we do not ignore + // any blocks; each must reach the conditional follow node. + bool LoopDontCareBlock = (this->IsBlockInAnyLoop((int)BlockNum) && (!CurrBlock->IsLoopHeaderBlock())); + if (LoopDontCareBlock) { + // Don't ignore blocks from the containing loop. + int InnermostLoopNum = this->GetInnermostLoopNum((int)BlockNum); + LoopDontCareBlock = (InnermostContainingLoopNum != InnermostLoopNum); + } + if (!LoopDontCareBlock) { + this->ResetSCCPVisitedBlocks(); + if (!CurrBlock->IsBlockReachableWithoutBackEdges(FollowBlockNum, HitDeadEnd)) { + if (!HitDeadEnd) { + Unstructured = true; + break; + } + } + } + } // end for all blocks in BlockList + + return Unstructured; +} // end of SMPFunction::FindUnstructuredBlockList() + + + // Does COND_BRANCH behave as an unstructured multi-level loop continue statement? bool SMPFunction::FindMultiLoopContinue(const int BranchBlockNum) { assert(0 <= BranchBlockNum); @@ -13089,74 +13250,96 @@ bool SMPFunction::DetectConditionalReachabilityErrors(const int HeadBlockNum, co // All blocks reachable by either FTBlock or NFTBlock should either precede the intersection point or // should be in CommonBlocksSeen (i.e. RPO block number greater than intersection point RPO number - // should imply that we are merely continuing downward from the intersection point). + // should imply that we are merely continuing downward from the intersection point). This is only true + // for the IfThenElse case, not for an IfThen. int IntersectionBlockNum = CommonBlocksSeen.FindLowestBitSet(); bool TracesIntersect = (0 < IntersectionBlockNum); if (TracesIntersect) { - for (size_t BlockNum = (size_t)(IntersectionBlockNum + 1); BlockNum < this->GetNumBlocks(); ++BlockNum) { - if (FTBlocksSeen.GetBit(BlockNum)) { - bool success = NFTBlocksSeen.GetBit(BlockNum); - if (!success) { - Unstructured = true; - break; + bool IfThenCase = (IntersectionBlockNum == NFTBlockNum); + bool OddIfThenCase = (IntersectionBlockNum == FTBlockNum); + bool IfThenElseCase = (!(IfThenCase || OddIfThenCase)); + if (IfThenElseCase) { + for (size_t BlockNum = (size_t)(IntersectionBlockNum + 1); BlockNum < this->GetNumBlocks(); ++BlockNum) { + if (FTBlocksSeen.GetBit(BlockNum)) { + bool success = NFTBlocksSeen.GetBit(BlockNum); + if (!success) { + Unstructured = true; + break; + } } } } } - if (!Unstructured) { - // Ensure that any loop contained inside the then or else clauses has its exit target - // blocks dominated by the loop head block; a "back door" into a loop exit target block - // that does not come from the loop must be restructured. - int LowestBlockSeen = FTBlocksSeen.FindLowestBitSet(); - int HighestBlockSeen = FTBlocksSeen.FindHighestBitSet(); - int LimitBlockNum = TracesIntersect ? IntersectionBlockNum : HighestBlockSeen; - if (0 <= LowestBlockSeen) { - for (int BlockNum = LowestBlockSeen; BlockNum <= LimitBlockNum; ++BlockNum) { - if (FTBlocksSeen.GetBit((size_t)BlockNum)) { - SMPBasicBlock *CurrBlock = this->GetBlockByNum((size_t)BlockNum); - if (CurrBlock->IsLoopHeaderBlock()) { - int LoopNum = this->GetLoopNumFromHeaderBlockNum(BlockNum); - assert(0 <= LoopNum); - for (int ExitTargetBlockNum : this->LoopExitTargets[(size_t)LoopNum]) { - if (!this->DoesBlockDominateBlock(HeadBlockNum, ExitTargetBlockNum)) { - Unstructured = true; - break; - } + if (0 < this->GetNumLoops()) { + if (!Unstructured) { + // Ensure that any loop contained inside the then or else clauses has its exit target + // blocks dominated by the loop head block; a "back door" into a loop exit target block + // that does not come from the loop must be restructured. + int LowestBlockSeen = FTBlocksSeen.FindLowestBitSet(); + int HighestBlockSeen = FTBlocksSeen.FindHighestBitSet(); + int LimitBlockNum = TracesIntersect ? IntersectionBlockNum : HighestBlockSeen; + if (0 <= LowestBlockSeen) { + for (int BlockNum = LowestBlockSeen; BlockNum <= LimitBlockNum; ++BlockNum) { + if (FTBlocksSeen.GetBit((size_t)BlockNum)) { + if (this->ConditionalReachabilityLoopErrorHelper(HeadBlockNum, BlockNum)) { + Unstructured = true; + break; } } } } } - } - if (!Unstructured) { - // Ensure that any loop contained inside the then or else clauses has its exit target - // blocks dominated by the loop head block; a "back door" into a loop exit target block - // that does not come from the loop must be restructured. - int LowestBlockSeen = NFTBlocksSeen.FindLowestBitSet(); - int HighestBlockSeen = NFTBlocksSeen.FindHighestBitSet(); - int LimitBlockNum = TracesIntersect ? IntersectionBlockNum : HighestBlockSeen; - if (0 <= LowestBlockSeen) { - for (int BlockNum = LowestBlockSeen; BlockNum <= LimitBlockNum; ++BlockNum) { - if (NFTBlocksSeen.GetBit((size_t)BlockNum)) { - SMPBasicBlock *CurrBlock = this->GetBlockByNum((size_t)BlockNum); - if (CurrBlock->IsLoopHeaderBlock()) { - int LoopNum = this->GetLoopNumFromHeaderBlockNum(BlockNum); - assert(0 <= LoopNum); - for (int ExitTargetBlockNum : this->LoopExitTargets[(size_t)LoopNum]) { - if (!this->DoesBlockDominateBlock(HeadBlockNum, ExitTargetBlockNum)) { - Unstructured = true; - break; - } + if (!Unstructured) { + // Ensure that any loop contained inside the then or else clauses has its exit target + // blocks dominated by the loop head block; a "back door" into a loop exit target block + // that does not come from the loop must be restructured. + int LowestBlockSeen = NFTBlocksSeen.FindLowestBitSet(); + int HighestBlockSeen = NFTBlocksSeen.FindHighestBitSet(); + int LimitBlockNum = TracesIntersect ? IntersectionBlockNum : HighestBlockSeen; + if (0 <= LowestBlockSeen) { + for (int BlockNum = LowestBlockSeen; BlockNum <= LimitBlockNum; ++BlockNum) { + if (NFTBlocksSeen.GetBit((size_t)BlockNum)) { + if (this->ConditionalReachabilityLoopErrorHelper(HeadBlockNum, BlockNum)) { + Unstructured = true; + break; } } } } } - } + } // end if we have loops return Unstructured; } // end of SMPFunction::DetectConditionalReachabilityErrors() +// Back door edge into loop exit targets (for multi-exit loops)? +bool SMPFunction::ConditionalReachabilityLoopErrorHelper(const int CondHeadBlockNum, const int BlockNum) const { + bool Unstructured = false; + + SMPBasicBlock *CurrBlock = this->GetBlockByNum((size_t)BlockNum); + if (CurrBlock->IsLoopHeaderBlock()) { + int InnerLoopNum = this->GetLoopNumFromHeaderBlockNum(BlockNum); + assert(0 <= InnerLoopNum); + bool MultiExitTargetInnerLoop = this->DoesLoopHaveMultipleExitTargets(InnerLoopNum); + for (int ExitTargetBlockNum : this->LoopExitTargets[(size_t)InnerLoopNum]) { + // If we have multiple exit targets, then they should all be contained + // with the ELSE-branch, with their common successor being the loop + // follow node. This loop follow node can be a common follow node for enclosing + // statements, including the current conditional statement and outer + // conditional statements, in which case the inner HeadBlock does not + // dominate it. However, with multiple exit targets, the exit targets + // themselves must be dominated by the conditional HeadBlockNum in order + // to be a structured CFG. + if (MultiExitTargetInnerLoop && (!this->DoesBlockDominateBlock(CondHeadBlockNum, ExitTargetBlockNum))) { + Unstructured = true; + break; + } + } + } + + return Unstructured; +} // end of SMPFunction::ConditionalReachabilityLoopErrorHelper() + // Find guarded loops and fill the GuardToLoopMap and LoopToGuardMap void SMPFunction::FindGuardedLoops(void) { assert(this->HasStructuredControlFlow()); @@ -15074,13 +15257,19 @@ void SMPFunction::BuildLoopList(int BlockNum, list<std::size_t> &LoopList) const // Build list of Block numbers contained in LoopNum. void SMPFunction::BuildLoopBlockList(const size_t LoopNum, list<std::size_t> &BlockList) { assert(LoopNum < this->LoopCount); + this->BuildBlockListFromBitset(this->FuncBlocksByLoop.at(LoopNum), BlockList); + return; +} // end of SMPFunction::BuildLoopBlockList() + +// each bit set in CurrBitSet is a block # for BlockList +void SMPFunction::BuildBlockListFromBitset(const STARSBitSet &CurrBitSet, list<std::size_t> &BlockList) const { for (size_t BlockIndex = 0; BlockIndex < (size_t)this->BlockCount; ++BlockIndex) { - if (this->FuncBlocksByLoop.at(LoopNum).GetBit(BlockIndex)) { + if (CurrBitSet.GetBit(BlockIndex)) { BlockList.push_back(BlockIndex); } } return; -} // end of SMPFunction::BuildLoopBlockList() +} // end of SMPFunction::BuildBlockListFromBitset() // Analyze how many times each loop iterates void SMPFunction::AnalyzeLoopIterations(void) { diff --git a/src/base/SMPProgram.cpp b/src/base/SMPProgram.cpp index b280b464..9089d66d 100644 --- a/src/base/SMPProgram.cpp +++ b/src/base/SMPProgram.cpp @@ -1147,7 +1147,7 @@ bool SMPProgram::EmitProgramSPARKAda(void) { for (FuncIter = this->FuncMap.begin(); FuncIter != this->FuncMap.end(); ++FuncIter) { SMPFunction *TempFunc = FuncIter->second; if (TempFunc == nullptr) continue; - bool FuncFound = (0x444492 == TempFunc->GetFirstFuncAddr()); + bool FuncFound = (0x402b90 == TempFunc->GetFirstFuncAddr()); if (FuncFound) { TempFunc->Dump(); TempFunc->DumpDotCFG(); -- GitLab