r274385 - [Temporary, Lifetime] Add lifetime marks for temporaries

Tim Shen via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 1 14:08:47 PDT 2016


Author: timshen
Date: Fri Jul  1 16:08:47 2016
New Revision: 274385

URL: http://llvm.org/viewvc/llvm-project?rev=274385&view=rev
Log:
[Temporary, Lifetime] Add lifetime marks for temporaries

With all MaterializeTemporaryExprs coming with a ExprWithCleanups, it's
easy to add correct lifetime.end marks into the right RunCleanupsScope.

Differential Revision: http://reviews.llvm.org/D20499

Added:
    cfe/trunk/test/CodeGen/temporary-lifetime-exceptions.cpp
    cfe/trunk/test/CodeGen/temporary-lifetime.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGCleanup.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGExpr.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/lib/CodeGen/EHScopeStack.h
    cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp

Modified: cfe/trunk/lib/CodeGen/CGCleanup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCleanup.cpp?rev=274385&r1=274384&r2=274385&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCleanup.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCleanup.cpp Fri Jul  1 16:08:47 2016
@@ -188,6 +188,7 @@ void *EHScopeStack::pushCleanup(CleanupK
   bool IsNormalCleanup = Kind & NormalCleanup;
   bool IsEHCleanup = Kind & EHCleanup;
   bool IsActive = !(Kind & InactiveCleanup);
+  bool IsLifetimeMarker = Kind & LifetimeMarker;
   EHCleanupScope *Scope =
     new (Buffer) EHCleanupScope(IsNormalCleanup,
                                 IsEHCleanup,
@@ -200,6 +201,8 @@ void *EHScopeStack::pushCleanup(CleanupK
     InnermostNormalCleanup = stable_begin();
   if (IsEHCleanup)
     InnermostEHScope = stable_begin();
+  if (IsLifetimeMarker)
+    Scope->setLifetimeMarker();
 
   return Scope->getCleanupBuffer();
 }

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=274385&r1=274384&r2=274385&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Fri Jul  1 16:08:47 2016
@@ -529,19 +529,6 @@ namespace {
       CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args);
     }
   };
-
-  /// A cleanup to call @llvm.lifetime.end.
-  class CallLifetimeEnd final : public EHScopeStack::Cleanup {
-    llvm::Value *Addr;
-    llvm::Value *Size;
-  public:
-    CallLifetimeEnd(Address addr, llvm::Value *size)
-      : Addr(addr.getPointer()), Size(size) {}
-
-    void Emit(CodeGenFunction &CGF, Flags flags) override {
-      CGF.EmitLifetimeEnd(Size, Addr);
-    }
-  };
 } // end anonymous namespace
 
 /// EmitAutoVarWithLifetime - Does the setup required for an automatic
@@ -1406,13 +1393,10 @@ void CodeGenFunction::EmitAutoVarCleanup
 
   // Make sure we call @llvm.lifetime.end.  This needs to happen
   // *last*, so the cleanup needs to be pushed *first*.
-  if (emission.useLifetimeMarkers()) {
-    EHStack.pushCleanup<CallLifetimeEnd>(NormalAndEHCleanup,
+  if (emission.useLifetimeMarkers())
+    EHStack.pushCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker,
                                          emission.getAllocatedAddress(),
                                          emission.getSizeForLifetimeMarkers());
-    EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin());
-    cleanup.setLifetimeMarker();
-  }
 
   // Check the type for a cleanup.
   if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())

Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=274385&r1=274384&r2=274385&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExpr.cpp Fri Jul  1 16:08:47 2016
@@ -11,13 +11,14 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "CodeGenFunction.h"
 #include "CGCXXABI.h"
 #include "CGCall.h"
+#include "CGCleanup.h"
 #include "CGDebugInfo.h"
 #include "CGObjCRuntime.h"
 #include "CGOpenMPRuntime.h"
 #include "CGRecordLayout.h"
+#include "CodeGenFunction.h"
 #include "CodeGenModule.h"
 #include "TargetInfo.h"
 #include "clang/AST/ASTContext.h"
@@ -423,6 +424,23 @@ EmitMaterializeTemporaryExpr(const Mater
       EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
     }
   } else {
+    switch (M->getStorageDuration()) {
+    case SD_Automatic:
+    case SD_FullExpression:
+      if (auto *Size = EmitLifetimeStart(
+              CGM.getDataLayout().getTypeAllocSize(Object.getElementType()),
+              Object.getPointer())) {
+        if (M->getStorageDuration() == SD_Automatic)
+          pushCleanupAfterFullExpr<CallLifetimeEnd>(NormalEHLifetimeMarker,
+                                                    Object, Size);
+        else
+          pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, Object,
+                                               Size);
+      }
+      break;
+    default:
+      break;
+    }
     EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
   }
   pushTemporaryCleanup(*this, M, E, Object);

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=274385&r1=274384&r2=274385&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Jul  1 16:08:47 2016
@@ -302,6 +302,19 @@ public:
 
   llvm::Instruction *CurrentFuncletPad = nullptr;
 
+  class CallLifetimeEnd final : public EHScopeStack::Cleanup {
+    llvm::Value *Addr;
+    llvm::Value *Size;
+
+  public:
+    CallLifetimeEnd(Address addr, llvm::Value *size)
+        : Addr(addr.getPointer()), Size(size) {}
+
+    void Emit(CodeGenFunction &CGF, Flags flags) override {
+      CGF.EmitLifetimeEnd(Size, Addr);
+    }
+  };
+
   /// Header for data within LifetimeExtendedCleanupStack.
   struct LifetimeExtendedCleanupHeader {
     /// The size of the following cleanup object.

Modified: cfe/trunk/lib/CodeGen/EHScopeStack.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/EHScopeStack.h?rev=274385&r1=274384&r2=274385&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/EHScopeStack.h (original)
+++ cfe/trunk/lib/CodeGen/EHScopeStack.h Fri Jul  1 16:08:47 2016
@@ -89,7 +89,10 @@ enum CleanupKind : unsigned {
   InactiveCleanup = 0x4,
   InactiveEHCleanup = EHCleanup | InactiveCleanup,
   InactiveNormalCleanup = NormalCleanup | InactiveCleanup,
-  InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup
+  InactiveNormalAndEHCleanup = NormalAndEHCleanup | InactiveCleanup,
+
+  LifetimeMarker = 0x8,
+  NormalEHLifetimeMarker = LifetimeMarker | NormalAndEHCleanup,
 };
 
 /// A stack of scopes which respond to exceptions, including cleanups

Added: cfe/trunk/test/CodeGen/temporary-lifetime-exceptions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/temporary-lifetime-exceptions.cpp?rev=274385&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/temporary-lifetime-exceptions.cpp (added)
+++ cfe/trunk/test/CodeGen/temporary-lifetime-exceptions.cpp Fri Jul  1 16:08:47 2016
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 %s -fexceptions -fcxx-exceptions -std=c++11 -O1 -triple x86_64 -emit-llvm -o - | FileCheck %s
+
+// lifetime.end should be invoked even if the destructor doesn't run due to an
+// exception thrown from previous ctor call.
+
+struct A { A(); ~A(); };
+A Baz(const A&);
+
+void Test1() {
+  // CHECK-LABEL: @_Z5Test1v(
+  // CHECK: getelementptr
+  // CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* [[TMP:[^ ]+]])
+  // CHECK-NEXT: getelementptr
+  // CHECK-NEXT: call void @llvm.lifetime.start(i64 1, i8* [[TMP1:[^ ]+]])
+
+  // Normal exit
+  // CHECK: call void @llvm.lifetime.end(i64 1, i8* [[TMP1]])
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* [[TMP]])
+
+  // Exception exit
+  // CHECK: call void @llvm.lifetime.end(i64 1, i8* [[TMP1]])
+  // CHECK-NEXT: call void @llvm.lifetime.end(i64 1, i8* [[TMP]])
+  Baz(Baz(A()));
+}

Added: cfe/trunk/test/CodeGen/temporary-lifetime.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/temporary-lifetime.cpp?rev=274385&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/temporary-lifetime.cpp (added)
+++ cfe/trunk/test/CodeGen/temporary-lifetime.cpp Fri Jul  1 16:08:47 2016
@@ -0,0 +1,165 @@
+// RUN: %clang_cc1 %s -std=c++11 -O1 -DWITH_DTOR -triple x86_64 -emit-llvm -o - | FileCheck -check-prefix=CHECK-DTOR %s
+// RUN: %clang_cc1 %s -std=c++11 -O1 -triple x86_64 -emit-llvm -o - | FileCheck -check-prefix=CHECK-NO-DTOR %s
+
+struct A {
+  A();
+#ifdef WITH_DTOR
+  ~A();
+#endif
+  char a[1024];
+  operator bool() const;
+};
+
+template <typename T>
+void Foo(T &&);
+
+template <typename T>
+void Bar(T &&);
+
+template <typename T>
+T Baz();
+
+void Test1() {
+  // CHECK-DTOR-LABEL: Test1
+  // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]])
+  // CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]])
+  // CHECK-DTOR: call void @_Z3FooIRK1AEvOT_
+  // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR]])
+  // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]])
+  // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]])
+  // CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]])
+  // CHECK-DTOR: call void @_Z3FooIRK1AEvOT_
+  // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR]])
+  // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]])
+  // CHECK-DTOR: }
+
+  // CHECK-NO-DTOR-LABEL: Test1
+  // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]])
+  // CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]])
+  // CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_
+  // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]])
+  // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]])
+  // CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR:[^ ]+]])
+  // CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_
+  // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]])
+  // CHECK-NO-DTOR: }
+  {
+    const A &a = A{};
+    Foo(a);
+  }
+  {
+    const A &a = A{};
+    Foo(a);
+  }
+}
+
+void Test2() {
+  // CHECK-DTOR-LABEL: Test2
+  // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR1:[0-9]+]])
+  // CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR1:[^ ]+]])
+  // CHECK-DTOR: call void @_Z3FooIRK1AEvOT_
+  // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR2:[0-9]+]])
+  // CHECK-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR2:[^ ]+]])
+  // CHECK-DTOR: call void @_Z3FooIRK1AEvOT_
+  // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR2]])
+  // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR2]])
+  // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[VAR1]])
+  // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR1]])
+  // CHECK-DTOR: }
+
+  // CHECK-NO-DTOR-LABEL: Test2
+  // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR1:[0-9]+]])
+  // CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR1:[^ ]+]])
+  // CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_
+  // CHECK-NO-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR2:[0-9]+]])
+  // CHECK-NO-DTOR: call void @_ZN1AC1Ev(%struct.A* nonnull %[[VAR2:[^ ]+]])
+  // CHECK-NO-DTOR: call void @_Z3FooIRK1AEvOT_
+  // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR2]])
+  // CHECK-NO-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR1]])
+  // CHECK-NO-DTOR: }
+  const A &a = A{};
+  Foo(a);
+  const A &b = A{};
+  Foo(b);
+}
+
+void Test3() {
+  // CHECK-DTOR-LABEL: Test3
+  // CHECK-DTOR: entry:
+  // CHECK-DTOR: call void @llvm.lifetime.start
+  // CHECK-DTOR: call void @llvm.lifetime.start
+  // CHECK-DTOR: if.then:
+  // CHECK-DTOR: call void @llvm.lifetime.end
+  // CHECK-DTOR: cleanup{{.*}}:
+  // CHECK-DTOR: call void @llvm.lifetime.end
+  // CHECK-DTOR: cleanup{{.*}}:
+  // CHECK-DTOR: call void @llvm.lifetime.end
+  // CHECK-DTOR: }
+  const A &a = A{};
+  if (const A &b = A(a)) {
+    Foo(b);
+    return;
+  }
+  Bar(a);
+}
+
+void Test4() {
+  // CHECK-DTOR-LABEL: Test4
+  // CHECK-DTOR: entry:
+  // CHECK-DTOR: call void @llvm.lifetime.start
+  // CHECK-DTOR: for.cond.cleanup:
+  // CHECK-DTOR: call void @llvm.lifetime.end
+  // CHECK-DTOR: for.body:
+  // CHECK-DTOR: }
+  for (const A &a = A{}; a;) {
+    Foo(a);
+  }
+}
+
+int Test5() {
+  // CHECK-DTOR-LABEL: Test5
+  // CHECK-DTOR: call void @llvm.lifetime.start
+  // CHECK-DTOR: call i32 @_Z3BazIiET_v()
+  // CHECK-DTOR: store
+  // CHECK-DTOR: call void @_Z3FooIRKiEvOT_
+  // CHECK-DTOR: load
+  // CHECK-DTOR: call void @llvm.lifetime.end
+  // CHECK-DTOR: }
+  const int &a = Baz<int>();
+  Foo(a);
+  return a;
+}
+
+void Test6() {
+  // CHECK-DTOR-LABEL: Test6
+  // CHECK-DTOR: call void @llvm.lifetime.start(i64 {{[0-9]+}}, i8* %[[ADDR:[0-9]+]])
+  // CHECK-DTOR: call i32 @_Z3BazIiET_v()
+  // CHECK-DTOR: store
+  // CHECK-DTOR: call void @_Z3FooIiEvOT_
+  // CHECK-DTOR: call void @llvm.lifetime.end(i64 {{[0-9]+}}, i8* %[[ADDR]])
+  // CHECK-DTOR: call void @llvm.lifetime.start(i64 {{[0-9]+}}, i8* %[[ADDR:[0-9]+]])
+  // CHECK-DTOR: call i32 @_Z3BazIiET_v()
+  // CHECK-DTOR: store
+  // CHECK-DTOR: call void @_Z3FooIiEvOT_
+  // CHECK-DTOR: call void @llvm.lifetime.end(i64 {{[0-9]+}}, i8* %[[ADDR]])
+  // CHECK-DTOR: }
+  Foo(Baz<int>());
+  Foo(Baz<int>());
+}
+
+void Test7() {
+  // CHECK-DTOR-LABEL: Test7
+  // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]])
+  // CHECK-DTOR: call void @_Z3BazI1AET_v({{.*}} %[[SLOT:[^ ]+]])
+  // CHECK-DTOR: call void @_Z3FooI1AEvOT_({{.*}} %[[SLOT]])
+  // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[SLOT]])
+  // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]])
+  // CHECK-DTOR: call void @llvm.lifetime.start(i64 1024, i8* %[[ADDR:[0-9]+]])
+  // CHECK-DTOR: call void @_Z3BazI1AET_v({{.*}} %[[SLOT:[^ ]+]])
+  // CHECK-DTOR: call void @_Z3FooI1AEvOT_({{.*}} %[[SLOT]])
+  // CHECK-DTOR: call void @_ZN1AD1Ev(%struct.A* nonnull %[[SLOT]])
+  // CHECK-DTOR: call void @llvm.lifetime.end(i64 1024, i8* %[[ADDR]])
+  // CHECK-DTOR: }
+  Foo(Baz<A>());
+  Foo(Baz<A>());
+}

Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp?rev=274385&r1=274384&r2=274385&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp Fri Jul  1 16:08:47 2016
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 %s
-// RUN: %clang_cc1 -std=c++11 -emit-llvm -O3 -disable-llvm-optzns %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 -check-prefix WIN32-LIFETIME %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 -check-prefix WIN32-O0 %s
+// RUN: %clang_cc1 -std=c++11 -emit-llvm -O3 -disable-llvm-optzns %s -o - -triple=i386-pc-win32 -mconstructor-aliases -fexceptions -fcxx-exceptions -fno-rtti | FileCheck -check-prefix WIN32 -check-prefix WIN32-O3 -check-prefix WIN32-LIFETIME %s
 
 struct A {
   A();
@@ -95,40 +95,78 @@ int HasConditionalDeactivatedCleanups(bo
   return (cond ? TakesTwo((TakeRef(A()), A()), (TakeRef(A()), A())) : CouldThrow());
 }
 
-// WIN32-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N at Z"{{.*}} {
-// WIN32:   alloca i1
-// WIN32:   %[[arg1_cond:.*]] = alloca i1
+// WIN32-O0-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N at Z"{{.*}} {
+// WIN32-O0:   alloca i1
+// WIN32-O0:   %[[arg1_cond:.*]] = alloca i1
 //        Start all four cleanups as deactivated.
-// WIN32:   store i1 false
-// WIN32:   store i1 false
-// WIN32:   store i1 false
-// WIN32:   store i1 false
-// WIN32:   br i1
+// WIN32-O0:   store i1 false
+// WIN32-O0:   store i1 false
+// WIN32-O0:   store i1 false
+// WIN32-O0:   store i1 false
+// WIN32-O0:   br i1
 //        True condition.
-// WIN32:   call x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
-// WIN32:   store i1 true
-// WIN32:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
-// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
-// WIN32:   store i1 true, i1* %[[arg1_cond]]
-// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
-// WIN32:   store i1 true
-// WIN32:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
-// WIN32:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
-// WIN32:   store i1 true
-// WIN32:   store i1 false, i1* %[[arg1_cond]]
-// WIN32:   invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
+// WIN32-O0:   call x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32-O0:   store i1 true
+// WIN32-O0:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32-O0:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32-O0:   store i1 true, i1* %[[arg1_cond]]
+// WIN32-O0:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32-O0:   store i1 true
+// WIN32-O0:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32-O0:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32-O0:   store i1 true
+// WIN32-O0:   store i1 false, i1* %[[arg1_cond]]
+// WIN32-O0:   invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
 //        False condition.
-// WIN32:   invoke i32 @"\01?CouldThrow@@YAHXZ"()
+// WIN32-O0:   invoke i32 @"\01?CouldThrow@@YAHXZ"()
 //        Two normal cleanups for TakeRef args.
-// WIN32:   call x86_thiscallcc void @"\01??1A@@QAE at XZ"({{.*}})
-// WIN32-NOT:   invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
-// WIN32:   ret i32
+// WIN32-O0:   call x86_thiscallcc void @"\01??1A@@QAE at XZ"({{.*}})
+// WIN32-O0-NOT:   invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
+// WIN32-O0:   ret i32
 //
 //        Somewhere in the landing pad soup, we conditionally destroy arg1.
-// WIN32:   %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]
-// WIN32:   br i1 %[[isactive]]
-// WIN32:   call x86_thiscallcc void @"\01??1A@@QAE at XZ"({{.*}})
-// WIN32: }
+// WIN32-O0:   %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]
+// WIN32-O0:   br i1 %[[isactive]]
+// WIN32-O0:   call x86_thiscallcc void @"\01??1A@@QAE at XZ"({{.*}})
+// WIN32-O0: }
+
+// WIN32-O3-LABEL: define i32 @"\01?HasConditionalDeactivatedCleanups@@YAH_N at Z"{{.*}} {
+// WIN32-O3:   alloca i1
+// WIN32-O3:   alloca i1
+// WIN32-O3:   %[[arg1_cond:.*]] = alloca i1
+//        Start all four cleanups as deactivated.
+// WIN32-O3:   store i1 false
+// WIN32-O3:   store i1 false
+// WIN32-O3:   store i1 false
+// WIN32-O3:   store i1 false
+// WIN32-O3:   store i1 false
+// WIN32-O3:   store i1 false
+// WIN32-O3:   br i1
+//        True condition.
+// WIN32-O3:   call x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32-O3:   store i1 true
+// WIN32-O3:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32-O3:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32-O3:   store i1 true, i1* %[[arg1_cond]]
+// WIN32-O3:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32-O3:   store i1 true
+// WIN32-O3:   invoke void @"\01?TakeRef@@YAXABUA@@@Z"
+// WIN32-O3:   invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE at XZ"
+// WIN32-O3:   store i1 true
+// WIN32-O3:   store i1 false, i1* %[[arg1_cond]]
+// WIN32-O3:   invoke i32 @"\01?TakesTwo@@YAHUA@@0 at Z"
+//        False condition.
+// WIN32-O3:   invoke i32 @"\01?CouldThrow@@YAHXZ"()
+//        Two normal cleanups for TakeRef args.
+// WIN32-O3:   call x86_thiscallcc void @"\01??1A@@QAE at XZ"({{.*}})
+// WIN32-O3-NOT:   invoke x86_thiscallcc void @"\01??1A@@QAE at XZ"
+// WIN32-O3:   ret i32
+//
+//        Somewhere in the landing pad soup, we conditionally destroy arg1.
+// WIN32-O3:   %[[isactive:.*]] = load i1, i1* %[[arg1_cond]]
+// WIN32-O3:   br i1 %[[isactive]]
+// WIN32-O3:   call x86_thiscallcc void @"\01??1A@@QAE at XZ"({{.*}})
+// WIN32-O3: }
 
 namespace crash_on_partial_destroy {
 struct A {




More information about the cfe-commits mailing list