[llvm] [SimplifyCFG] Simplify switch instruction that has duplicate arms (PR #114262)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 30 13:28:41 PDT 2024
================
@@ -7436,6 +7437,110 @@ static bool simplifySwitchOfCmpIntrinsic(SwitchInst *SI, IRBuilderBase &Builder,
return true;
}
+bool SimplifyCFGOpt::simplifyDuplicateSwitchArms(SwitchInst *SI) {
+ // Simplify the case where multiple arms contain only a terminator, the
+ // terminators are the same, and their sucessor PHIS incoming values are the
+ // same.
+
+ // Find BBs that are candidates for simplification.
+ SmallPtrSet<BasicBlock *, 8> BBs;
+ for (auto &Case : SI->cases()) {
+ BasicBlock *BB = Case.getCaseSuccessor();
+
+ // FIXME: This case needs some extra care because the terminators other than
+ // SI need to be updated.
+ if (!BB->hasNPredecessors(1))
+ continue;
+
+ // FIXME: Relax that the terminator is a BranchInst by checking for equality
+ // on other kinds of terminators.
+ Instruction *T = BB->getTerminator();
+ if (T && isa<BranchInst>(T))
+ BBs.insert(BB);
+ }
+
+ auto IsBranchEq = [](BranchInst *A, BranchInst *B) {
+ if (A->isConditional() != B->isConditional())
+ return false;
+
+ if (A->isConditional()) {
+ // If the conditions are instructions, check equality up to commutativity.
+ // Otherwise, check that the two Values are the same.
+ Value *AC = A->getCondition();
+ Value *BC = B->getCondition();
+ auto *ACI = dyn_cast<Instruction>(AC);
+ auto *BCI = dyn_cast<Instruction>(BC);
+ if ((ACI && BCI && !areIdenticalUpToCommutativity(ACI, BCI)) && AC != BC)
+ return false;
+ }
+
+ if (A->getNumSuccessors() != B->getNumSuccessors())
+ return false;
+
+ for (unsigned I = 0; I < A->getNumSuccessors(); ++I) {
+ BasicBlock *ASucc = A->getSuccessor(I);
+ if (ASucc != B->getSuccessor(I))
+ return false;
+ // Need to check that PHIs in sucessors have matching values
+ for (PHINode &Phi : ASucc->phis())
+ if (Phi.getIncomingValueForBlock(A->getParent()) !=
+ Phi.getIncomingValueForBlock(B->getParent()))
+ return false;
+ }
+
+ return true;
+ };
+
+ auto IsBBEqualTo = [&IsBranchEq](BasicBlock *A, BasicBlock *B) {
+ // FIXME: Support more than just a single BranchInst. One way we could do
+ // this is by taking a hashing approach.
+ if (A->size() != 1 || B->size() != 1)
+ return false;
+
+ return IsBranchEq(cast<BranchInst>(A->getTerminator()),
+ cast<BranchInst>(B->getTerminator()));
+ };
+
+ // Construct a map from candidate basic block to an equivalent basic block
+ // to replace it with. All equivalent basic blocks should be replaced with
+ // the same basic block. To do this, if there is no equivalent BB in the map,
+ // then insert into the map BB -> BB. Otherwise, we should check only elements
+ // in the map for equivalence to ensure that all equivalent BB get replaced
+ // by the BB in the map. Replacing BB with BB has no impact, so we skip
+ // a call to setSuccessor when we do the actual replacement.
+ DenseMap<BasicBlock *, BasicBlock *> ReplaceWith;
+ for (BasicBlock *BB : BBs) {
+ bool Inserted = false;
+ for (auto KV : ReplaceWith) {
+ if (IsBBEqualTo(BB, KV.first)) {
+ ReplaceWith[BB] = KV.first;
+ Inserted = true;
+ break;
+ }
+ }
+ if (!Inserted)
+ ReplaceWith[BB] = BB;
+ }
----------------
goldsteinn wrote:
I think the way to implement this is with `DenseMap<BasicBlock *, SmallVector<BasicBlock *>>`. If a given BB is not in `ReplaceWith`, you add it w/ empty list. If it is, add to list of existing entry. You then iterate over all key BBs in `ReplaceWith` and replace all items in the `SmallVector` with the key BB.
In this case your hash function can just be zero (or maybe `BB->size()`) and `isBBEqualTo` is your equals function.
https://github.com/llvm/llvm-project/pull/114262
More information about the llvm-commits
mailing list