ahatanak updated this revision to Diff 82142.
ahatanak added a comment.

Rebase and improve test cases.

- Add "-mllvm -disable-llvm-optzns" to the RUN line.
- Add a test case that shows lifetime.start of a variable isn't moved to the 
beginning of its scope when the goto leaves the scope.


https://reviews.llvm.org/D27680

Files:
  lib/CodeGen/CGDecl.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGStmt.cpp
  lib/CodeGen/CodeGenFunction.h
  test/CodeGen/lifetime2.c

Index: test/CodeGen/lifetime2.c
===================================================================
--- test/CodeGen/lifetime2.c
+++ test/CodeGen/lifetime2.c
@@ -1,4 +1,4 @@
-// RUN: %clang -S -emit-llvm -o - -O2 %s | FileCheck %s -check-prefixes=CHECK,O2
+// RUN: %clang -S -emit-llvm -o - -O2 -mllvm -disable-llvm-optzns %s | FileCheck %s -check-prefixes=CHECK,O2
 // RUN: %clang -S -emit-llvm -o - -O0 %s | FileCheck %s -check-prefixes=CHECK,O0
 
 extern int bar(char *A, int n);
@@ -19,11 +19,11 @@
 
 // CHECK-LABEL: @no_goto_bypass
 void no_goto_bypass() {
+  // O2: @llvm.lifetime.start(i64 5
   // O2: @llvm.lifetime.start(i64 1
   char x;
 l1:
   bar(&x, 1);
-  // O2: @llvm.lifetime.start(i64 5
   // O2: @llvm.lifetime.end(i64 5
   char y[5];
   bar(y, 5);
@@ -89,3 +89,58 @@
 L:
   bar(&x, 1);
 }
+
+// O2-LABEL: define i32 @move_lifetime_start
+// O2: %i = alloca i32, align 4
+// O2: %[[BITCAST:[0-9]+]] = bitcast i32* %i to i8*
+// O2: call void @llvm.lifetime.start(i64 4, i8* %[[BITCAST]])
+// O2: br label %[[DESTLABEL:[a-z0-9]+]]
+// O2: [[DESTLABEL]]:
+// O2: switch i32 %{{.*}}, label %{{.*}} [
+// O2-NEXT: i32 2, label %[[DESTLABEL]]
+
+extern void foo2(int p);
+
+int move_lifetime_start(int a) {
+  int *p = 0;
+label1:
+  if (p) {
+    foo2(*p);
+    return 0;
+  }
+
+  int i = 999;
+  if (a != 2) {
+    p = &i;
+    goto label1;
+  }
+  return -1;
+}
+
+// O2-LABEL: define i32 @dont_move_lifetime_start
+// O2: %i = alloca i32, align 4
+// O2: br label %[[DESTLABEL:[a-z0-9]+]]
+// O2: [[DESTLABEL]]:
+// O2: %[[BITCAST:[0-9]+]] = bitcast i32* %i to i8*
+// O2: call void @llvm.lifetime.start(i64 4, i8* %[[BITCAST]])
+// O2: switch i32 %{{.*}}, label %{{.*}} [
+// O2-NEXT: i32 0, label %{{.*}}
+// O2-NEXT: i32 2, label %[[DESTLABEL]]
+
+int dont_move_lifetime_start(int a) {
+  int *p = 0;
+label1:
+  {
+    if (p) {
+      foo2(*p);
+      return 0;
+    }
+
+    int i = 999;
+    if (a != 2) {
+      p = &i;
+      goto label1;
+    }
+  }
+  return -1;
+}
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -348,14 +348,20 @@
   class CallLifetimeEnd final : public EHScopeStack::Cleanup {
     llvm::Value *Addr;
     llvm::Value *Size;
+    llvm::CallInst *LifetimeStart;
 
   public:
-    CallLifetimeEnd(Address addr, llvm::Value *size)
-        : Addr(addr.getPointer()), Size(size) {}
+    CallLifetimeEnd(Address addr, llvm::Value *size,
+                    llvm::CallInst *lifetimeStart = nullptr)
+        : Addr(addr.getPointer()), Size(size), LifetimeStart(lifetimeStart) {}
 
     void Emit(CodeGenFunction &CGF, Flags flags) override {
       CGF.EmitLifetimeEnd(Size, Addr);
     }
+
+    llvm::CallInst *&getLifetimeStart() {
+      return LifetimeStart;
+    }
   };
 
   /// Header for data within LifetimeExtendedCleanupStack.
@@ -523,10 +529,10 @@
   /// \brief Enters a new scope for capturing cleanups, all of which
   /// will be executed once the scope is exited.
   class RunCleanupsScope {
-    EHScopeStack::stable_iterator CleanupStackDepth;
     size_t LifetimeExtendedCleanupStackSize;
     bool OldDidCallStackSave;
   protected:
+    EHScopeStack::stable_iterator CleanupStackDepth;
     bool PerformCleanup;
   private:
 
@@ -578,6 +584,7 @@
     SourceRange Range;
     SmallVector<const LabelDecl*, 4> Labels;
     LexicalScope *ParentScope;
+    llvm::BasicBlock *BB;
 
     LexicalScope(const LexicalScope &) = delete;
     void operator=(const LexicalScope &) = delete;
@@ -589,13 +596,27 @@
       CGF.CurLexicalScope = this;
       if (CGDebugInfo *DI = CGF.getDebugInfo())
         DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin());
+      CGF.EnsureInsertPoint();
+      BB = CGF.Builder.GetInsertBlock();
     }
 
     void addLabel(const LabelDecl *label) {
       assert(PerformCleanup && "adding label to dead scope?");
       Labels.push_back(label);
     }
 
+    EHScopeStack::stable_iterator getCleanupStackDepth() const {
+      return CleanupStackDepth;
+    }
+
+    llvm::BasicBlock *getBasicBlock() const {
+      return BB;
+    }
+
+    LexicalScope *getParentScope() const {
+      return ParentScope;
+    }
+
     /// \brief Exit this cleanup scope, emitting any accumulated
     /// cleanups.
     ~LexicalScope() {
@@ -620,6 +641,10 @@
         rescopeLabels();
     }
 
+    bool hasLabel(const LabelDecl *LD) const {
+      return llvm::is_contained(Labels, LD);
+    }
+
     void rescopeLabels();
   };
 
@@ -2184,7 +2209,7 @@
   void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType,
                         Address Ptr);
 
-  llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr);
+  llvm::CallInst *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr);
   void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr);
 
   llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
@@ -2313,27 +2338,30 @@
     bool IsConstantAggregate;
 
     /// Non-null if we should use lifetime annotations.
-    llvm::Value *SizeForLifetimeMarkers;
+    llvm::CallInst *LifetimeStart;
 
     struct Invalid {};
     AutoVarEmission(Invalid) : Variable(nullptr), Addr(Address::invalid()) {}
 
     AutoVarEmission(const VarDecl &variable)
       : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr),
-        IsByRef(false), IsConstantAggregate(false),
-        SizeForLifetimeMarkers(nullptr) {}
+        IsByRef(false), IsConstantAggregate(false), LifetimeStart(nullptr) {}
 
     bool wasEmittedAsGlobal() const { return !Addr.isValid(); }
 
   public:
     static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); }
 
     bool useLifetimeMarkers() const {
-      return SizeForLifetimeMarkers != nullptr;
+      return LifetimeStart != nullptr;
     }
     llvm::Value *getSizeForLifetimeMarkers() const {
+      return LifetimeStart->getOperand(0);
+    }
+
+    llvm::CallInst *getLifetimeStartMarker() const {
       assert(useLifetimeMarkers());
-      return SizeForLifetimeMarkers;
+      return LifetimeStart;
     }
 
     /// Returns the raw, allocated address, which is not necessarily
Index: lib/CodeGen/CGStmt.cpp
===================================================================
--- lib/CodeGen/CGStmt.cpp
+++ lib/CodeGen/CGStmt.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CodeGenFunction.h"
+#include "CGCleanup.h"
 #include "CGDebugInfo.h"
 #include "CodeGenModule.h"
 #include "TargetInfo.h"
@@ -558,14 +559,80 @@
   }
 }
 
+/// Move LifetimeStart to the beginning of lexical scope LS.
+static void moveLifetimeStart(llvm::CallInst *&LifetimeStart,
+                              CodeGenFunction::LexicalScope *LS,
+                              CodeGenFunction *CGF) {
+  llvm::BasicBlock *EntryBlock = &CGF->CurFn->getEntryBlock();
+  llvm::BasicBlock *BB = LS ? LS->getBasicBlock() : EntryBlock;
+  auto I = BB->begin();
+
+  // If BB is the entry block, move the lifetime marker to after the alloca
+  // insertion point.
+  if (BB == EntryBlock)
+    I = CGF->AllocaInsertPt->getIterator();
+
+  // Move the lifetime marker.
+  LifetimeStart->removeFromParent();
+  BB->getInstList().insertAfter(I, LifetimeStart);
+
+  // Move the bitcast instruction too.
+  auto *Ptr = cast<llvm::Instruction>(LifetimeStart->getOperand(1));
+  if (isa<llvm::BitCastInst>(Ptr)) {
+    assert(isa<llvm::AllocaInst>(cast<llvm::BitCastInst>(Ptr)->getOperand(0)) &&
+           "this should be a bitcast of an alloca");
+    Ptr->removeFromParent();
+    BB->getInstList().insertAfter(I, Ptr);
+  }
+
+  LifetimeStart = nullptr;
+}
+
 void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
   // If this code is reachable then emit a stop point (if generating
   // debug info). We have to do this ourselves because we are on the
   // "simple" statement path.
   if (HaveInsertPoint())
     EmitStopPoint(&S);
 
-  EmitBranchThroughCleanup(getJumpDestForLabel(S.getLabel()));
+  auto Dest = getJumpDestForLabel(S.getLabel());
+  auto JumpDestIdx = Dest.getScopeDepth();
+
+  // If we are compiling for C and the goto's destination label has been seen,
+  // move the lifetime.start markers.
+  if (!getLangOpts().CPlusPlus && JumpDestIdx.isValid()) {
+    LexicalScope *LS = CurLexicalScope;
+    auto SI = EHStack.getInnermostNormalCleanup();
+
+    // Search for the lexical scope enclosing the destination label. Note that
+    // LS will be null if the function body is the enclosing lexical scope.
+    while (LS) {
+      if (LS->hasLabel(S.getLabel()))
+        break;
+      SI = LS->getCleanupStackDepth();
+      LS = LS->getParentScope();
+    }
+
+    // Move all the lifetime.start markers of the scopes in range
+    // [SI, JumpDestIdx) to the beginning of the enclosing lexical scope.
+    while (SI != JumpDestIdx) {
+      auto *Scope = &cast<EHCleanupScope>(*EHStack.find(SI));
+      SI = Scope->getEnclosingNormalCleanup();
+
+      if (!Scope->isLifetimeMarker())
+        continue;
+
+      auto *C = static_cast<CallLifetimeEnd *>(Scope->getCleanup());
+      llvm::CallInst *&LifetimeStart = C->getLifetimeStart();
+
+      if (!LifetimeStart)
+        continue;
+
+      moveLifetimeStart(LifetimeStart, LS, this);
+    }
+  }
+
+  EmitBranchThroughCleanup(Dest);
 }
 
 
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -430,9 +430,10 @@
     switch (M->getStorageDuration()) {
     case SD_Automatic:
     case SD_FullExpression:
-      if (auto *Size = EmitLifetimeStart(
+      if (auto *LifetimeStart = EmitLifetimeStart(
               CGM.getDataLayout().getTypeAllocSize(Object.getElementType()),
               Object.getPointer())) {
+        auto *Size = LifetimeStart->getOperand(0);
         if (M->getStorageDuration() == SD_Automatic)
           pushCleanupAfterFullExpr<CallLifetimeEnd>(NormalEHLifetimeMarker,
                                                     Object, Size);
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -889,7 +889,7 @@
 /// Emit a lifetime.begin marker if some criteria are satisfied.
 /// \return a pointer to the temporary size Value if a marker was emitted, null
 /// otherwise
-llvm::Value *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
+llvm::CallInst *CodeGenFunction::EmitLifetimeStart(uint64_t Size,
                                                 llvm::Value *Addr) {
   if (!ShouldEmitLifetimeMarkers)
     return nullptr;
@@ -899,7 +899,7 @@
   llvm::CallInst *C =
       Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr});
   C->setDoesNotThrow();
-  return SizeV;
+  return C;
 }
 
 void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
@@ -1024,7 +1024,7 @@
         // them incorrectly placed.
         if (!Bypasses.IsBypassed(&D)) {
           uint64_t size = CGM.getDataLayout().getTypeAllocSize(allocaTy);
-          emission.SizeForLifetimeMarkers =
+          emission.LifetimeStart =
               EmitLifetimeStart(size, address.getPointer());
         }
       } else {
@@ -1374,7 +1374,8 @@
   if (emission.useLifetimeMarkers())
     EHStack.pushCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker,
                                          emission.getAllocatedAddress(),
-                                         emission.getSizeForLifetimeMarkers());
+                                         emission.getSizeForLifetimeMarkers(),
+                                         emission.getLifetimeStartMarker());
 
   // Check the type for a cleanup.
   if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to