r213576 - Emit lifetime.start / lifetime.end markers for unnamed temporary objects.

Arnaud De Grandmaison Arnaud.DeGrandmaison at arm.com
Mon Jul 21 12:59:00 PDT 2014


Reverted it as it broke the sanitizer-x86 bot.

-----Original Message-----
From: Hal Finkel [mailto:hfinkel at anl.gov]
Sent: 21 July 2014 21:12
To: Arnaud De Grandmaison
Cc: cfe-commits at cs.uiuc.edu
Subject: Re: r213576 - Emit lifetime.start / lifetime.end markers for unnamed temporary objects.

----- 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?r
> ev=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?r
> ev=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/CodeGenFunct
> ion.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


-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium.  Thank you.

ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No:  2557590
ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No:  2548782




More information about the cfe-commits mailing list