SelectionDAG switch lowering: Replace unreachable default with most popular case.

This can significantly reduce the size of the switch, allowing for more
efficient lowering.

I also worked with the idea of exploiting unreachable defaults by
omitting the range check for jump tables, but always ended up with a
non-neglible binary size increase. It might be worth looking into some more.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@223049 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Hans Wennborg
2014-12-01 17:08:32 +00:00
parent d9788e9372
commit e6f4d335d7
4 changed files with 100 additions and 23 deletions
@@ -2695,32 +2695,57 @@ void SelectionDAGBuilder::visitSwitch(const SwitchInst &SI) {
if (SwitchMBB + 1 != FuncInfo.MF->end())
NextBlock = SwitchMBB + 1;
// Create a vector of Cases, sorted so that we can efficiently create a binary
// search tree from them.
CaseVector Cases;
Clusterify(Cases, SI);
// Get the default destination MBB.
MachineBasicBlock *Default = FuncInfo.MBBMap[SI.getDefaultDest()];
// If there is only the default destination, branch to it if it is not the
// next basic block. Otherwise, just fall through.
if (!SI.getNumCases()) {
if (isa<UnreachableInst>(SI.getDefaultDest()->getFirstNonPHIOrDbg())) {
// Replace an unreachable default destination with the most popular case
// destination.
DenseMap<const BasicBlock*, uint64_t> Popularity;
uint64_t MaxPop = 0;
const BasicBlock *MaxBB = nullptr;
for (auto I : SI.cases()) {
const BasicBlock *BB = I.getCaseSuccessor();
if (++Popularity[BB] > MaxPop) {
MaxPop = Popularity[BB];
MaxBB = BB;
}
}
// Set new default.
Default = FuncInfo.MBBMap[MaxBB];
// Remove cases that have been replaced by the default.
CaseItr I = Cases.begin();
while (I != Cases.end()) {
if (I->BB == Default) {
I = Cases.erase(I);
continue;
}
++I;
}
}
// If there is only the default destination, go there directly.
if (Cases.empty()) {
// Update machine-CFG edges.
SwitchMBB->addSuccessor(Default);
// If this is not a fall-through branch, emit the branch.
if (Default != NextBlock)
DAG.setRoot(DAG.getNode(ISD::BR, getCurSDLoc(),
MVT::Other, getControlRoot(),
DAG.getBasicBlock(Default)));
if (Default != NextBlock) {
DAG.setRoot(DAG.getNode(ISD::BR, getCurSDLoc(), MVT::Other,
getControlRoot(), DAG.getBasicBlock(Default)));
}
return;
}
// If there are any non-default case statements, create a vector of Cases
// representing each one, and sort the vector so that we can efficiently
// create a binary search tree from them.
CaseVector Cases;
Clusterify(Cases, SI);
// Get the Value to be switched on and default basic blocks, which will be
// inserted into CaseBlock records, representing basic blocks in the binary
// search tree.
// Get the Value to be switched on.
const Value *SV = SI.getCondition();
// Push the initial CaseRec onto the worklist