[llvm] d218092 - [SCCP] Check whether the default case is reachable (#76295)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 8 04:08:46 PST 2024


Author: Yingwei Zheng
Date: 2024-01-08T20:08:42+08:00
New Revision: d218092543b3f9ba2204d7c8fe5ac70befa3d772

URL: https://github.com/llvm/llvm-project/commit/d218092543b3f9ba2204d7c8fe5ac70befa3d772
DIFF: https://github.com/llvm/llvm-project/commit/d218092543b3f9ba2204d7c8fe5ac70befa3d772.diff

LOG: [SCCP] Check whether the default case is reachable (#76295)

This patch eliminates unreachable default cases using range information.
Fixes #76085.

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/SCCPSolver.cpp
    llvm/test/Transforms/SCCP/switch.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index ab95698abc4399..3dc6016a0a373f 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -310,6 +310,7 @@ bool SCCPSolver::removeNonFeasibleEdges(BasicBlock *BB, DomTreeUpdater &DTU,
         new UnreachableInst(DefaultDest->getContext(), NewUnreachableBB);
       }
 
+      DefaultDest->removePredecessor(BB);
       SI->setDefaultDest(NewUnreachableBB);
       Updates.push_back({DominatorTree::Delete, BB, DefaultDest});
       Updates.push_back({DominatorTree::Insert, BB, NewUnreachableBB});
@@ -1063,14 +1064,17 @@ void SCCPInstVisitor::getFeasibleSuccessors(Instruction &TI,
     // is ready.
     if (SCValue.isConstantRange(/*UndefAllowed=*/false)) {
       const ConstantRange &Range = SCValue.getConstantRange();
+      unsigned ReachableCaseCount = 0;
       for (const auto &Case : SI->cases()) {
         const APInt &CaseValue = Case.getCaseValue()->getValue();
-        if (Range.contains(CaseValue))
+        if (Range.contains(CaseValue)) {
           Succs[Case.getSuccessorIndex()] = true;
+          ++ReachableCaseCount;
+        }
       }
 
-      // TODO: Determine whether default case is reachable.
-      Succs[SI->case_default()->getSuccessorIndex()] = true;
+      Succs[SI->case_default()->getSuccessorIndex()] =
+          Range.isSizeLargerThan(ReachableCaseCount);
       return;
     }
 

diff  --git a/llvm/test/Transforms/SCCP/switch.ll b/llvm/test/Transforms/SCCP/switch.ll
index 19e72217fd03bf..306f0eebf2b408 100644
--- a/llvm/test/Transforms/SCCP/switch.ll
+++ b/llvm/test/Transforms/SCCP/switch.ll
@@ -4,6 +4,8 @@
 ; Make sure we always consider the default edge executable for a switch
 ; with no cases.
 declare void @foo()
+declare i32 @g(i32)
+
 define void @test1() {
 ; CHECK-LABEL: @test1(
 ; CHECK-NEXT:    switch i32 undef, label [[D:%.*]] [
@@ -115,17 +117,16 @@ switch.1:
   ret i32 %phi
 }
 
-; TODO: Determine that the default destination is dead.
 define i32 @test_local_range(ptr %p) {
 ; CHECK-LABEL: @test_local_range(
 ; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    switch i32 [[X]], label [[SWITCH_DEFAULT:%.*]] [
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT_UNREACHABLE:%.*]] [
 ; CHECK-NEXT:    i32 0, label [[SWITCH_0:%.*]]
 ; CHECK-NEXT:    i32 1, label [[SWITCH_1:%.*]]
 ; CHECK-NEXT:    i32 2, label [[SWITCH_2:%.*]]
 ; CHECK-NEXT:    ]
-; CHECK:       switch.default:
-; CHECK-NEXT:    ret i32 -1
+; CHECK:       default.unreachable:
+; CHECK-NEXT:    unreachable
 ; CHECK:       switch.0:
 ; CHECK-NEXT:    ret i32 0
 ; CHECK:       switch.1:
@@ -161,14 +162,14 @@ switch.3:
 define i32 @test_duplicate_successors(ptr %p) {
 ; CHECK-LABEL: @test_duplicate_successors(
 ; CHECK-NEXT:    [[X:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG0]]
-; CHECK-NEXT:    switch i32 [[X]], label [[SWITCH_DEFAULT:%.*]] [
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT_UNREACHABLE:%.*]] [
 ; CHECK-NEXT:    i32 0, label [[SWITCH_0:%.*]]
 ; CHECK-NEXT:    i32 1, label [[SWITCH_0]]
 ; CHECK-NEXT:    i32 2, label [[SWITCH_1:%.*]]
 ; CHECK-NEXT:    i32 3, label [[SWITCH_1]]
 ; CHECK-NEXT:    ]
-; CHECK:       switch.default:
-; CHECK-NEXT:    ret i32 -1
+; CHECK:       default.unreachable:
+; CHECK-NEXT:    unreachable
 ; CHECK:       switch.0:
 ; CHECK-NEXT:    ret i32 0
 ; CHECK:       switch.1:
@@ -201,13 +202,13 @@ switch.2:
 ; range information.
 define internal i32 @test_ip_range(i32 %x) {
 ; CHECK-LABEL: @test_ip_range(
-; CHECK-NEXT:    switch i32 [[X:%.*]], label [[SWITCH_DEFAULT:%.*]] [
+; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT_UNREACHABLE:%.*]] [
 ; CHECK-NEXT:    i32 3, label [[SWITCH_3:%.*]]
 ; CHECK-NEXT:    i32 1, label [[SWITCH_1:%.*]]
 ; CHECK-NEXT:    i32 2, label [[SWITCH_2:%.*]]
 ; CHECK-NEXT:    ], !prof [[PROF1:![0-9]+]]
-; CHECK:       switch.default:
-; CHECK-NEXT:    ret i32 -1
+; CHECK:       default.unreachable:
+; CHECK-NEXT:    unreachable
 ; CHECK:       switch.1:
 ; CHECK-NEXT:    ret i32 1
 ; CHECK:       switch.2:
@@ -240,8 +241,8 @@ switch.3:
 
 define void @call_test_ip_range() {
 ; CHECK-LABEL: @call_test_ip_range(
-; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @test_ip_range(i32 1)
-; CHECK-NEXT:    [[TMP2:%.*]] = call i32 @test_ip_range(i32 3)
+; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @test_ip_range(i32 1), !range [[RNG2:![0-9]+]]
+; CHECK-NEXT:    [[TMP2:%.*]] = call i32 @test_ip_range(i32 3), !range [[RNG2]]
 ; CHECK-NEXT:    ret void
 ;
   call i32 @test_ip_range(i32 1)
@@ -301,6 +302,72 @@ end.2:
   ret i32 20
 }
 
+define i32 @test_default_unreachable_by_dom_cond(i32 %x) {
+; CHECK-LABEL: @test_default_unreachable_by_dom_cond(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[OR_COND:%.*]] = icmp ult i32 [[X:%.*]], 4
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[IF_THEN:%.*]], label [[RETURN:%.*]]
+; CHECK:       if.then:
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT_UNREACHABLE:%.*]] [
+; CHECK-NEXT:      i32 0, label [[SW_BB:%.*]]
+; CHECK-NEXT:      i32 1, label [[SW_BB2:%.*]]
+; CHECK-NEXT:      i32 2, label [[SW_BB4:%.*]]
+; CHECK-NEXT:      i32 3, label [[SW_BB6:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       sw.bb:
+; CHECK-NEXT:    [[CALL:%.*]] = tail call i32 @g(i32 2)
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       sw.bb2:
+; CHECK-NEXT:    [[CALL3:%.*]] = tail call i32 @g(i32 3)
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       sw.bb4:
+; CHECK-NEXT:    [[CALL5:%.*]] = tail call i32 @g(i32 4)
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       sw.bb6:
+; CHECK-NEXT:    [[CALL7:%.*]] = tail call i32 @g(i32 5)
+; CHECK-NEXT:    br label [[RETURN]]
+; CHECK:       default.unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       return:
+; CHECK-NEXT:    [[RETVAL_0:%.*]] = phi i32 [ [[CALL7]], [[SW_BB6]] ], [ [[CALL5]], [[SW_BB4]] ], [ [[CALL3]], [[SW_BB2]] ], [ [[CALL]], [[SW_BB]] ], [ -23, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    ret i32 [[RETVAL_0]]
+;
+entry:
+  %or.cond = icmp ult i32 %x, 4
+  br i1 %or.cond, label %if.then, label %return
+
+if.then:
+  switch i32 %x, label %sw.epilog [
+  i32 0, label %sw.bb
+  i32 1, label %sw.bb2
+  i32 2, label %sw.bb4
+  i32 3, label %sw.bb6
+  ]
+
+sw.bb:
+  %call = tail call i32 @g(i32 2)
+  br label %return
+
+sw.bb2:
+  %call3 = tail call i32 @g(i32 3)
+  br label %return
+
+sw.bb4:
+  %call5 = tail call i32 @g(i32 4)
+  br label %return
+
+sw.bb6:
+  %call7 = tail call i32 @g(i32 5)
+  br label %return
+
+sw.epilog:
+  call void @foo()
+  br label %return
+
+return:
+  %retval.0 = phi i32 [ %call7, %sw.bb6 ], [ %call5, %sw.bb4 ], [ %call3, %sw.bb2 ], [ %call, %sw.bb ], [ -23, %sw.epilog ], [ -23, %entry ]
+  ret i32 %retval.0
+}
 
 declare void @llvm.assume(i1)
 


        


More information about the llvm-commits mailing list