Commit 6e24a465 authored by Arnaud A. de Grandmaison's avatar Arnaud A. de Grandmaison
Browse files

Revert "Emit lifetime.start / lifetime.end markers for unnamed temporary objects."

This commit did break the sanitizer-x86 bot. Revert it while
investigating.

llvm-svn: 213579
parent 63a2d07f
Loading
Loading
Loading
Loading
+24 −16
Original line number Diff line number Diff line
@@ -468,6 +468,22 @@ 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
@@ -786,9 +802,10 @@ static bool shouldUseMemSetPlusStoresToInitialize(llvm::Constant *Init,
}

/// Should we use the LLVM lifetime intrinsics for the given local variable?
bool CodeGenFunction::shouldUseLifetimeMarkers(unsigned Size) const {
static bool shouldUseLifetimeMarkers(CodeGenFunction &CGF, const VarDecl &D,
                                     unsigned Size) {
  // For now, only in optimized builds.
  if (CGM.getCodeGenOpts().OptimizationLevel == 0)
  if (CGF.CGM.getCodeGenOpts().OptimizationLevel == 0)
    return false;

  // Limit the size of marked objects to 32 bytes. We don't want to increase
@@ -798,6 +815,7 @@ bool CodeGenFunction::shouldUseLifetimeMarkers(unsigned Size) const {
  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.
@@ -807,18 +825,6 @@ void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) {
  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
@@ -914,11 +920,13 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
      // 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(size)) {
      if (HaveInsertPoint() && shouldUseLifetimeMarkers(*this, D, size)) {
        llvm::Value *sizeV = llvm::ConstantInt::get(Int64Ty, size);

        emission.SizeForLifetimeMarkers = sizeV;
        EmitLifetimeStart(sizeV, Alloc);
        llvm::Value *castAddr = Builder.CreateBitCast(Alloc, Int8PtrTy);
        Builder.CreateCall2(CGM.getLLVMLifetimeStartFn(), sizeV, castAddr)
          ->setDoesNotThrow();
      } else {
        assert(!emission.useLifetimeMarkers());
      }
+0 −25
Original line number Diff line number Diff line
@@ -353,17 +353,6 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(

  // 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.
@@ -374,20 +363,6 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
  } 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
+0 −37
Original line number Diff line number Diff line
@@ -436,23 +436,6 @@ 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();
@@ -1007,23 +990,6 @@ 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();
@@ -1707,9 +1673,6 @@ 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);

+0 −132
Original line number Diff line number Diff line
// 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);
}