aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
diff options
context:
space:
mode:
authorYingwei Zheng <dtcxzyw2333@gmail.com>2024-07-01 03:35:39 +0800
committerGitHub <noreply@github.com>2024-07-01 03:35:39 +0800
commit4997af98a008e71a3df61707559710d1c2769839 (patch)
tree4a67444eec67ef4dac3a70926ed04279e2212e24 /llvm/lib/Transforms/Utils/SimplifyCFG.cpp
parent3efac5c68ac3117e8488a7fa247e45951e52936f (diff)
downloadllvm-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.cpp93
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;
}