llvm.org GIT mirror llvm / a018025
[LowerSwitch] Fix a bug when LowerSwitch deletes the default block Summary: LowerSwitch crashed with the attached test case after deleting the default block. This happened because the current implementation of deleting dead blocks is wrong. After the default block being deleted, it contains no instruction or terminator, and it should no be traversed anymore. However, since the iterator is advanced before processSwitchInst() function is executed, the block advanced to could be deleted inside processSwitchInst(). The deleted block would then be visited next and crash dyn_cast<SwitchInst>(Cur->getTerminator()) because Cur->getTerminator() returns a nullptr. This patch fixes this problem by recording dead default blocks into a list, and delete them after all processSwitchInst() has been done. It still possible to visit dead default blocks and waste time process them. But it is a compile time issue, and I plan to have another patch to add support to skip dead blocks. Reviewers: kariddi, resistor, hans, reames Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D11852 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244642 91177308-0d34-0410-b5e6-96231b3b80d8 Chen Li 4 years ago
2 changed file(s) with 39 addition(s) and 7 deletion(s). Raw diff Collapse all Expand all
7777 typedef std::vector CaseVector;
7878 typedef std::vector::iterator CaseItr;
7979 private:
80 void processSwitchInst(SwitchInst *SI);
80 void processSwitchInst(SwitchInst *SI, SmallVectorImpl &DeleteList);
8181
8282 BasicBlock *switchConvert(CaseItr Begin, CaseItr End,
8383 ConstantInt *LowerBound, ConstantInt *UpperBound,
115115
116116 bool LowerSwitch::runOnFunction(Function &F) {
117117 bool Changed = false;
118 SmallVector DeleteList;
118119
119120 for (Function::iterator I = F.begin(), E = F.end(); I != E; ) {
120121 BasicBlock *Cur = I++; // Advance over block so we don't traverse new blocks
121122
122123 if (SwitchInst *SI = dyn_cast(Cur->getTerminator())) {
123124 Changed = true;
124 processSwitchInst(SI);
125 }
125 processSwitchInst(SI, DeleteList);
126 }
127 }
128
129 for (BasicBlock* BB: DeleteList) {
130 DeleteDeadBlock(BB);
126131 }
127132
128133 return Changed;
396401 // processSwitchInst - Replace the specified switch instruction with a sequence
397402 // of chained if-then insts in a balanced binary search.
398403 //
399 void LowerSwitch::processSwitchInst(SwitchInst *SI) {
404 void LowerSwitch::processSwitchInst(SwitchInst *SI, SmallVectorImpl &DeleteList) {
400405 BasicBlock *CurBlock = SI->getParent();
401406 BasicBlock *OrigBlock = CurBlock;
402407 Function *F = CurBlock->getParent();
517522 BasicBlock *OldDefault = SI->getDefaultDest();
518523 CurBlock->getInstList().erase(SI);
519524
520 // If the Default block has no more predecessors just remove it.
525 // If the Default block has no more predecessors just add it to DeleteList.
521526 if (pred_begin(OldDefault) == pred_end(OldDefault))
522 DeleteDeadBlock(OldDefault);
523 }
527 DeleteList.push_back(OldDefault);
528 }
0 ; RUN: opt < %s -lowerswitch -disable-output
1
2 ; This test verify -lowerswitch does not crash after deleting the default block.
3
4 declare i32 @f(i32)
5
6 define i32 @unreachable(i32 %x) {
7
8 entry:
9 switch i32 %x, label %unreachable [
10 i32 5, label %a
11 i32 6, label %a
12 i32 7, label %a
13 i32 10, label %b
14 i32 20, label %b
15 i32 30, label %b
16 i32 40, label %b
17 ]
18 unreachable:
19 unreachable
20 a:
21 %0 = call i32 @f(i32 0)
22 ret i32 %0
23 b:
24 %1 = call i32 @f(i32 1)
25 ret i32 %1
26 }