Validated by nightly-test runs on x86 and x86-64 darwin, including after
self-host.  Hopefully these results hold up on different platforms.  

I tried to keep the GNU ObjC runtime happy, but it's hard for me to test.
Reimplement how clang generates IR for exceptions.  Instead of creating new
invoke destinations which sequentially chain to the previous destination,
push a more semantic representation of *why* we need the cleanup/catch/filter
behavior, then collect that information into a single landing pad upon request.

Also reorganizes how normal cleanups (i.e. cleanups triggered by non-exceptional
control flow) are generated, since it's actually fairly closely tied in with
the former.  Remove the need to track which cleanup scope a block is associated
with.

Document a lot of previously poorly-understood (by me, at least) behavior.

The new framework implements the Horrible Hack (tm), which requires every
landing pad to have a catch-all so that inlining will work.  Clang no longer
requires the Horrible Hack just to make exceptions flow correctly within
a function, however.  The HH is an unfortunate requirement of LLVM's EH IR.




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@107631 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CodeGenCXX/condition.cpp b/test/CodeGenCXX/condition.cpp
index f5b43d2..b1fa9f1 100644
--- a/test/CodeGenCXX/condition.cpp
+++ b/test/CodeGenCXX/condition.cpp
@@ -96,66 +96,132 @@
 
 int foo();
 
+// CHECK: define void @_Z14while_destructi
 void while_destruct(int z) {
-  // CHECK: define void @_Z14while_destructi
-  // CHECK: {{while.cond:|:3}}
+  // CHECK: [[Z:%.*]] = alloca i32
+  // CHECK: [[CLEANUPDEST:%.*]] = alloca i32
   while (X x = X()) {
     // CHECK: call void @_ZN1XC1Ev
+    // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv
+    // CHECK-NEXT: br i1 [[COND]]
 
-    // CHECK: {{while.body:|:5}}
-    // CHECK: store i32 21
+    // Loop-exit staging block.
+    // CHECK: store i32 1, i32* [[CLEANUPDEST]]
+    // CHECK-NEXT: br
+
+    // While body.
+    // CHECK: store i32 21, i32* [[Z]]
+    // CHECK: store i32 2, i32* [[CLEANUPDEST]]
+    // CHECK-NEXT: br
     z = 21;
 
-    // CHECK: {{while.cleanup:|:6}}
+    // Cleanup.
     // CHECK: call void @_ZN1XD1Ev
+    // CHECK-NEXT: [[DEST:%.*]] = load i32* [[CLEANUPDEST]]
+    // CHECK-NEXT: switch i32 [[DEST]]
   }
-  // CHECK: {{while.end|:8}}
-  // CHECK: store i32 22
+
+  // CHECK: store i32 22, i32* [[Z]]
   z = 22;
 
   // CHECK: call void @_Z4getXv
-  // CHECK: call zeroext i1 @_ZN1XcvbEv
-  // CHECK: call void @_ZN1XD1Ev
-  // CHECK: br
+  // CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv
+  // CHECK-NEXT: call void @_ZN1XD1Ev
+  // CHECK-NEXT: br
   while(getX()) { }
 
-  // CHECK: store i32 25
+  // CHECK: store i32 25, i32* [[Z]]
   z = 25;
 
   // CHECK: ret
 }
 
+// CHECK: define void @_Z12for_destructi(
 void for_destruct(int z) {
-  // CHECK: define void @_Z12for_destruct
+  // CHECK: [[Z:%.*]] = alloca i32
+  // CHECK: [[XDEST:%.*]] = alloca i32
+  // CHECK: [[I:%.*]] = alloca i32
   // CHECK: call void @_ZN1YC1Ev
-  for(Y y = Y(); X x = X(); ++z)
-    // CHECK: {{for.cond:|:4}}
+  // CHECK-NEXT: br
+  // -> %for.cond
+
+  for(Y y = Y(); X x = X(); ++z) {
+    // %for.cond: The loop condition.
     // CHECK: call void @_ZN1XC1Ev
-    // CHECK: {{for.body:|:6}}
-    // CHECK: store i32 23
+    // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv(
+    // CHECK-NEXT: br i1 [[COND]]
+    // -> %for.body, %for.cond.cleanup
+
+    // %for.cond.cleanup: Exit cleanup staging.
+    // CHECK: store i32 1, i32* [[XDEST]]
+    // CHECK-NEXT: br
+    // -> %cleanup
+
+    // %for.body:
+    // CHECK: store i32 23, i32* [[Z]]
+    // CHECK-NEXT: br
+    // -> %for.inc
     z = 23;
-    // CHECK: {{for.inc:|:7}}
-    // CHECK: br label %{{for.cond.cleanup|10}}
-    // CHECK: {{for.cond.cleanup:|:10}}
+
+    // %for.inc:
+    // CHECK: [[TMP:%.*]] = load i32* [[Z]]
+    // CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1
+    // CHECK-NEXT: store i32 [[INC]], i32* [[Z]]
+    // CHECK-NEXT: store i32 2, i32* [[XDEST]]
+    // CHECK-NEXT: br
+    // -> %cleanup
+
+    // %cleanup:  Destroys X.
     // CHECK: call void @_ZN1XD1Ev
-  // CHECK: {{for.end:|:12}}
-  // CHECK: call void @_ZN1YD1Ev
+    // CHECK-NEXT: [[YDESTTMP:%.*]] = load i32* [[XDEST]]
+    // CHECK-NEXT: switch i32 [[YDESTTMP]]
+    // 1 -> %cleanup4, 2 -> %cleanup.cont
+
+    // %cleanup.cont:  (eliminable)
+    // CHECK: br
+    // -> %for.cond
+
+    // %cleanup4: Destroys Y.
+    // CHECK: call void @_ZN1YD1Ev(
+    // CHECK-NEXT: br
+    // -> %for.end
+  }
+
+  // %for.end:
   // CHECK: store i32 24
   z = 24;
 
+  // CHECK-NEXT: store i32 0, i32* [[I]]
+  // CHECK-NEXT: br
+  // -> %for.cond6
+
+  // %for.cond6:
   // CHECK: call void @_Z4getXv
-  // CHECK: call zeroext i1 @_ZN1XcvbEv
-  // CHECK: call void @_ZN1XD1Ev
+  // CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv
+  // CHECK-NEXT: call void @_ZN1XD1Ev
+  // CHECK-NEXT: br
+  // -> %for.body10, %for.end16
+
+  // %for.body10:
   // CHECK: br
+  // -> %for.inc11
+
+  // %for.inc11:
   // CHECK: call void @_Z4getXv
-  // CHECK: load
-  // CHECK: add
-  // CHECK: call void @_ZN1XD1Ev
+  // CHECK-NEXT: load i32* [[I]]
+  // CHECK-NEXT: add
+  // CHECK-NEXT: store
+  // CHECK-NEXT: call void @_ZN1XD1Ev
+  // CHECK-NEXT: br
+  // -> %for.cond6
   int i = 0;
   for(; getX(); getX(), ++i) { }
-  z = 26;
+
+  // %for.end16
   // CHECK: store i32 26
-  // CHECK: ret
+  z = 26;
+
+  // CHECK-NEXT: ret void
 }
 
 void do_destruct(int z) {
diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp
index ef3d4b9..ee8f1a5 100644
--- a/test/CodeGenCXX/destructors.cpp
+++ b/test/CodeGenCXX/destructors.cpp
@@ -187,15 +187,63 @@
   // Checked at top of file:
   // @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev
 
+  // More checks at end of file.
+
+}
+
+namespace test4 {
+  struct A { ~A(); };
+
+  // CHECK: define void @_ZN5test43fooEv()
+  // CHECK: call void @_ZN5test41AD1Ev
+  // CHECK: ret void
+  void foo() {
+    {
+      A a;
+      goto failure;
+    }
+
+  failure:
+    return;
+  }
+
+  // CHECK: define void @_ZN5test43barEi(
+  // CHECK:      [[X:%.*]] = alloca i32
+  // CHECK-NEXT: [[A:%.*]] = alloca
+  // CHECK:      br label
+  // CHECK:      [[TMP:%.*]] = load i32* [[X]]
+  // CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP]], 0
+  // CHECK-NEXT: br i1
+  // CHECK:      call void @_ZN5test41AD1Ev(
+  // CHECK:      br label
+  // CHECK:      [[TMP:%.*]] = load i32* [[X]]
+  // CHECK:      [[TMP2:%.*]] = add nsw i32 [[TMP]], -1
+  // CHECK:      store i32 [[TMP2]], i32* [[X]]
+  // CHECK:      br label
+  // CHECK:      ret void
+  void bar(int x) {
+    for (A a; x; ) {
+      x--;
+    }
+  }
+}
+
+// Checks from test3:
+
   // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(
   // CHECK: call void @_ZN5test31BD2Ev(
   // CHECK: call void @_ZN5test31AD2Ev(
   // CHECK: ret void
 
   // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(
-  // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev(
+  // CHECK: invoke void @_ZN5test312_GLOBAL__N_11DD1Ev(
   // CHECK: call void @_ZdlPv(
   // CHECK: ret void
+  // CHECK: call i8* @llvm.eh.exception(
+  // CHECK: invoke void @_ZdlPv
+  // CHECK: call void @_Unwind_Resume_or_Rethrow
+  // CHECK: call i8* @llvm.eh.exception(
+  // CHECK: call void @_ZSt9terminatev(
 
   // Checked at top of file:
   // @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev
@@ -215,9 +263,14 @@
   // CHECK: declare void @_ZN5test31AD2Ev(
 
   // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(
-  // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev(
+  // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD1Ev(
   // CHECK: call void @_ZdlPv(
   // CHECK: ret void
+  // CHECK: call i8* @llvm.eh.exception()
+  // CHECK: invoke void @_ZdlPv(
+  // CHECK: call void @_Unwind_Resume_or_Rethrow(
+  // CHECK: call i8* @llvm.eh.exception()
+  // CHECK: call void @_ZSt9terminatev()
 
   // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev(
   // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
@@ -228,4 +281,3 @@
   // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8
   // CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev(
   // CHECK: ret void
-}
diff --git a/test/CodeGenCXX/eh.cpp b/test/CodeGenCXX/eh.cpp
index f2629d1..4d09558 100644
--- a/test/CodeGenCXX/eh.cpp
+++ b/test/CodeGenCXX/eh.cpp
@@ -38,6 +38,7 @@
 // CHECK:     define void @_Z5test2v()
 // CHECK:       [[FREEVAR:%.*]] = alloca i1
 // CHECK-NEXT:  [[EXNOBJVAR:%.*]] = alloca i8*
+// CHECK-NEXT:  [[EXNSLOTVAR:%.*]] = alloca i8*
 // CHECK-NEXT:  store i1 false, i1* [[FREEVAR]]
 // CHECK-NEXT:  [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16)
 // CHECK-NEXT:  store i8* [[EXNOBJ]], i8** [[EXNOBJVAR]]
@@ -104,3 +105,91 @@
 //      :    [[HANDLER]]:  (can't check this in Release-Asserts builds)
 // CHECK:      {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{%.*}}* @_ZTIN5test51AE to i8*))
 }
+
+namespace test6 {
+  template <class T> struct allocator {
+    ~allocator() throw() { }
+  };
+
+  void foo() {
+    allocator<int> a;
+  }
+}
+
+// PR7127
+namespace test7 {
+// CHECK:      define i32 @_ZN5test73fooEv() 
+  int foo() {
+// CHECK:      [[FREEEXNOBJ:%.*]] = alloca i1
+// CHECK-NEXT: [[EXNALLOCVAR:%.*]] = alloca i8*
+// CHECK-NEXT: [[CAUGHTEXNVAR:%.*]] = alloca i8*
+// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32
+// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]]
+    try {
+      try {
+// CHECK-NEXT: [[EXNALLOC:%.*]] = call i8* @__cxa_allocate_exception
+// CHECK-NEXT: store i8* [[EXNALLOC]], i8** [[EXNALLOCVAR]]
+// CHECK-NEXT: store i1 true, i1* [[FREEEXNOBJ]]
+// CHECK-NEXT: bitcast i8* [[EXNALLOC]] to i32*
+// CHECK-NEXT: store i32 1, i32*
+// CHECK-NEXT: store i1 false, i1* [[FREEEXNOBJ]]
+// CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXNALLOC]], i8* bitcast (i8** @_ZTIi to i8*), i8* null
+        throw 1;
+      }
+// This cleanup ends up here for no good reason.  It's actually unused.
+// CHECK:      load i8** [[EXNALLOCVAR]]
+// CHECK-NEXT: call void @__cxa_free_exception(
+
+// CHECK:      [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
+// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
+// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
+// CHECK-NEXT: call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
+// CHECK-NEXT: icmp eq
+// CHECK-NEXT: br i1
+// CHECK:      load i8** [[CAUGHTEXNVAR]]
+// CHECK-NEXT: call i8* @__cxa_begin_catch
+// CHECK:      invoke void @__cxa_rethrow
+      catch (int) {
+        throw;
+      }
+    }
+// CHECK:      [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
+// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
+// CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* [[CAUGHTEXN]], i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* null)
+// CHECK-NEXT: call void @__cxa_end_catch()
+// CHECK-NEXT: br label
+// CHECK:      load i8** [[CAUGHTEXNVAR]]
+// CHECK-NEXT: call i8* @__cxa_begin_catch
+// CHECK-NEXT: call void @__cxa_end_catch
+    catch (...) {
+    }
+// CHECK:      ret i32 0
+    return 0;
+  }
+}
+
+// Ordering of destructors in a catch handler.
+namespace test8 {
+  struct A { A(const A&); ~A(); };
+  void bar();
+
+  // CHECK: define void @_ZN5test83fooEv()
+  void foo() {
+    try {
+      // CHECK:      invoke void @_ZN5test83barEv()
+      bar();
+    } catch (A a) {
+      // CHECK:      call i8* @__cxa_get_exception_ptr
+      // CHECK-NEXT: bitcast
+      // CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_(
+      // CHECK:      call i8* @__cxa_begin_catch
+      // CHECK-NEXT: invoke void @_ZN5test81AD1Ev(
+
+      // CHECK:      call void @__cxa_end_catch()
+      // CHECK-NEXT: load
+      // CHECK-NEXT: switch
+
+      // CHECK:      ret void
+    }
+  }
+}
diff --git a/test/CodeGenCXX/nrvo.cpp b/test/CodeGenCXX/nrvo.cpp
index 9ee5536..6181f0e 100644
--- a/test/CodeGenCXX/nrvo.cpp
+++ b/test/CodeGenCXX/nrvo.cpp
@@ -1,5 +1,5 @@
 // RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s
-// RUN: %clang_cc1 -emit-llvm -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
+// RUN: %clang_cc1 -emit-llvm -O1 -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s
 
 // Test code generation for the named return value optimization.
 class X {
@@ -13,48 +13,97 @@
 // CHECK-EH: define void @_Z5test0v
 X test0() {
   X x;
-  // CHECK-NOT: call void @_ZN1XD1Ev
-  // CHECK: ret void
-  // CHECK-EH: br label
-  // CHECK-EH: call void @_ZN1XD1Ev
-  // CHECK-EH: br label
-  // CHECK-EH: invoke void @_ZN1XD1Ev
-  // CHECK-EH: ret void
+  // CHECK:          call void @_ZN1XC1Ev
+  // CHECK-NEXT:     ret void
+
+  // CHECK-EH:       call void @_ZN1XC1Ev
+  // CHECK-EH-NEXT:  ret void
   return x;
 }
 
 // CHECK: define void @_Z5test1b(
+// CHECK-EH: define void @_Z5test1b(
 X test1(bool B) {
-  // CHECK: call void @_ZN1XC1Ev
+  // CHECK:      tail call void @_ZN1XC1Ev
+  // CHECK-NEXT: ret void
   X x;
-  // CHECK-NOT: call void @_ZN1XD1Ev
-  // CHECK: ret void
   if (B)
     return (x);
   return x;
-  // CHECK-EH: invoke void @_ZN1XD1Ev
+  // CHECK-EH:      tail call void @_ZN1XC1Ev
+  // CHECK-EH-NEXT: ret void
 }
 
 // CHECK: define void @_Z5test2b
 // CHECK-EH: define void @_Z5test2b
 X test2(bool B) {
-  // No NRVO
-  // CHECK: call void @_ZN1XC1Ev
+  // No NRVO.
+
   X x;
-  // CHECK: call void @_ZN1XC1Ev
   X y;
-  // CHECK: call void @_ZN1XC1ERKS_
-  // CHECK-EH: invoke void @_ZN1XC1ERKS_
   if (B)
     return y;
-  // CHECK: call void @_ZN1XC1ERKS_
-  // CHECK-EH: invoke void @_ZN1XC1ERKS_
   return x;
+
+  // CHECK: call void @_ZN1XC1Ev
+  // CHECK-NEXT: call void @_ZN1XC1Ev
+  // CHECK: call void @_ZN1XC1ERKS_
+  // CHECK: call void @_ZN1XC1ERKS_
   // CHECK: call void @_ZN1XD1Ev
   // CHECK: call void @_ZN1XD1Ev
   // CHECK: ret void
+
+  // The block ordering in the -fexceptions IR is unfortunate.
+
+  // CHECK-EH:      call void @_ZN1XC1Ev
+  // CHECK-EH-NEXT: invoke void @_ZN1XC1Ev
+  // -> %invoke.cont1, %lpad
+
+  // %invoke.cont1:
+  // CHECK-EH:      br i1
+  // -> %if.then, %if.end
+
+  // %if.then: returning 'x'
+  // CHECK-EH:      invoke void @_ZN1XC1ERKS_
+  // -> %cleanup, %lpad5
+
+  // %invoke.cont: rethrow block for %eh.cleanup.
+  // This really should be elsewhere in the function.
+  // CHECK-EH:      call void @_Unwind_Resume_or_Rethrow
+  // CHECK-EH-NEXT: unreachable
+
+  // %lpad: landing pad for ctor of 'y', dtor of 'y'
+  // CHECK-EH:      call i8* @llvm.eh.exception()
+  // CHECK-EH: call i32 (i8*, i8*, ...)* @llvm.eh.selector
+  // CHECK-EH-NEXT: br label
+  // -> %eh.cleanup
+
+  // %invoke.cont2: normal cleanup for 'x'
+  // CHECK-EH:      call void @_ZN1XD1Ev
+  // CHECK-EH-NEXT: ret void
+
+  // %lpad5: landing pad for return copy ctors, EH cleanup for 'y'
   // CHECK-EH: invoke void @_ZN1XD1Ev
+  // -> %eh.cleanup, %terminate.lpad
+
+  // %if.end: returning 'y'
+  // CHECK-EH: invoke void @_ZN1XC1ERKS_
+  // -> %cleanup, %lpad5
+
+  // %cleanup: normal cleanup for 'y'
   // CHECK-EH: invoke void @_ZN1XD1Ev
+  // -> %invoke.cont2, %lpad
+
+  // %eh.cleanup:  EH cleanup for 'x'
+  // CHECK-EH: invoke void @_ZN1XD1Ev
+  // -> %invoke.cont, %terminate.lpad
+
+  // %terminate.lpad: terminate landing pad.
+  // CHECK-EH:      call i8* @llvm.eh.exception()
+  // CHECK-EH-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector
+  // CHECK-EH-NEXT: call void @_ZSt9terminatev()
+  // CHECK-EH-NEXT: unreachable
+
 }
 
 X test3(bool B) {
diff --git a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
index 9347cc9..17c1030 100644
--- a/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
+++ b/test/CodeGenCXX/threadsafe-statics-exceptions.cpp
@@ -12,15 +12,18 @@
   // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x)
   // CHECK: invoke void @_ZN1XC1Ev
   // CHECK: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x)
-  // CHECK: call i32 @__cxa_atexit
+  // CHECK-NEXT: call i32 @__cxa_atexit
   // CHECK: br
   static X x;
+
+  // CHECK: call i8* @__cxa_allocate_exception
+  // CHECK: invoke void @__cxa_throw
+  throw Y();
+
+  // Finally, the landing pad.
   // CHECK: call i8* @llvm.eh.exception()
   // CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector
   // CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x)
   // CHECK: call void @_Unwind_Resume_or_Rethrow
   // CHECK: unreachable
-
-  // CHECK: call i8* @__cxa_allocate_exception
-  throw Y();
 }