@@ -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