Skip to content

Commit 32b627f

Browse files
fixup! precompute getIncomingValueForBlock
1 parent 794d4e8 commit 32b627f

File tree

1 file changed

+76
-54
lines changed

1 file changed

+76
-54
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 76 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
74407453
namespace 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

75187533
bool 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

Comments
 (0)