Fix a crash when the default of a switch is removed

This patch fixes a problem that occurs in LowerSwitch when a switch statement has a PHI node as its condition, and the PHI node only has two incoming blocks, and one of those incoming blocks is through an unreachable default in the switch statement. When this condition occurs, LowerSwitch holds a pointer to the condition value, but removes the switch block as a predecessor of the PHI block, causing the PHI node to be replaced. LowerSwitch then tries to use its stale pointer to the original condition value, causing a crash.

Differential Revision: https://reviews.llvm.org/D62560

llvm-svn: 362427
This commit is contained in:
Andrew Kaylor 2019-06-03 17:54:15 +00:00
parent 83645d214d
commit 4172dbab5d
2 changed files with 41 additions and 0 deletions

View File

@ -584,6 +584,11 @@ void LowerSwitch::processSwitchInst(SwitchInst *SI,
PopSucc->removePredecessor(OrigBlock);
return;
}
// If the condition was a PHI node with the switch block as a predecessor
// removing predecessors may have caused the condition to be erased.
// Getting the condition value again here protects against that.
Val = SI->getCondition();
}
// Create a new, empty default block so that the new hierarchy of

View File

@ -0,0 +1,36 @@
; RUN: opt < %s -lowerswitch -S | FileCheck %s
; This test verifies -lowerswitch does not crash when an removing an
; unreachable default branch causes a PHI node used as the switch
; condition to be erased.
define void @f() local_unnamed_addr {
entry:
br label %sw.epilog
sw.epilog: ; preds = %sw.epilog.outer, %for.body
%i = phi i32 [ undef, %for.body ], [ 0, %entry ]
br i1 undef, label %for.body, label %for.end
for.body: ; preds = %sw.epilog
switch i32 %i, label %sw.epilog [
i32 0, label %sw.epilog.outer.backedge.loopexit
i32 1, label %sw.epilog.outer.backedge
]
sw.epilog.outer.backedge.loopexit: ; preds = %for.body
br label %for.end
sw.epilog.outer.backedge: ; preds = %for.body
unreachable
for.end: ; preds = %sw.epilog
ret void
}
; The phi and the switch should both be eliminated.
; CHECK: @f()
; CHECK: sw.epilog:
; CHECK-NOT: phi
; CHECK: for.body:
; CHECK-NOT: switch