From a3d4e67e432577ebca542c8e483ec692956a88c8 Mon Sep 17 00:00:00 2001
From: David Majnemer <david.majnemer@gmail.com>
Date: Tue, 5 Jan 2016 07:42:17 +0000
Subject: [PATCH] [SimplifyCFG] Further improve our ability to remove redundant
 catchpads

In r256814, we managed to remove catchpads which were trivially redudant
because they were the same SSA value.  We can do better using the same
algorithm but with a smarter datastructure by hashing the SSA values
within the catchpad and comparing them structurally.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256815 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Transforms/Utils/Local.cpp                | 28 +++++++-
 .../SimplifyCFG/wineh-unreachable.ll          | 66 +++++++++++++++++++
 2 files changed, 92 insertions(+), 2 deletions(-)

diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp
index 3845ca2e7e5..3f46c5ebf45 100644
--- a/lib/Transforms/Utils/Local.cpp
+++ b/lib/Transforms/Utils/Local.cpp
@@ -1324,12 +1324,36 @@ static bool markAliveBlocks(Function &F,
       }
     } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Terminator)) {
       // Remove catchpads which cannot be reached.
-      SmallPtrSet<BasicBlock *, 4> HandlersSeen;
+      struct CatchPadDenseMapInfo {
+        static CatchPadInst *getEmptyKey() {
+          return DenseMapInfo<CatchPadInst *>::getEmptyKey();
+        }
+        static CatchPadInst *getTombstoneKey() {
+          return DenseMapInfo<CatchPadInst *>::getTombstoneKey();
+        }
+        static unsigned getHashValue(CatchPadInst *CatchPad) {
+          return static_cast<unsigned>(hash_combine_range(
+              CatchPad->value_op_begin(), CatchPad->value_op_end()));
+        }
+        static bool isEqual(CatchPadInst *LHS, CatchPadInst *RHS) {
+          if (LHS == getEmptyKey() || LHS == getTombstoneKey() ||
+              RHS == getEmptyKey() || RHS == getTombstoneKey())
+            return LHS == RHS;
+          return LHS->isIdenticalTo(RHS);
+        }
+      };
+
+      // Set of unique CatchPads.
+      SmallDenseMap<CatchPadInst *, detail::DenseSetEmpty, 4,
+                    CatchPadDenseMapInfo, detail::DenseSetPair<CatchPadInst *>>
+          HandlerSet;
+      detail::DenseSetEmpty Empty;
       for (CatchSwitchInst::handler_iterator I = CatchSwitch->handler_begin(),
                                              E = CatchSwitch->handler_end();
            I != E; ++I) {
         BasicBlock *HandlerBB = *I;
-        if (!HandlersSeen.insert(HandlerBB).second) {
+        auto *CatchPad = cast<CatchPadInst>(HandlerBB->getFirstNonPHI());
+        if (!HandlerSet.insert({CatchPad, Empty}).second) {
           CatchSwitch->removeHandler(I);
           --I;
           --E;
diff --git a/test/Transforms/SimplifyCFG/wineh-unreachable.ll b/test/Transforms/SimplifyCFG/wineh-unreachable.ll
index d871e17b6b0..c5d6490ba5d 100644
--- a/test/Transforms/SimplifyCFG/wineh-unreachable.ll
+++ b/test/Transforms/SimplifyCFG/wineh-unreachable.ll
@@ -99,3 +99,69 @@ catch.body:
 exit:
   ret void
 }
+
+; CHECK-LABEL: define void @test7()
+define void @test7() personality i8* bitcast (void ()* @Personality to i8*) {
+entry:
+  invoke void @f()
+          to label %exit unwind label %catch.pad
+
+catch.pad:
+  %cs1 = catchswitch within none [label %catch.body, label %catch.body2] unwind to caller
+  ; CHECK: catchswitch within none [label %catch.body] unwind to caller
+
+catch.body:
+  %catch = catchpad within %cs1 [i8* null, i32 0, i8* null]
+  catchret from %catch to label %exit
+
+catch.body2:
+  %catch2 = catchpad within %cs1 [i8* null, i32 0, i8* null]
+  catchret from %catch2 to label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: define void @test8()
+define void @test8() personality i8* bitcast (void ()* @Personality to i8*) {
+entry:
+  invoke void @f()
+          to label %exit unwind label %catch.pad
+
+catch.pad:
+  %cs1 = catchswitch within none [label %catch.body, label %catch.body2] unwind to caller
+  ; CHECK: catchswitch within none [label %catch.body] unwind to caller
+
+catch.body2:
+  %catch2 = catchpad within %cs1 [i8* null, i32 0, i8* null]
+  catchret from %catch2 to label %exit
+
+catch.body:
+  %catch = catchpad within %cs1 [i8* null, i32 0, i8* null]
+  catchret from %catch to label %exit
+
+exit:
+  ret void
+}
+
+; CHECK-LABEL: define void @test9()
+define void @test9() personality i8* bitcast (void ()* @Personality to i8*) {
+entry:
+  invoke void @f()
+          to label %exit unwind label %catch.pad
+
+catch.pad:
+  %cs1 = catchswitch within none [label %catch.body, label %catch.body2] unwind to caller
+  ; CHECK: catchswitch within none [label %catch.body, label %catch.body2] unwind to caller
+
+catch.body:
+  %catch = catchpad within %cs1 [i8* null, i32 0, i8* null]
+  catchret from %catch to label %exit
+
+catch.body2:
+  %catch2 = catchpad within %cs1 [i8* null, i32 64, i8* null]
+  catchret from %catch2 to label %exit
+
+exit:
+  ret void
+}
-- 
2.40.0