r180932 - Ensure that the line table for functions with cleanups is sequential.

Adrian Prantl aprantl at apple.com
Thu May 2 10:30:21 PDT 2013


Author: adrian
Date: Thu May  2 12:30:20 2013
New Revision: 180932

URL: http://llvm.org/viewvc/llvm-project?rev=180932&view=rev
Log:
Ensure that the line table for functions with cleanups is sequential.

If there is cleanup code, the cleanup code gets the debug location of
the closing '}'. The subsequent ret IR-instruction does not get a
debug location. The return _expression_ will get the debug location
of the return statement.

If the function contains only a single, simple return statement,
the cleanup code may become the first breakpoint in the function.
In this case we set the debug location for the cleanup code
to the location of the return statement.

rdar://problem/13442648

Added:
    cfe/trunk/test/CodeGenObjC/arc-linetable.m
Modified:
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGenObjC/debug-info-block-line.m

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=180932&r1=180931&r2=180932&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Thu May  2 12:30:20 2013
@@ -1625,7 +1625,8 @@ static bool checkThisPointer(llvm::Value
   return false;
 }
 
-void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
+void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
+                                         bool EmitRetDbgLoc) {
   // Functions with no result always return void.
   if (ReturnValue == 0) {
     Builder.CreateRetVoid();
@@ -1670,8 +1671,10 @@ void CodeGenFunction::EmitFunctionEpilog
       // If there is a dominating store to ReturnValue, we can elide
       // the load, zap the store, and usually zap the alloca.
       if (llvm::StoreInst *SI = findDominatingStoreToReturnValue(*this)) {
+        // Reuse the debug location from the store unless we're told not to.
+        if (EmitRetDbgLoc)
+          RetDbgLoc = SI->getDebugLoc();
         // Get the stored value and nuke the now-dead store.
-        RetDbgLoc = SI->getDebugLoc();
         RV = SI->getValueOperand();
         SI->eraseFromParent();
 

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=180932&r1=180931&r2=180932&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Thu May  2 12:30:20 2013
@@ -37,6 +37,9 @@ void CodeGenFunction::EmitStopPoint(cons
     else
       Loc = S->getLocStart();
     DI->EmitLocation(Builder, Loc);
+
+    if (++NumStopPoints == 1)
+      FirstStopPoint = Loc;
   }
 }
 
@@ -839,6 +842,9 @@ void CodeGenFunction::EmitReturnStmt(con
     }
   }
 
+  if (RV == 0 || RV->isEvaluatable(getContext()))
+    ++NumSimpleReturnExprs;
+
   cleanupScope.ForceCleanup();
   EmitBranchThroughCleanup(ReturnBlock);
 }

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=180932&r1=180931&r2=180932&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu May  2 12:30:20 2013
@@ -44,6 +44,7 @@ CodeGenFunction::CodeGenFunction(CodeGen
     DebugInfo(0), DisableDebugInfo(false), CalleeWithThisReturn(0),
     DidCallStackSave(false),
     IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
+    NumStopPoints(0), NumSimpleReturnExprs(0),
     CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
     CXXDefaultInitExprThis(0),
     CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0),
@@ -187,16 +188,35 @@ void CodeGenFunction::FinishFunction(Sou
   assert(BreakContinueStack.empty() &&
          "mismatched push/pop in break/continue stack!");
 
-  if (CGDebugInfo *DI = getDebugInfo())
-    DI->EmitLocation(Builder, EndLoc);
+  // If the function contains only a single, simple return statement,
+  // the cleanup code may become the first breakpoint in the
+  // function. To be safe set the debug location for it to the
+  // location of the return statement.  Otherwise point it to end of
+  // the function's lexical scope.
+  if (CGDebugInfo *DI = getDebugInfo()) {
+    if (NumSimpleReturnExprs == 1 && NumStopPoints == 1)
+      DI->EmitLocation(Builder, FirstStopPoint);
+    else
+      DI->EmitLocation(Builder, EndLoc);
+  }
 
   // Pop any cleanups that might have been associated with the
   // parameters.  Do this in whatever block we're currently in; it's
   // important to do this before we enter the return block or return
   // edges will be *really* confused.
-  if (EHStack.stable_begin() != PrologueCleanupDepth)
+  bool EmitRetDbgLoc = true;
+  if (EHStack.stable_begin() != PrologueCleanupDepth) {
     PopCleanupBlocks(PrologueCleanupDepth);
 
+    // Make sure the line table doesn't jump back into the body for
+    // the ret after it's been at EndLoc.
+    EmitRetDbgLoc = false;
+
+    if (CGDebugInfo *DI = getDebugInfo())
+      if (NumSimpleReturnExprs == 1 && NumStopPoints == 1)
+        DI->EmitLocation(Builder, EndLoc);
+  }
+
   // Emit function epilog (to return).
   EmitReturnBlock();
 
@@ -208,7 +228,7 @@ void CodeGenFunction::FinishFunction(Sou
     DI->EmitFunctionEnd(Builder);
   }
 
-  EmitFunctionEpilog(*CurFnInfo);
+  EmitFunctionEpilog(*CurFnInfo, EmitRetDbgLoc);
   EmitEndEHSpec(CurCodeDecl);
 
   assert(EHStack.empty() &&

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=180932&r1=180931&r2=180932&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu May  2 12:30:20 2013
@@ -1206,6 +1206,15 @@ private:
   /// lazily by getUnreachableBlock().
   llvm::BasicBlock *UnreachableBlock;
 
+  /// Counts of the number of distinct breakpoint locations in this function.
+  unsigned NumStopPoints;
+
+  /// Count the number of simple (constant) return expressions in the function.
+  unsigned NumSimpleReturnExprs;
+
+  /// The first debug location (breakpoint) in the function.
+  SourceLocation FirstStopPoint;
+
 public:
   /// A scope within which we are constructing the fields of an object which
   /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use
@@ -1563,7 +1572,7 @@ public:
 
   /// EmitFunctionEpilog - Emit the target specific LLVM code to return the
   /// given temporary.
-  void EmitFunctionEpilog(const CGFunctionInfo &FI);
+  void EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc);
 
   /// EmitStartEHSpec - Emit the start of the exception spec.
   void EmitStartEHSpec(const Decl *D);

Added: cfe/trunk/test/CodeGenObjC/arc-linetable.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc-linetable.m?rev=180932&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc-linetable.m (added)
+++ cfe/trunk/test/CodeGenObjC/arc-linetable.m Thu May  2 12:30:20 2013
@@ -0,0 +1,101 @@
+// RUN: %clang_cc1 -emit-llvm -fblocks -fobjc-arc -g -triple x86_64-apple-darwin10 %s -o - | FileCheck %s
+
+// Legend: EXP = Return expression, RET = ret instruction
+
+// CHECK: define {{.*}}testNoSideEffect
+// CHECK: call void @objc_storeStrong{{.*}}
+// CHECK: call void @objc_storeStrong{{.*}} !dbg ![[ARC1:[0-9]+]]
+// CHECK: ret {{.*}} !dbg ![[RET1:[0-9]+]]
+
+// CHECK: define {{.*}}testNoCleanup
+// CHECK: ret {{.*}} !dbg ![[RET2:[0-9]+]]
+
+// CHECK: define {{.*}}testSideEffect
+// CHECK: @objc_msgSend{{.*}} !dbg ![[MSG3:[0-9]+]]
+// CHECK: ret {{.*}} !dbg ![[RET3:[0-9]+]]
+
+// CHECK: define {{.*}}testMultiline
+// CHECK: @objc_msgSend{{.*}} !dbg ![[MSG4:[0-9]+]]
+// CHECK: load{{.*}} !dbg ![[EXP4:[0-9]+]]
+// CHECK: ret {{.*}} !dbg ![[RET4:[0-9]+]]
+
+// CHECK: define {{.*}}testVoid
+// CHECK: call void @objc_storeStrong{{.*}}
+// CHECK: call void @objc_storeStrong{{.*}} !dbg ![[ARC5:[0-9]+]]
+// CHECK: ret {{.*}} !dbg ![[RET5:[0-9]+]]
+
+// CHECK: define {{.*}}testVoidNoReturn
+// CHECK: @objc_msgSend{{.*}} !dbg ![[MSG6:[0-9]+]]
+// CHECK: ret {{.*}} !dbg ![[RET6:[0-9]+]]
+
+// CHECK: define {{.*}}testNoCleanupSideEffect
+// CHECK: @objc_msgSend{{.*}} !dbg ![[MSG7:[0-9]+]]
+// CHECK: ret {{.*}} !dbg ![[RET7:[0-9]+]]
+
+
+ at interface NSObject
++ (id)alloc;
+- (id)init;
+- (id)retain;
+ at end
+
+ at class NSString;
+
+ at interface AppDelegate : NSObject
+
+ at end
+
+ at implementation AppDelegate : NSObject
+
+- (int)testNoSideEffect:(NSString *)foo {
+  // CHECK: ![[ARC1]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  return 1; // Return expression
+  // CHECK: ![[RET1]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+}           // Cleanup + Ret
+
+- (int)testNoCleanup {
+  // CHECK: ![[RET2]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  return 1;
+}
+
+- (int)testSideEffect:(NSString *)foo {
+  // CHECK: ![[MSG3]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  return [self testNoSideEffect :foo];
+  // CHECK: ![[RET3]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+}
+
+- (int)testMultiline:(NSString *)foo {
+  // CHECK: ![[MSG4]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  int r = [self testSideEffect :foo];
+  // CHECK: ![[EXP4]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  return r;
+  // CHECK: ![[RET4]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+}
+
+- (void)testVoid:(NSString *)foo {
+  // CHECK: ![[ARC5]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  return;
+  // CHECK: ![[RET5]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+}
+
+- (void)testVoidNoReturn:(NSString *)foo {
+  // CHECK: ![[MSG6]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  [self testVoid :foo];
+  // CHECK: ![[RET6]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+}
+
+- (int)testNoCleanupSideEffect {
+  // CHECK: ![[MSG7]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  [self testVoid :@"foo"];
+  // CHECK: ![[RET7]] = metadata !{i32 [[@LINE+1]], i32 0, metadata !{{.*}}, null}
+  return 1;
+}
+
+
+ at end
+
+
+int main(int argc, const char** argv) {
+  AppDelegate *o = [[AppDelegate alloc] init];
+  return [o testMultiline :@"foo"];
+}

Modified: cfe/trunk/test/CodeGenObjC/debug-info-block-line.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/debug-info-block-line.m?rev=180932&r1=180931&r2=180932&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/debug-info-block-line.m (original)
+++ cfe/trunk/test/CodeGenObjC/debug-info-block-line.m Thu May  2 12:30:20 2013
@@ -64,13 +64,16 @@ typedef enum : NSUInteger {
 // CHECK: define internal void @"__39-[TServer serverConnection:getCommand:]_block_invoke"
 // CHECK: call void @objc_storeStrong(i8** [[ZERO:%.*]], i8* [[ONE:%.*]]) [[NUW:#[0-9]+]]
 // CHECK: call void @objc_storeStrong(i8** [[TWO:%.*]], i8* [[THREE:%.*]]) [[NUW]]
+// CHECK: call {{.*}}@objc_msgSend{{.*}}, !dbg ![[LINE_ABOVE:[0-9]+]]
+// CHECK: getelementptr
+// CHECK-NOT: !dbg, ![[LINE_ABOVE]]
 // CHECK: bitcast %5** [[TMP:%.*]] to i8**
-// CHECK: call void @objc_storeStrong(i8** [[VAL1:%.*]], i8* null) [[NUW]], !dbg ![[MD1:.*]]
-// CHECK: bitcast %4** [[TMP:%.*]] to i8**
-// CHECK: call void @objc_storeStrong(i8** [[VAL2:%.*]], i8* null) [[NUW]], !dbg ![[MD1]]
+// CHECK-NOT: !dbg, ![[LINE_ABOVE]]
+// CHECK: call void @objc_storeStrong(i8** [[VAL1:%.*]], i8* null) [[NUW]]
+// CHECK-NEXT: bitcast %4** [[TMP:%.*]] to i8**
+// CHECK-NEXT: call void @objc_storeStrong(i8** [[VAL2:%.*]], i8* null) [[NUW]]
 // CHECK-NEXT: ret
 // CHECK: attributes [[NUW]] = { nounwind }
-// CHECK: ![[MD1]] = metadata !{i32 87
     [map dataWithCompletionBlock:^(NSData *data, NSError *error) {
         if (data) {
             NSString    *encoded = [[data compressedData] encodedString:18];





More information about the cfe-commits mailing list