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