r213576 - Emit lifetime.start / lifetime.end markers for unnamed temporary objects.
Hal Finkel
hfinkel at anl.gov
Mon Jul 21 12:11:55 PDT 2014
----- Original Message -----
> From: "Arnaud A. de Grandmaison" <arnaud.degrandmaison at arm.com>
> To: cfe-commits at cs.uiuc.edu
> Sent: Monday, July 21, 2014 1:54:21 PM
> Subject: r213576 - Emit lifetime.start / lifetime.end markers for unnamed temporary objects.
>
> Author: aadg
> Date: Mon Jul 21 13:54:21 2014
> New Revision: 213576
>
> URL: http://llvm.org/viewvc/llvm-project?rev=213576&view=rev
> Log:
> Emit lifetime.start / lifetime.end markers for unnamed temporary
> objects.
>
> This will give more information to the optimizers so that they can
> reuse stack slots.
Nice. What was wrong the first time?
-Hal
>
> Added:
> cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp
> Modified:
> cfe/trunk/lib/CodeGen/CGDecl.cpp
> cfe/trunk/lib/CodeGen/CGExpr.cpp
> cfe/trunk/lib/CodeGen/CodeGenFunction.h
>
> Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=213576&r1=213575&r2=213576&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Mon Jul 21 13:54:21 2014
> @@ -468,22 +468,6 @@ namespace {
> CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args);
> }
> };
> -
> - /// A cleanup to call @llvm.lifetime.end.
> - class CallLifetimeEnd : public EHScopeStack::Cleanup {
> - llvm::Value *Addr;
> - llvm::Value *Size;
> - public:
> - CallLifetimeEnd(llvm::Value *addr, llvm::Value *size)
> - : Addr(addr), Size(size) {}
> -
> - void Emit(CodeGenFunction &CGF, Flags flags) override {
> - llvm::Value *castAddr = CGF.Builder.CreateBitCast(Addr,
> CGF.Int8PtrTy);
> - CGF.Builder.CreateCall2(CGF.CGM.getLLVMLifetimeEndFn(),
> - Size, castAddr)
> - ->setDoesNotThrow();
> - }
> - };
> }
>
> /// EmitAutoVarWithLifetime - Does the setup required for an
> automatic
> @@ -802,10 +786,9 @@ static bool shouldUseMemSetPlusStoresToI
> }
>
> /// Should we use the LLVM lifetime intrinsics for the given local
> variable?
> -static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, const
> VarDecl &D,
> - unsigned Size) {
> +bool CodeGenFunction::shouldUseLifetimeMarkers(unsigned Size) const
> {
> // For now, only in optimized builds.
> - if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0)
> + if (CGM.getCodeGenOpts().OptimizationLevel == 0)
> return false;
>
> // Limit the size of marked objects to 32 bytes. We don't want to
> increase
> @@ -815,7 +798,6 @@ static bool shouldUseLifetimeMarkers(Cod
> return Size > SizeThreshold;
> }
>
> -
> /// EmitAutoVarDecl - Emit code and set up an entry in LocalDeclMap
> for a
> /// variable declaration with auto, register, or no storage class
> specifier.
> /// These turn into simple stack objects, or GlobalValues depending
> on target.
> @@ -825,6 +807,18 @@ void CodeGenFunction::EmitAutoVarDecl(co
> EmitAutoVarCleanups(emission);
> }
>
> +void CodeGenFunction::EmitLifetimeStart(llvm::Value *Size,
> llvm::Value *Addr) {
> + llvm::Value *castAddr = Builder.CreateBitCast(Addr, Int8PtrTy);
> + Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), Size, castAddr)
> + ->setDoesNotThrow();
> +}
> +
> +void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value
> *Addr) {
> + llvm::Value *castAddr = Builder.CreateBitCast(Addr, Int8PtrTy);
> + Builder.CreateCall2(CGM.getLLVMLifetimeEndFn(), Size, castAddr)
> + ->setDoesNotThrow();
> +}
> +
> /// EmitAutoVarAlloca - Emit the alloca and debug information for a
> /// local variable. Does not emit initialization or destruction.
> CodeGenFunction::AutoVarEmission
> @@ -920,13 +914,11 @@ CodeGenFunction::EmitAutoVarAlloca(const
> // Emit a lifetime intrinsic if meaningful. There's no point
> // in doing this if we don't have a valid insertion point (?).
> uint64_t size = CGM.getDataLayout().getTypeAllocSize(LTy);
> - if (HaveInsertPoint() && shouldUseLifetimeMarkers(*this, D,
> size)) {
> + if (HaveInsertPoint() && shouldUseLifetimeMarkers(size)) {
> llvm::Value *sizeV = llvm::ConstantInt::get(Int64Ty, size);
>
> emission.SizeForLifetimeMarkers = sizeV;
> - llvm::Value *castAddr = Builder.CreateBitCast(Alloc,
> Int8PtrTy);
> - Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), sizeV,
> castAddr)
> - ->setDoesNotThrow();
> + EmitLifetimeStart(sizeV, Alloc);
> } else {
> assert(!emission.useLifetimeMarkers());
> }
>
> Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=213576&r1=213575&r2=213576&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Mon Jul 21 13:54:21 2014
> @@ -353,6 +353,17 @@ LValue CodeGenFunction::EmitMaterializeT
>
> // Create and initialize the reference temporary.
> llvm::Value *Object = createReferenceTemporary(*this, M, E);
> +
> + uint64_t size =
> +
> CGM.getDataLayout().getTypeStoreSize(ConvertTypeForMem(E->getType()));
> + llvm::Value *sizeV = nullptr;
> + llvm::AllocaInst *Alloca = dyn_cast<llvm::AllocaInst>(Object);
> + bool useLifetimeMarkers = Alloca &&
> shouldUseLifetimeMarkers(size);
> + if (useLifetimeMarkers) {
> + sizeV = llvm::ConstantInt::get(Int64Ty, size);
> + EmitLifetimeStart(sizeV, Object);
> + }
> +
> if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object)) {
> // If the temporary is a global and has a constant initializer,
> we may
> // have already initialized it.
> @@ -363,6 +374,20 @@ LValue CodeGenFunction::EmitMaterializeT
> } else {
> EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
> }
> +
> + if (useLifetimeMarkers)
> + switch (M->getStorageDuration()) {
> + case SD_FullExpression:
> + EHStack.pushCleanup<CallLifetimeEnd>(NormalAndEHCleanup,
> Object, sizeV);
> + break;
> + case SD_Automatic:
> + pushCleanupAfterFullExpr<CallLifetimeEnd>(NormalAndEHCleanup,
> Object,
> + sizeV);
> + break;
> + default:
> + llvm_unreachable("unexpected storage duration for Lifetime
> markers");
> + }
> +
> pushTemporaryCleanup(*this, M, E, Object);
>
> // Perform derived-to-base casts and/or field accesses, to get
> from the
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=213576&r1=213575&r2=213576&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Jul 21 13:54:21 2014
> @@ -436,6 +436,23 @@ public:
> new (Buffer + sizeof(Header)) T(a0, a1, a2, a3);
> }
>
> + /// \brief Queue a cleanup to be pushed after finishing the
> current
> + /// full-expression.
> + template <class T, class A0, class A1>
> + void pushCleanupAfterFullExpr(CleanupKind Kind, A0 a0, A1 a1) {
> + assert(!isInConditionalBranch() && "can't defer conditional
> cleanup");
> +
> + LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind };
> +
> + size_t OldSize = LifetimeExtendedCleanupStack.size();
> + LifetimeExtendedCleanupStack.resize(
> + LifetimeExtendedCleanupStack.size() + sizeof(Header) +
> Header.Size);
> +
> + char *Buffer = &LifetimeExtendedCleanupStack[OldSize];
> + new (Buffer) LifetimeExtendedCleanupHeader(Header);
> + new (Buffer + sizeof(Header)) T(a0, a1);
> + }
> +
> /// Set up the last cleaup that was pushed as a conditional
> /// full-expression cleanup.
> void initFullExprCleanup();
> @@ -990,6 +1007,23 @@ private:
> void EmitOpenCLKernelMetadata(const FunctionDecl *FD,
> llvm::Function *Fn);
>
> + /// Should we use the LLVM lifetime intrinsics for a local
> variable of the
> + /// given size in bytes ?
> + bool shouldUseLifetimeMarkers(unsigned Size) const;
> +
> + /// A cleanup to call @llvm.lifetime.end.
> + class CallLifetimeEnd : public EHScopeStack::Cleanup {
> + llvm::Value *Addr;
> + llvm::Value *Size;
> + public:
> + CallLifetimeEnd(llvm::Value *addr, llvm::Value *size)
> + : Addr(addr), Size(size) {}
> +
> + void Emit(CodeGenFunction &CGF, Flags flags) override {
> + CGF.EmitLifetimeEnd(Size, Addr);
> + }
> + };
> +
> public:
> CodeGenFunction(CodeGenModule &cgm, bool
> suppressNewContext=false);
> ~CodeGenFunction();
> @@ -1673,6 +1707,9 @@ public:
> void EmitCXXTemporary(const CXXTemporary *Temporary, QualType
> TempType,
> llvm::Value *Ptr);
>
> + void EmitLifetimeStart(llvm::Value *Size, llvm::Value *Addr);
> + void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr);
> +
> llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
> void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
>
>
> Added: cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp?rev=213576&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp (added)
> +++ cfe/trunk/test/CodeGenCXX/unnamed-object-lifetime.cpp Mon Jul 21
> 13:54:21 2014
> @@ -0,0 +1,132 @@
> +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1 -o -
> %s | FileCheck %s
> +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm -O1
> -fcxx-exceptions -fexceptions -o - %s | FileCheck
> --check-prefix=CHECK-EH %s
> +
> +// Test lifetime marker generation for unnamed temporary objects.
> +
> +struct X {
> + X();
> + ~X();
> + char t[33]; // make the class big enough so that lifetime markers
> get inserted
> +};
> +
> +extern void useX(const X &);
> +
> +// CHECK-LABEL: define void @_Z6simplev
> +// CHECK-EH-LABEL: define void @_Z6simplev
> +void simple() {
> + // CHECK: [[ALLOCA:%.*]] = alloca %struct.X
> + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.X*
> [[ALLOCA]], i32 0, i32 0, i32 0
> + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[PTR]])
> + // CHECK-NEXT: call void @_ZN1XC1Ev
> + // CHECK-NEXT: call void @_Z4useXRK1X
> + // CHECK-NEXT: call void @_ZN1XD1Ev
> + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[PTR]])
> + //
> + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.X
> + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.X*
> [[ALLOCA]], i32 0, i32 0, i32 0
> + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[PTR]])
> + // CHECK-EH-NEXT: call void @_ZN1XC1Ev
> + // CHECK-EH: invoke void @_Z4useXRK1X
> + // CHECK-EH: invoke void @_ZN1XD1Ev
> + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]])
> + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[PTR]])
> + useX(X());
> +}
> +
> +struct Y {
> + Y(){}
> + ~Y(){}
> + char t[34]; // make the class big enough so that lifetime markers
> get inserted
> +};
> +
> +extern void useY(const Y &);
> +
> +// Check lifetime markers are inserted, despite Y's trivial
> constructor & destructor
> +// CHECK-LABEL: define void @_Z7trivialv
> +// CHECK-EH-LABEL: define void @_Z7trivialv
> +void trivial() {
> + // CHECK: [[ALLOCA:%.*]] = alloca %struct.Y
> + // CHECK: [[PTR:%.*]] = getelementptr inbounds %struct.Y*
> [[ALLOCA]], i32 0, i32 0, i32 0
> + // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[PTR]])
> + // CHECK-NEXT: call void @_Z4useYRK1Y
> + // CHECK-NEXT: call void @llvm.lifetime.end(i64 34, i8* [[PTR]])
> + //
> + // CHECK-EH: [[ALLOCA:%.*]] = alloca %struct.Y
> + // CHECK-EH: [[PTR:%.*]] = getelementptr inbounds %struct.Y*
> [[ALLOCA]], i32 0, i32 0, i32 0
> + // CHECK-EH: call void @llvm.lifetime.start(i64 34, i8* [[PTR]])
> + // CHECK-EH-NEXT: invoke void @_Z4useYRK1Y
> + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]])
> + // CHECK-EH: call void @llvm.lifetime.end(i64 34, i8* [[PTR]])
> + useY(Y());
> +}
> +
> +struct Z {
> + Z();
> + ~Z();
> + char t;
> +};
> +
> +extern void useZ(const Z &);
> +
> +// Check lifetime markers are not inserted if the unnamed object is
> too small
> +// CHECK-LABEL: define void @_Z8tooSmallv
> +// CHECK-EH-LABEL: define void @_Z8tooSmallv
> +void tooSmall() {
> + // CHECK-NOT: call void @llvm.lifetime.start
> + // CHECK: call void @_Z4useZRK1Z
> + // CHECK-NOT: call void @llvm.lifetime.end
> + // CHECK: ret
> + //
> + // CHECK-EH-NOT: call void @llvm.lifetime.start
> + // CHECK-EH: invoke void @_Z4useZRK1Z
> + // CHECK-EH-NOT: call void @llvm.lifetime.end
> + // CHECK-EH: ret
> + useZ(Z());
> +}
> +
> +// Check the lifetime are inserted at the right place in their
> respective scope
> +// CHECK-LABEL: define void @_Z6scopesv
> +void scopes() {
> + // CHECK: alloca %struct
> + // CHECK: alloca %struct
> + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[X:%.*]])
> + // CHECK: call void @llvm.lifetime.end(i64 33, i8* [[X]])
> + // CHECK: call void @llvm.lifetime.start(i64 34, i8* [[Y:%.*]])
> + // CHECK: call void @llvm.lifetime.end(i64 34, i8* [[Y]])
> + useX(X());
> + useY(Y());
> +}
> +
> +struct L {
> + L(int);
> + ~L();
> + char t[33];
> +};
> +
> +// Check the lifetime-extended case
> +// CHECK-LABEL: define void @_Z16extendedLifetimev
> +void extendedLifetime() {
> + extern void useL(const L&);
> +
> + // CHECK: [[A:%.*]] = alloca %struct.L
> + // CHECK: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]], i32
> 0, i32 0, i32 0
> + // CHECK: call void @llvm.lifetime.start(i64 33, i8* [[P]])
> + // CHECK: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2)
> + // CHECK-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]])
> + // CHECK: call void @_Z4useLRK1L(%struct.L* dereferenceable(33)
> [[A]])
> + // CHECK: call void @_ZN1LD1Ev(%struct.L* [[A]])
> + // CHECK-NEXT: call void @llvm.lifetime.end(i64 33, i8* [[P]])
> + //
> + // CHECK-EH: [[A:%.*]] = alloca %struct.L
> + // CHECK-EH: [[P:%.*]] = getelementptr inbounds %struct.L* [[A]],
> i32 0, i32 0, i32 0
> + // CHECK-EH: call void @llvm.lifetime.start(i64 33, i8* [[P]])
> + // CHECK-EH: call void @_ZN1LC1Ei(%struct.L* [[A]], i32 2)
> + // CHECK-EH-NOT: call void @llvm.lifetime.end(i64 33, i8* [[P]])
> + // CHECK-EH: invoke void @_Z4useLRK1L(%struct.L*
> dereferenceable(33) [[A]])
> + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]])
> + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]])
> + // CHECK-EH: invoke void @_ZN1LD1Ev(%struct.L* [[A]])
> + // CHECK-EH: call void @llvm.lifetime.end(i64 33, i8* [[P]])
> + const L &l = 2;
> + useL(l);
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
--
Hal Finkel
Assistant Computational Scientist
Leadership Computing Facility
Argonne National Laboratory
More information about the cfe-commits
mailing list