----- Original Message ----- > From: "Arnaud A. de Grandmaison" <[email protected]> > To: [email protected] > 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 > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits > -- Hal Finkel Assistant Computational Scientist Leadership Computing Facility Argonne National Laboratory _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
