timshen created this revision.
timshen added a reviewer: rsmith.
timshen added a subscriber: cfe-commits.
With all MaterializeTemporaryExprs coming with a ExprWithCleanups, it's
easy to add correct lifetime.end marks into the right RunCleanupsScope.
http://reviews.llvm.org/D20499
Files:
lib/CodeGen/CGCleanup.cpp
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/EHScopeStack.h
test/CodeGen/temporary-lifetime.cpp
Index: test/CodeGen/temporary-lifetime.cpp
===================================================================
--- /dev/null
+++ test/CodeGen/temporary-lifetime.cpp
@@ -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>());
+}
Index: lib/CodeGen/EHScopeStack.h
===================================================================
--- lib/CodeGen/EHScopeStack.h
+++ lib/CodeGen/EHScopeStack.h
@@ -89,7 +89,10 @@
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
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -302,6 +302,19 @@
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.
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -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,7 +424,33 @@
EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
}
} else {
+ llvm::Value *Size = nullptr;
+ switch (M->getStorageDuration()) {
+ case SD_Automatic:
+ case SD_FullExpression:
+ Size = EmitLifetimeStart(
+ CGM.getDataLayout().getTypeAllocSize(Object.getElementType()),
+ Object.getPointer());
+ break;
+ default:
+ break;
+ }
EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
+ if (Size) {
+ switch (M->getStorageDuration()) {
+ case SD_Automatic:
+ pushCleanupAfterFullExpr<CallLifetimeEnd>(NormalEHLifetimeMarker,
+ Object, Size);
+ break;
+ case SD_FullExpression:
+ EHStack.pushCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, Object,
+ Size);
+ break;
+ default:
+ llvm_unreachable("Storage duration should be either SD_Automatic or "
+ "SD_FullExpression");
+ }
+ }
}
pushTemporaryCleanup(*this, M, E, Object);
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -528,19 +528,6 @@
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
@@ -1394,13 +1381,10 @@
// 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())
Index: lib/CodeGen/CGCleanup.cpp
===================================================================
--- lib/CodeGen/CGCleanup.cpp
+++ lib/CodeGen/CGCleanup.cpp
@@ -188,6 +188,7 @@
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 @@
InnermostNormalCleanup = stable_begin();
if (IsEHCleanup)
InnermostEHScope = stable_begin();
+ if (IsLifetimeMarker)
+ Scope->setLifetimeMarker();
return Scope->getCleanupBuffer();
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits