[llvm] 073b254 - [SimplifyCFG] Redirect switch cases that lead to UB into an unreachable block
Max Kazantsev via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 20 20:45:40 PDT 2021
Author: Max Kazantsev
Date: 2021-09-21T10:45:19+07:00
New Revision: 073b254cffeffdef36ffbee0c9afdc0da9cd6ac3
URL: https://github.com/llvm/llvm-project/commit/073b254cffeffdef36ffbee0c9afdc0da9cd6ac3
DIFF: https://github.com/llvm/llvm-project/commit/073b254cffeffdef36ffbee0c9afdc0da9cd6ac3.diff
LOG: [SimplifyCFG] Redirect switch cases that lead to UB into an unreachable block
When following a case of a switch instruction is guaranteed to lead to
UB, we can safely break these edges and redirect those cases into a newly
created unreachable block. As result, CFG will become simpler and we can
remove some of Phi inputs to make further analyzes easier.
Patch by Dmitry Bakunevich!
Differential Revision: https://reviews.llvm.org/D109428
Reviewed By: lebedev.ri
Added:
Modified:
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
llvm/test/CodeGen/AArch64/arm64-ccmp.ll
llvm/test/Transforms/SimplifyCFG/switch_ub.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 0865e4a41bfd2..2ff98b238de08 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6629,8 +6629,30 @@ static bool removeUndefIntroducingPredecessor(BasicBlock *BB,
if (DTU)
DTU->applyUpdates({{DominatorTree::Delete, Predecessor, BB}});
return true;
+ } else if (SwitchInst *SI = dyn_cast<SwitchInst>(T)) {
+ // Redirect all branches leading to UB into
+ // a newly created unreachable block.
+ BasicBlock *Unreachable = BasicBlock::Create(
+ Predecessor->getContext(), "unreachable", BB->getParent(), BB);
+ Builder.SetInsertPoint(Unreachable);
+ // The new block contains only one instruction: Unreachable
+ Builder.CreateUnreachable();
+ for (auto &Case : SI->cases())
+ if (Case.getCaseSuccessor() == BB) {
+ BB->removePredecessor(Predecessor);
+ Case.setSuccessor(Unreachable);
+ }
+ if (SI->getDefaultDest() == BB) {
+ BB->removePredecessor(Predecessor);
+ SI->setDefaultDest(Unreachable);
+ }
+
+ if (DTU)
+ DTU->applyUpdates(
+ { { DominatorTree::Insert, Predecessor, Unreachable },
+ { DominatorTree::Delete, Predecessor, BB } });
+ return true;
}
- // TODO: SwitchInst.
}
return false;
diff --git a/llvm/test/CodeGen/AArch64/arm64-ccmp.ll b/llvm/test/CodeGen/AArch64/arm64-ccmp.ll
index cc05240800e82..d3721d338d04a 100644
--- a/llvm/test/CodeGen/AArch64/arm64-ccmp.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-ccmp.ll
@@ -367,22 +367,7 @@ declare i32 @foo()
define void @build_modify_expr() nounwind ssp {
; CHECK-LABEL: build_modify_expr:
; CHECK: ; %bb.0: ; %entry
-; CHECK-NEXT: cmp w8, #37
-; CHECK-NEXT: mov w8, #1
-; CHECK-NEXT: lsl x8, x8, xzr
-; CHECK-NEXT: mov x9, #31
-; CHECK-NEXT: movk x9, #48, lsl #32
-; CHECK-NEXT: and x8, x8, x9
-; CHECK-NEXT: ccmp x8, #0, #4, ls
-; CHECK-NEXT: b.eq LBB11_2
-; CHECK-NEXT: ; %bb.1: ; %if.end85
-; CHECK-NEXT: ret
-; CHECK-NEXT: LBB11_2: ; %sw.bb.i.i.preheader
-; CHECK-NEXT: ; implicit-def: $x8
-; CHECK-NEXT: LBB11_3: ; %sw.bb.i.i
-; CHECK-NEXT: ; =>This Inner Loop Header: Depth=1
-; CHECK-NEXT: ldr x8, [x8, #32]
-; CHECK-NEXT: b LBB11_3
+; CHECK-NEXT: ret
entry:
switch i32 undef, label %sw.bb.i.i [
i32 69, label %if.end85
diff --git a/llvm/test/Transforms/SimplifyCFG/switch_ub.ll b/llvm/test/Transforms/SimplifyCFG/switch_ub.ll
index b9fcd54a5dfa4..0b48ee6986137 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch_ub.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch_ub.ll
@@ -6,23 +6,15 @@ declare void @foo_01()
declare void @foo_02()
declare void @foo_03()
-; TODO: Basing on fact that load(null) is UB, we can remove edge pred->bb.
define i32 @test_01(i32* %p, i32 %x, i1 %cond) {
; CHECK-LABEL: @test_01(
; CHECK-NEXT: entry:
-; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB:%.*]], label [[PRED:%.*]]
-; CHECK: pred:
-; CHECK-NEXT: switch i32 [[X:%.*]], label [[COMMON_RET:%.*]] [
-; CHECK-NEXT: i32 42, label [[BB]]
-; CHECK-NEXT: i32 123456, label [[BB]]
-; CHECK-NEXT: i32 -654321, label [[BB]]
-; CHECK-NEXT: ]
+; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB:%.*]], label [[COMMON_RET:%.*]]
; CHECK: common.ret:
-; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[R:%.*]], [[BB]] ], [ 0, [[PRED]] ]
+; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[R:%.*]], [[BB]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
; CHECK: bb:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ null, [[PRED]] ], [ null, [[PRED]] ], [ null, [[PRED]] ], [ [[P:%.*]], [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[R]] = load i32, i32* [[PHI]], align 4
+; CHECK-NEXT: [[R]] = load i32, i32* [[P:%.*]], align 4
; CHECK-NEXT: br label [[COMMON_RET]]
;
entry:
@@ -42,23 +34,15 @@ other_succ:
ret i32 0
}
-; TODO: Basing on fact that load(null) is UB, we can remove edge pred->bb.
define i32 @test_02(i32* %p, i32 %x, i1 %cond) {
; CHECK-LABEL: @test_02(
; CHECK-NEXT: entry:
-; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB:%.*]], label [[PRED:%.*]]
-; CHECK: pred:
-; CHECK-NEXT: switch i32 [[X:%.*]], label [[BB]] [
-; CHECK-NEXT: i32 42, label [[COMMON_RET:%.*]]
-; CHECK-NEXT: i32 123456, label [[COMMON_RET]]
-; CHECK-NEXT: i32 -654321, label [[COMMON_RET]]
-; CHECK-NEXT: ]
+; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB:%.*]], label [[COMMON_RET:%.*]]
; CHECK: common.ret:
-; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[R:%.*]], [[BB]] ], [ 0, [[PRED]] ], [ 0, [[PRED]] ], [ 0, [[PRED]] ]
+; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[R:%.*]], [[BB]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
; CHECK: bb:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ null, [[PRED]] ], [ [[P:%.*]], [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[R]] = load i32, i32* [[PHI]], align 4
+; CHECK-NEXT: [[R]] = load i32, i32* [[P:%.*]], align 4
; CHECK-NEXT: br label [[COMMON_RET]]
;
entry:
@@ -78,13 +62,12 @@ other_succ:
ret i32 0
}
-; TODO: Basing on fact that load(null) is UB, we can remove edge pred->bb.
define i32 @test_03(i32* %p, i32 %x, i1 %cond) {
; CHECK-LABEL: @test_03(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB:%.*]], label [[PRED:%.*]]
; CHECK: pred:
-; CHECK-NEXT: switch i32 [[X:%.*]], label [[BB]] [
+; CHECK-NEXT: switch i32 [[X:%.*]], label [[UNREACHABLE:%.*]] [
; CHECK-NEXT: i32 42, label [[COMMON_RET:%.*]]
; CHECK-NEXT: i32 123456, label [[COMMON_RET]]
; CHECK-NEXT: i32 -654321, label [[COMMON_RET]]
@@ -95,9 +78,10 @@ define i32 @test_03(i32* %p, i32 %x, i1 %cond) {
; CHECK: common.ret:
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[R:%.*]], [[BB]] ], [ 1, [[DO_1]] ], [ 1, [[DO_2]] ], [ 1, [[DO_3]] ], [ 0, [[PRED]] ], [ 0, [[PRED]] ], [ 0, [[PRED]] ]
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
+; CHECK: unreachable:
+; CHECK-NEXT: unreachable
; CHECK: bb:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ null, [[PRED]] ], [ [[P:%.*]], [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[R]] = load i32, i32* [[PHI]], align 4
+; CHECK-NEXT: [[R]] = load i32, i32* [[P:%.*]], align 4
; CHECK-NEXT: br label [[COMMON_RET]]
; CHECK: do_1:
; CHECK-NEXT: call void @foo_01()
@@ -141,26 +125,21 @@ other_succ:
ret i32 0
}
-; TODO: Basing on fact that load(null) is UB, we can remove edge pred->bb.
define i32 @test_04(i32* %p, i32 %x, i1 %cond) {
; CHECK-LABEL: @test_04(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB:%.*]], label [[PRED:%.*]]
; CHECK: pred:
; CHECK-NEXT: switch i32 [[X:%.*]], label [[COMMON_RET:%.*]] [
-; CHECK-NEXT: i32 42, label [[BB]]
-; CHECK-NEXT: i32 123456, label [[BB]]
-; CHECK-NEXT: i32 -654321, label [[BB]]
-; CHECK-NEXT: i32 1, label [[DO_1:%.*]]
-; CHECK-NEXT: i32 2, label [[DO_2:%.*]]
; CHECK-NEXT: i32 3, label [[DO_3:%.*]]
+; CHECK-NEXT: i32 2, label [[DO_2:%.*]]
+; CHECK-NEXT: i32 1, label [[DO_1:%.*]]
; CHECK-NEXT: ]
; CHECK: common.ret:
; CHECK-NEXT: [[COMMON_RET_OP:%.*]] = phi i32 [ [[R:%.*]], [[BB]] ], [ 1, [[DO_1]] ], [ 1, [[DO_2]] ], [ 1, [[DO_3]] ], [ 0, [[PRED]] ]
; CHECK-NEXT: ret i32 [[COMMON_RET_OP]]
; CHECK: bb:
-; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ null, [[PRED]] ], [ null, [[PRED]] ], [ null, [[PRED]] ], [ [[P:%.*]], [[ENTRY:%.*]] ]
-; CHECK-NEXT: [[R]] = load i32, i32* [[PHI]], align 4
+; CHECK-NEXT: [[R]] = load i32, i32* [[P:%.*]], align 4
; CHECK-NEXT: br label [[COMMON_RET]]
; CHECK: do_1:
; CHECK-NEXT: call void @foo_01()
More information about the llvm-commits
mailing list