diff options
author | LU-JOHN <John.Lu@amd.com> | 2025-07-31 08:44:14 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-31 09:44:14 -0400 |
commit | a757f23404c594f4a48b4ddb6625f88b349d11d5 (patch) | |
tree | 02354d664ee1244b6e7ce9fe8fd87da5717bfa19 /llvm/lib/Transforms/Utils/SimplifyCFG.cpp | |
parent | f54e4b26cd9e8180631865c9479154eb1b4b81a4 (diff) | |
download | llvm-a757f23404c594f4a48b4ddb6625f88b349d11d5.zip llvm-a757f23404c594f4a48b4ddb6625f88b349d11d5.tar.gz llvm-a757f23404c594f4a48b4ddb6625f88b349d11d5.tar.bz2 |
[SimplifyCFG] Extend jump-threading to allow live local defs (#135079)
Extend jump-threading to allow local defs that are live outside of the
threaded block. Allow threading to destinations where the local defs are
not live.
---------
Signed-off-by: John Lu <John.Lu@amd.com>
Diffstat (limited to 'llvm/lib/Transforms/Utils/SimplifyCFG.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 71 |
1 files changed, 61 insertions, 10 deletions
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 94b0ab8..674de57 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -198,6 +198,11 @@ static cl::opt<unsigned> MaxSwitchCasesPerResult( "max-switch-cases-per-result", cl::Hidden, cl::init(16), cl::desc("Limit cases to analyze when converting a switch to select")); +static cl::opt<unsigned> MaxJumpThreadingLiveBlocks( + "max-jump-threading-live-blocks", cl::Hidden, cl::init(24), + cl::desc("Limit number of blocks a define in a threaded block is allowed " + "to be live in")); + STATISTIC(NumBitMaps, "Number of switch instructions turned into bitmaps"); STATISTIC(NumLinearMaps, "Number of switch instructions turned into linear mapping"); @@ -3390,8 +3395,27 @@ bool SimplifyCFGOpt::speculativelyExecuteBB(BranchInst *BI, return true; } +using BlocksSet = SmallPtrSet<BasicBlock *, 8>; + +// Return false if number of blocks searched is too much. +static bool findReaching(BasicBlock *BB, BasicBlock *DefBB, + BlocksSet &ReachesNonLocalUses) { + if (BB == DefBB) + return true; + if (!ReachesNonLocalUses.insert(BB).second) + return true; + + if (ReachesNonLocalUses.size() > MaxJumpThreadingLiveBlocks) + return false; + for (BasicBlock *Pred : predecessors(BB)) + if (!findReaching(Pred, DefBB, ReachesNonLocalUses)) + return false; + return true; +} + /// Return true if we can thread a branch across this block. -static bool blockIsSimpleEnoughToThreadThrough(BasicBlock *BB) { +static bool blockIsSimpleEnoughToThreadThrough(BasicBlock *BB, + BlocksSet &NonLocalUseBlocks) { int Size = 0; EphemeralValueTracker EphTracker; @@ -3411,12 +3435,16 @@ static bool blockIsSimpleEnoughToThreadThrough(BasicBlock *BB) { return false; // Don't clone large BB's. } - // We can only support instructions that do not define values that are - // live outside of the current basic block. + // Record blocks with non-local uses of values defined in the current basic + // block. for (User *U : I.users()) { Instruction *UI = cast<Instruction>(U); - if (UI->getParent() != BB || isa<PHINode>(UI)) - return false; + BasicBlock *UsedInBB = UI->getParent(); + if (UsedInBB == BB) { + if (isa<PHINode>(UI)) + return false; + } else + NonLocalUseBlocks.insert(UsedInBB); } // Looks ok, continue checking. @@ -3475,18 +3503,37 @@ foldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU, return false; // Now we know that this block has multiple preds and two succs. - // Check that the block is small enough and values defined in the block are - // not used outside of it. - if (!blockIsSimpleEnoughToThreadThrough(BB)) + // Check that the block is small enough and record which non-local blocks use + // values defined in the block. + + BlocksSet NonLocalUseBlocks; + BlocksSet ReachesNonLocalUseBlocks; + if (!blockIsSimpleEnoughToThreadThrough(BB, NonLocalUseBlocks)) return false; + // Jump-threading can only be done to destinations where no values defined + // in BB are live. + + // Quickly check if both destinations have uses. If so, jump-threading cannot + // be done. + if (NonLocalUseBlocks.contains(BI->getSuccessor(0)) && + NonLocalUseBlocks.contains(BI->getSuccessor(1))) + return false; + + // Search backward from NonLocalUseBlocks to find which blocks + // reach non-local uses. + for (BasicBlock *UseBB : NonLocalUseBlocks) + // Give up if too many blocks are searched. + if (!findReaching(UseBB, BB, ReachesNonLocalUseBlocks)) + return false; + for (const auto &Pair : KnownValues) { - // Okay, we now know that all edges from PredBB should be revectored to - // branch to RealDest. ConstantInt *CB = Pair.first; ArrayRef<BasicBlock *> PredBBs = Pair.second.getArrayRef(); BasicBlock *RealDest = BI->getSuccessor(!CB->getZExtValue()); + // Okay, we now know that all edges from PredBB should be revectored to + // branch to RealDest. if (RealDest == BB) continue; // Skip self loops. @@ -3496,6 +3543,10 @@ foldCondBranchOnValueKnownInPredecessorImpl(BranchInst *BI, DomTreeUpdater *DTU, })) continue; + // Only revector to RealDest if no values defined in BB are live. + if (ReachesNonLocalUseBlocks.contains(RealDest)) + continue; + LLVM_DEBUG({ dbgs() << "Condition " << *Cond << " in " << BB->getName() << " has value " << *Pair.first << " in predecessors:\n"; |