Skip to content

Commit c8eecb6

Browse files
fixup! make it O(n)
1 parent 64ddee6 commit c8eecb6

File tree

1 file changed

+102
-84
lines changed

1 file changed

+102
-84
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 102 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -7437,106 +7437,124 @@ static bool simplifySwitchOfCmpIntrinsic(SwitchInst *SI, IRBuilderBase &Builder,
74377437
return true;
74387438
}
74397439

7440-
bool SimplifyCFGOpt::simplifyDuplicateSwitchArms(SwitchInst *SI) {
7441-
// Simplify the case where multiple arms contain only a terminator, the
7442-
// terminators are the same, and their sucessor PHIS incoming values are the
7443-
// same.
7444-
7445-
// Find BBs that are candidates for simplification.
7446-
SmallPtrSet<BasicBlock *, 8> BBs;
7447-
for (auto &Case : SI->cases()) {
7448-
BasicBlock *BB = Case.getCaseSuccessor();
7449-
7450-
// FIXME: This case needs some extra care because the terminators other than
7451-
// SI need to be updated.
7452-
if (!BB->hasNPredecessors(1))
7453-
continue;
7440+
namespace llvm {
7441+
template <> struct DenseMapInfo<const SwitchInst::CaseHandle *> {
7442+
static const SwitchInst::CaseHandle *getEmptyKey() {
7443+
return reinterpret_cast<const SwitchInst::CaseHandle *>(
7444+
DenseMapInfo<void *>::getEmptyKey());
7445+
}
7446+
static const SwitchInst::CaseHandle *getTombstoneKey() {
7447+
return reinterpret_cast<const SwitchInst::CaseHandle *>(
7448+
DenseMapInfo<void *>::getTombstoneKey());
7449+
}
7450+
static unsigned getHashValue(const SwitchInst::CaseHandle *Case) {
7451+
BasicBlock *Succ = Case->getCaseSuccessor();
7452+
return hash_combine(Succ->size(), Succ->getTerminator()->getOpcode());
7453+
}
7454+
static bool isEqual(const SwitchInst::CaseHandle *LHS,
7455+
const SwitchInst::CaseHandle *RHS) {
7456+
7457+
auto EKey = DenseMapInfo<const SwitchInst::CaseHandle *>::getEmptyKey();
7458+
auto TKey = DenseMapInfo<const SwitchInst::CaseHandle *>::getTombstoneKey();
7459+
if (LHS == EKey || RHS == EKey || LHS == TKey || RHS == TKey)
7460+
return LHS == RHS;
7461+
7462+
auto IsBranchEq = [](BranchInst *A, BranchInst *B) {
7463+
if (A->isConditional() != B->isConditional())
7464+
return false;
74547465

7455-
// FIXME: Relax that the terminator is a BranchInst by checking for equality
7456-
// on other kinds of terminators.
7457-
Instruction *T = BB->getTerminator();
7458-
if (T && isa<BranchInst>(T))
7459-
BBs.insert(BB);
7460-
}
7466+
if (A->isConditional()) {
7467+
// If the conditions are instructions, check equality up to
7468+
// commutativity. Otherwise, check that the two Values are the same.
7469+
Value *AC = A->getCondition();
7470+
Value *BC = B->getCondition();
7471+
auto *ACI = dyn_cast<Instruction>(AC);
7472+
auto *BCI = dyn_cast<Instruction>(BC);
74617473

7462-
auto IsBranchEq = [](BranchInst *A, BranchInst *B) {
7463-
if (A->isConditional() != B->isConditional())
7464-
return false;
7474+
if (ACI && BCI && !areIdenticalUpToCommutativity(ACI, BCI))
7475+
return false;
7476+
if ((!ACI || !BCI) && AC != BC)
7477+
return false;
7478+
}
74657479

7466-
if (A->isConditional()) {
7467-
// If the conditions are instructions, check equality up to commutativity.
7468-
// Otherwise, check that the two Values are the same.
7469-
Value *AC = A->getCondition();
7470-
Value *BC = B->getCondition();
7471-
auto *ACI = dyn_cast<Instruction>(AC);
7472-
auto *BCI = dyn_cast<Instruction>(BC);
7473-
if ((ACI && BCI && !areIdenticalUpToCommutativity(ACI, BCI)) && AC != BC)
7480+
if (A->getNumSuccessors() != B->getNumSuccessors())
74747481
return false;
7475-
}
74767482

7477-
if (A->getNumSuccessors() != B->getNumSuccessors())
7478-
return false;
7483+
for (unsigned I = 0; I < A->getNumSuccessors(); ++I)
7484+
if (A->getSuccessor(I) != B->getSuccessor(I))
7485+
return false;
74797486

7480-
for (unsigned I = 0; I < A->getNumSuccessors(); ++I)
7481-
if (A->getSuccessor(I) != B->getSuccessor(I))
7482-
return false;
7487+
return true;
7488+
};
74837489

7484-
return true;
7485-
};
7490+
auto IsBBEq = [&IsBranchEq](BasicBlock *A, BasicBlock *B) {
7491+
// FIXME: Support more than just a single BranchInst. One way we could do
7492+
// this is by taking a hashing approach.
7493+
if (A->size() != 1 || B->size() != 1)
7494+
return false;
74867495

7487-
auto IsBBEqualTo = [&IsBranchEq](BasicBlock *A, BasicBlock *B) {
7488-
// FIXME: Support more than just a single BranchInst. One way we could do
7489-
// this is by taking a hashing approach.
7490-
if (A->size() != 1 || B->size() != 1)
7491-
return false;
7496+
if (!IsBranchEq(cast<BranchInst>(A->getTerminator()),
7497+
cast<BranchInst>(B->getTerminator())))
7498+
return false;
74927499

7493-
if (!IsBranchEq(cast<BranchInst>(A->getTerminator()),
7494-
cast<BranchInst>(B->getTerminator())))
7495-
return false;
7500+
// Need to check that PHIs in sucessors have matching values
7501+
for (auto *Succ : cast<BranchInst>(A->getTerminator())->successors())
7502+
for (PHINode &Phi : Succ->phis())
7503+
if (Phi.getIncomingValueForBlock(A) !=
7504+
Phi.getIncomingValueForBlock(B))
7505+
return false;
74967506

7497-
// Need to check that PHIs in sucessors have matching values
7498-
for (auto *Succ : cast<BranchInst>(A->getTerminator())->successors())
7499-
for (PHINode &Phi : Succ->phis())
7500-
if (Phi.getIncomingValueForBlock(A) != Phi.getIncomingValueForBlock(B))
7501-
return false;
7507+
return true;
7508+
};
75027509

7503-
return true;
7504-
};
7510+
return IsBBEq(LHS->getCaseSuccessor(), RHS->getCaseSuccessor());
7511+
}
7512+
};
7513+
} // namespace llvm
75057514

7506-
// Construct a map from candidate basic block to an equivalent basic block
7507-
// to replace it with. All equivalent basic blocks should be replaced with
7508-
// the same basic block. To do this, if there is no equivalent BB in the map,
7509-
// then insert into the map BB -> BB. Otherwise, we should check only elements
7510-
// in the map for equivalence to ensure that all equivalent BB get replaced
7511-
// by the BB in the map. Replacing BB with BB has no impact, so we skip
7512-
// a call to setSuccessor when we do the actual replacement.
7513-
DenseMap<BasicBlock *, BasicBlock *> ReplaceWith;
7514-
for (BasicBlock *BB : BBs) {
7515-
bool Inserted = false;
7516-
for (auto KV : ReplaceWith) {
7517-
if (IsBBEqualTo(BB, KV.first)) {
7518-
ReplaceWith[BB] = KV.first;
7519-
Inserted = true;
7520-
break;
7521-
}
7522-
}
7523-
if (!Inserted)
7524-
ReplaceWith[BB] = BB;
7515+
bool SimplifyCFGOpt::simplifyDuplicateSwitchArms(SwitchInst *SI) {
7516+
// Build a map where the key is the CaseHandle that contains the successor
7517+
// BasicBlock to replace all CaseHandle successor BasicBlocks in the value
7518+
// list. We use a custom DenseMapInfo to build this map in O(size(cases()).
7519+
// We use CaseHandle instead of BasicBlock since it allows us to do the
7520+
// replacement in O(size(cases)). If we had used BasicBlock, then to do the
7521+
// actual replacement, we'd need an additional nested loop to loop over all
7522+
// CaseHandle since there is no O(1) lookup of BasicBlock -> Cases.
7523+
DenseSet<const SwitchInst::CaseHandle *,
7524+
DenseMapInfo<const SwitchInst::CaseHandle *>>
7525+
ReplaceWith;
7526+
7527+
// We'd like to use CaseHandle* for our set because it is easier to write
7528+
// getEmptyKey and getTombstoneKey for CaseHandle* than it is for CaseHandle.
7529+
// We need to take ownership though, since SI->cases() makes no guarantee that
7530+
// the CaseHandle is still allocated on every iteration. We can skip over
7531+
// cases we know we won't consider for replacement.
7532+
SmallVector<SwitchInst::CaseHandle> Cases;
7533+
for (auto Case : SI->cases()) {
7534+
BasicBlock *BB = Case.getCaseSuccessor();
7535+
// Skip BBs that are not candidates for simplification.
7536+
// FIXME: This case needs some extra care because the terminators other than
7537+
// SI need to be updated.
7538+
if (!BB->hasNPredecessors(1))
7539+
continue;
7540+
// FIXME: Relax that the terminator is a BranchInst by checking for equality
7541+
// on other kinds of terminators.
7542+
Instruction *T = BB->getTerminator();
7543+
if (!T || !isa<BranchInst>(T))
7544+
continue;
7545+
Cases.emplace_back(Case);
75257546
}
75267547

7527-
// Do the replacement in SI.
75287548
bool MadeChange = false;
7529-
// There is no fast lookup of BasicBlock -> Cases, so we iterate over cases
7530-
// and check that the case was a candidate. BBs is already filtered, so
7531-
// hopefully calling contains on it is not too expensive.
7532-
for (auto &Case : SI->cases()) {
7533-
BasicBlock *OldSucc = Case.getCaseSuccessor();
7534-
if (!BBs.contains(OldSucc))
7535-
continue;
7536-
BasicBlock *NewSucc = ReplaceWith[OldSucc];
7537-
if (OldSucc != NewSucc) {
7538-
Case.setSuccessor(NewSucc);
7549+
for (auto &Case : Cases) {
7550+
// Case is a candidate for simplification. If we find a duplicate BB,
7551+
// replace it.
7552+
const auto Res = ReplaceWith.find(&Case);
7553+
if (Res != ReplaceWith.end()) {
7554+
Case.setSuccessor((*Res)->getCaseSuccessor());
75397555
MadeChange = true;
7556+
} else {
7557+
ReplaceWith.insert(&Case);
75407558
}
75417559
}
75427560

0 commit comments

Comments
 (0)