Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 39 additions & 23 deletions llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,22 +386,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const PathType &Path) {
return OS;
}

/// Helper to get the successor corresponding to a particular case value for
/// a switch statement.
static BasicBlock *getNextCaseSuccessor(SwitchInst *Switch,
const APInt &NextState) {
BasicBlock *NextCase = nullptr;
for (auto Case : Switch->cases()) {
if (Case.getCaseValue()->getValue() == NextState) {
NextCase = Case.getCaseSuccessor();
break;
}
}
if (!NextCase)
NextCase = Switch->getDefaultDest();
return NextCase;
}

namespace {
/// ThreadingPath is a path in the control flow of a loop that can be threaded
/// by cloning necessary basic blocks and replacing conditional branches with
Expand Down Expand Up @@ -835,19 +819,32 @@ struct AllSwitchPaths {
TPaths = std::move(TempList);
}

/// Fast helper to get the successor corresponding to a particular case value
/// for a switch statement.
BasicBlock *getNextCaseSuccessor(const APInt &NextState) {
// Precompute the value => successor mapping
if (CaseValToDest.empty()) {
for (auto Case : Switch->cases()) {
APInt CaseVal = Case.getCaseValue()->getValue();
CaseValToDest[CaseVal] = Case.getCaseSuccessor();
}
}

auto SuccIt = CaseValToDest.find(NextState);
return SuccIt == CaseValToDest.end() ? Switch->getDefaultDest()
: SuccIt->second;
}

// Two states are equivalent if they have the same switch destination.
// Unify the states in different threading path if the states are equivalent.
void unifyTPaths() {
llvm::SmallDenseMap<BasicBlock *, APInt> DestToState;
SmallDenseMap<BasicBlock *, APInt> DestToState;
for (ThreadingPath &Path : TPaths) {
APInt NextState = Path.getExitValue();
BasicBlock *Dest = getNextCaseSuccessor(Switch, NextState);
auto StateIt = DestToState.find(Dest);
if (StateIt == DestToState.end()) {
DestToState.insert({Dest, NextState});
BasicBlock *Dest = getNextCaseSuccessor(NextState);
auto [StateIt, Inserted] = DestToState.try_emplace(Dest, NextState);
if (Inserted)
continue;
}

if (NextState != StateIt->second) {
LLVM_DEBUG(dbgs() << "Next state in " << Path << " is equivalent to "
<< StateIt->second << "\n");
Expand All @@ -861,6 +858,7 @@ struct AllSwitchPaths {
BasicBlock *SwitchBlock;
OptimizationRemarkEmitter *ORE;
std::vector<ThreadingPath> TPaths;
DenseMap<APInt, BasicBlock *> CaseValToDest;
LoopInfo *LI;
Loop *SwitchOuterLoop;
};
Expand Down Expand Up @@ -1162,6 +1160,24 @@ struct TransformDFA {
SSAUpdate.RewriteAllUses(&DTU->getDomTree());
}

/// Helper to get the successor corresponding to a particular case value for
/// a switch statement.
/// TODO: Unify it with SwitchPaths->getNextCaseSuccessor(SwitchInst *Switch)
/// by updating cached value => successor mapping during threading.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, the need for a second copy is unfortunate...

static BasicBlock *getNextCaseSuccessor(SwitchInst *Switch,
const APInt &NextState) {
BasicBlock *NextCase = nullptr;
for (auto Case : Switch->cases()) {
if (Case.getCaseValue()->getValue() == NextState) {
NextCase = Case.getCaseSuccessor();
break;
}
}
if (!NextCase)
NextCase = Switch->getDefaultDest();
return NextCase;
}

/// Clones a basic block, and adds it to the CFG.
///
/// This function also includes updating phi nodes in the successors of the
Expand Down