@@ -7437,28 +7437,39 @@ static bool simplifySwitchOfCmpIntrinsic(SwitchInst *SI, IRBuilderBase &Builder,
74377437 return true ;
74387438}
74397439
7440+ // / Checking whether two CaseHandle.getCaseSuccessor() are equal depends on
7441+ // / the incoming values of their successor PHINodes.
7442+ // / PHINode::getIncomingValueForBlock has O(|Preds|), so we'd like to avoid
7443+ // / calling this function on each BasicBlock every time isEqual is called,
7444+ // / especially since the same BasicBlock may be passed as an argument multiple
7445+ // / times. To do this, we can precompute a map of PHINode -> Pred BasicBlock ->
7446+ // / IncomingValue and add it in the Wrapper so isEqual can do O(1) checking
7447+ // / of the incoming values.
7448+ struct CaseHandleWrapper {
7449+ const SwitchInst::CaseHandle Case;
7450+ DenseMap<PHINode *, DenseMap<BasicBlock *, Value *>> &PhiPredIVs;
7451+ };
7452+
74407453namespace llvm {
7441- template <> struct DenseMapInfo <const SwitchInst::CaseHandle *> {
7442- static const SwitchInst::CaseHandle *getEmptyKey () {
7443- return reinterpret_cast <const SwitchInst::CaseHandle *>(
7454+ template <> struct DenseMapInfo <const CaseHandleWrapper *> {
7455+ static const CaseHandleWrapper *getEmptyKey () {
7456+ return reinterpret_cast <CaseHandleWrapper *>(
74447457 DenseMapInfo<void *>::getEmptyKey ());
74457458 }
7446- static const SwitchInst::CaseHandle *getTombstoneKey () {
7447- return reinterpret_cast <const SwitchInst::CaseHandle *>(
7459+ static const CaseHandleWrapper *getTombstoneKey () {
7460+ return reinterpret_cast <CaseHandleWrapper *>(
74487461 DenseMapInfo<void *>::getTombstoneKey ());
74497462 }
7450- static unsigned getHashValue (const SwitchInst::CaseHandle *Case ) {
7451- BasicBlock *Succ = Case-> getCaseSuccessor ();
7463+ static unsigned getHashValue (const CaseHandleWrapper *CT ) {
7464+ BasicBlock *Succ = CT-> Case . getCaseSuccessor ();
74527465 BranchInst *BI = cast<BranchInst>(Succ->getTerminator ());
7453-
74547466 auto It = BI->successors ();
74557467 return hash_combine (Succ->size (), hash_combine_range (It.begin (), It.end ()));
74567468 }
7457- static bool isEqual (const SwitchInst::CaseHandle *LHS,
7458- const SwitchInst::CaseHandle *RHS) {
7459-
7460- auto EKey = DenseMapInfo<const SwitchInst::CaseHandle *>::getEmptyKey ();
7461- auto TKey = DenseMapInfo<const SwitchInst::CaseHandle *>::getTombstoneKey ();
7469+ static bool isEqual (const CaseHandleWrapper *LHS,
7470+ const CaseHandleWrapper *RHS) {
7471+ auto EKey = DenseMapInfo<CaseHandleWrapper *>::getEmptyKey ();
7472+ auto TKey = DenseMapInfo<CaseHandleWrapper *>::getTombstoneKey ();
74627473 if (LHS == EKey || RHS == EKey || LHS == TKey || RHS == TKey)
74637474 return LHS == RHS;
74647475
@@ -7490,49 +7501,38 @@ template <> struct DenseMapInfo<const SwitchInst::CaseHandle *> {
74907501 return true ;
74917502 };
74927503
7493- auto IsBBEq = [&IsBranchEq](BasicBlock *A, BasicBlock *B) {
7494- // FIXME: we checked that the size of A and B are both 1 in
7495- // simplifyDuplicateSwitchArms to make the Case list smaller to improve
7496- // performance. If we decide to support BasicBlocks with more than just a
7497- // single instruction, we need to check that A.size() == B.size() here.
7498-
7499- if (!IsBranchEq (cast<BranchInst>(A->getTerminator ()),
7500- cast<BranchInst>(B->getTerminator ())))
7501- return false ;
7502-
7503- // Need to check that PHIs in sucessors have matching values
7504- for (auto *Succ : cast<BranchInst>(A->getTerminator ())->successors ())
7505- for (PHINode &Phi : Succ->phis ())
7506- if (Phi.getIncomingValueForBlock (A) !=
7507- Phi.getIncomingValueForBlock (B))
7504+ auto IsBBEq =
7505+ [&IsBranchEq](
7506+ BasicBlock *A, BasicBlock *B,
7507+ DenseMap<PHINode *, DenseMap<BasicBlock *, Value *>> &PhiPredIVs) {
7508+ // FIXME: we checked that the size of A and B are both 1 in
7509+ // simplifyDuplicateSwitchArms to make the Case list smaller to
7510+ // improve performance. If we decide to support BasicBlocks with more
7511+ // than just a single instruction, we need to check that A.size() ==
7512+ // B.size() here.
7513+
7514+ if (!IsBranchEq (cast<BranchInst>(A->getTerminator ()),
7515+ cast<BranchInst>(B->getTerminator ())))
75087516 return false ;
75097517
7510- return true ;
7511- };
7518+ // Need to check that PHIs in sucessors have matching values
7519+ for (auto *Succ : cast<BranchInst>(A->getTerminator ())->successors ())
7520+ for (PHINode &Phi : Succ->phis ())
7521+ if (PhiPredIVs[&Phi][A] != PhiPredIVs[&Phi][B])
7522+ return false ;
75127523
7513- return IsBBEq (LHS->getCaseSuccessor (), RHS->getCaseSuccessor ());
7524+ return true ;
7525+ };
7526+
7527+ return IsBBEq (LHS->Case .getCaseSuccessor (), RHS->Case .getCaseSuccessor (),
7528+ LHS->PhiPredIVs );
75147529 }
75157530};
75167531} // namespace llvm
75177532
75187533bool SimplifyCFGOpt::simplifyDuplicateSwitchArms (SwitchInst *SI) {
7519- // Build a map where the key is the CaseHandle that contains the successor
7520- // BasicBlock to replace all CaseHandle successor BasicBlocks in the value
7521- // list. We use a custom DenseMapInfo to build this map in O(size(cases()).
7522- // We use CaseHandle instead of BasicBlock since it allows us to do the
7523- // replacement in O(size(cases)). If we had used BasicBlock, then to do the
7524- // actual replacement, we'd need an additional nested loop to loop over all
7525- // CaseHandle since there is no O(1) lookup of BasicBlock -> Cases.
7526- DenseSet<const SwitchInst::CaseHandle *,
7527- DenseMapInfo<const SwitchInst::CaseHandle *>>
7528- ReplaceWith;
7529-
7530- // We'd like to use CaseHandle* for our set because it is easier to write
7531- // getEmptyKey and getTombstoneKey for CaseHandle* than it is for CaseHandle.
7532- // We need to take ownership though, since SI->cases() makes no guarantee that
7533- // the CaseHandle is still allocated on every iteration. We can skip over
7534- // cases we know we won't consider for replacement.
7535- SmallVector<SwitchInst::CaseHandle> Cases;
7534+ DenseMap<PHINode *, DenseMap<BasicBlock *, Value *>> PhiPredIVs;
7535+ SmallVector<CaseHandleWrapper> Cases;
75367536 for (auto Case : SI->cases ()) {
75377537 BasicBlock *BB = Case.getCaseSuccessor ();
75387538 // Skip BBs that are not candidates for simplification.
@@ -7552,19 +7552,41 @@ bool SimplifyCFGOpt::simplifyDuplicateSwitchArms(SwitchInst *SI) {
75527552 if (!T || !isa<BranchInst>(T))
75537553 continue ;
75547554
7555- Cases.emplace_back (Case);
7555+ // Preprocess incoming PHI values for successors of BB.
7556+ for (BasicBlock *Succ : cast<BranchInst>(T)->successors ()) {
7557+ for (PHINode &Phi : Succ->phis ()) {
7558+ auto IncomingVals = PhiPredIVs.find (&Phi);
7559+ Value *Incoming = Phi.getIncomingValueForBlock (BB);
7560+ if (IncomingVals != PhiPredIVs.end ())
7561+ IncomingVals->second .insert ({BB, Incoming});
7562+ else
7563+ PhiPredIVs[&Phi] = {{BB, Incoming}};
7564+ }
7565+ }
7566+
7567+ Cases.emplace_back (CaseHandleWrapper{Case, PhiPredIVs});
75567568 }
75577569
7570+ // Build a set such that if the CaseHandleWrapper exists in the set and
7571+ // another CaseHandleWrapper isEqual, then the equivalent CaseHandleWrapper
7572+ // which is not in the set should be replaced with the one in the set. If the
7573+ // CaseHandleWrapper is not in the set, then it should be added to the set so
7574+ // other CaseHandleWrappers can check against it in the same manner. We chose
7575+ // to use CaseHandleWrapper instead of BasicBlock since we'd need an extra
7576+ // nested loop since there is no O(1) lookup of BasicBlock -> Cases in
7577+ // SwichInst.
7578+ DenseSet<const CaseHandleWrapper *, DenseMapInfo<const CaseHandleWrapper *>>
7579+ ReplaceWith;
75587580 bool MadeChange = false ;
7559- for (auto &Case : Cases) {
7560- // Case is a candidate for simplification. If we find a duplicate BB,
7581+ for (auto &CHW : Cases) {
7582+ // CHW is a candidate for simplification. If we find a duplicate BB,
75617583 // replace it.
7562- const auto Res = ReplaceWith.find (&Case );
7584+ const auto Res = ReplaceWith.find (&CHW );
75637585 if (Res != ReplaceWith.end ()) {
7564- Case.setSuccessor ((*Res)->getCaseSuccessor ());
7586+ CHW. Case .setSuccessor ((*Res)->Case . getCaseSuccessor ());
75657587 MadeChange = true ;
75667588 } else {
7567- ReplaceWith.insert (&Case );
7589+ ReplaceWith.insert (&CHW );
75687590 }
75697591 }
75707592
0 commit comments