diff options
author | Yingwei Zheng <dtcxzyw2333@gmail.com> | 2024-07-01 03:35:39 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-01 03:35:39 +0800 |
commit | 4997af98a008e71a3df61707559710d1c2769839 (patch) | |
tree | 4a67444eec67ef4dac3a70926ed04279e2212e24 /llvm/lib/Transforms/Utils/SimplifyCFG.cpp | |
parent | 3efac5c68ac3117e8488a7fa247e45951e52936f (diff) | |
download | llvm-4997af98a008e71a3df61707559710d1c2769839.zip llvm-4997af98a008e71a3df61707559710d1c2769839.tar.gz llvm-4997af98a008e71a3df61707559710d1c2769839.tar.bz2 |
[SimplifyCFG] Simplify nested branches (#97067)
This patch folds the following pattern (I don't know what to call this):
```
bb0:
br i1 %cond1, label %bb1, label %bb2
bb1:
br i1 %cond2, label %bb3, label %bb4
bb2:
br i1 %cond2, label %bb4, label %bb3
bb3:
...
bb4:
...
```
into
```
bb0:
%cond = xor i1 %cond1, %cond2
br i1 %cond, label %bb4, label %bb3
bb3:
...
bb4:
...
```
Alive2: https://alive2.llvm.org/ce/z/5iOJEL
Closes https://github.com/llvm/llvm-project/issues/97022.
Closes https://github.com/llvm/llvm-project/issues/83417.
I found this pattern in some verilator-generated code, which is widely
used in RTL simulation. This fold will reduces branches and improves the
performance of CPU frontend. To my surprise, this pattern is also common
in C/C++ code base.
Affected libraries/applications:
cmake/cvc5/freetype/git/gromacs/jq/linux/openblas/openmpi/openssl/php/postgres/ruby/sqlite/wireshark/z3/...
Diffstat (limited to 'llvm/lib/Transforms/Utils/SimplifyCFG.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 6847bb7..69daa63 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -7361,6 +7361,95 @@ static BasicBlock *allPredecessorsComeFromSameSource(BasicBlock *BB) { return PredPred; } +/// Fold the following pattern: +/// bb0: +/// br i1 %cond1, label %bb1, label %bb2 +/// bb1: +/// br i1 %cond2, label %bb3, label %bb4 +/// bb2: +/// br i1 %cond2, label %bb4, label %bb3 +/// bb3: +/// ... +/// bb4: +/// ... +/// into +/// bb0: +/// %cond = xor i1 %cond1, %cond2 +/// br i1 %cond, label %bb4, label %bb3 +/// bb3: +/// ... +/// bb4: +/// ... +/// NOTE: %cond2 always dominates the terminator of bb0. +static bool mergeNestedCondBranch(BranchInst *BI, DomTreeUpdater *DTU) { + BasicBlock *BB = BI->getParent(); + BasicBlock *BB1 = BI->getSuccessor(0); + BasicBlock *BB2 = BI->getSuccessor(1); + auto IsSimpleSuccessor = [BB](BasicBlock *Succ, BranchInst *&SuccBI) { + if (Succ == BB) + return false; + if (&Succ->front() != Succ->getTerminator()) + return false; + SuccBI = dyn_cast<BranchInst>(Succ->getTerminator()); + if (!SuccBI || !SuccBI->isConditional()) + return false; + BasicBlock *Succ1 = SuccBI->getSuccessor(0); + BasicBlock *Succ2 = SuccBI->getSuccessor(1); + return Succ1 != Succ && Succ2 != Succ && Succ1 != BB && Succ2 != BB && + !isa<PHINode>(Succ1->front()) && !isa<PHINode>(Succ2->front()); + }; + BranchInst *BB1BI, *BB2BI; + if (!IsSimpleSuccessor(BB1, BB1BI) || !IsSimpleSuccessor(BB2, BB2BI)) + return false; + + if (BB1BI->getCondition() != BB2BI->getCondition() || + BB1BI->getSuccessor(0) != BB2BI->getSuccessor(1) || + BB1BI->getSuccessor(1) != BB2BI->getSuccessor(0)) + return false; + + BasicBlock *BB3 = BB1BI->getSuccessor(0); + BasicBlock *BB4 = BB1BI->getSuccessor(1); + IRBuilder<> Builder(BI); + BI->setCondition( + Builder.CreateXor(BI->getCondition(), BB1BI->getCondition())); + BB1->removePredecessor(BB); + BI->setSuccessor(0, BB4); + BB2->removePredecessor(BB); + BI->setSuccessor(1, BB3); + if (DTU) { + SmallVector<DominatorTree::UpdateType, 4> Updates; + Updates.push_back({DominatorTree::Delete, BB, BB1}); + Updates.push_back({DominatorTree::Insert, BB, BB4}); + Updates.push_back({DominatorTree::Delete, BB, BB2}); + Updates.push_back({DominatorTree::Insert, BB, BB3}); + + DTU->applyUpdates(Updates); + } + bool HasWeight = false; + uint64_t BBTWeight, BBFWeight; + if (extractBranchWeights(*BI, BBTWeight, BBFWeight)) + HasWeight = true; + else + BBTWeight = BBFWeight = 1; + uint64_t BB1TWeight, BB1FWeight; + if (extractBranchWeights(*BB1BI, BB1TWeight, BB1FWeight)) + HasWeight = true; + else + BB1TWeight = BB1FWeight = 1; + uint64_t BB2TWeight, BB2FWeight; + if (extractBranchWeights(*BB2BI, BB2TWeight, BB2FWeight)) + HasWeight = true; + else + BB2TWeight = BB2FWeight = 1; + if (HasWeight) { + uint64_t Weights[2] = {BBTWeight * BB1FWeight + BBFWeight * BB2TWeight, + BBTWeight * BB1TWeight + BBFWeight * BB2FWeight}; + FitWeights(Weights); + setBranchWeights(BI, Weights[0], Weights[1], /*IsExpected=*/false); + } + return true; +} + bool SimplifyCFGOpt::simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) { assert( !isa<ConstantInt>(BI->getCondition()) && @@ -7468,6 +7557,10 @@ bool SimplifyCFGOpt::simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) { if (mergeConditionalStores(PBI, BI, DTU, DL, TTI)) return requestResimplify(); + // Look for nested conditional branches. + if (mergeNestedCondBranch(BI, DTU)) + return requestResimplify(); + return false; } |