]> granicus.if.org Git - clang/commitdiff
[clang] Add DISuprogram and DIE for a func decl
authorDjordje Todorovic <djordje.todorovic@rt-rk.com>
Thu, 27 Jun 2019 06:44:44 +0000 (06:44 +0000)
committerDjordje Todorovic <djordje.todorovic@rt-rk.com>
Thu, 27 Jun 2019 06:44:44 +0000 (06:44 +0000)
Attach a unique DISubprogram to a function declaration that will be
used for call site debug info.

([7/13] Introduce the debug entry values.)

Co-authored-by: Ananth Sowda <asowda@cisco.com>
Co-authored-by: Nikola Prica <nikola.prica@rt-rk.com>
Co-authored-by: Ivan Baev <ibaev@cisco.com>
Differential Revision: https://reviews.llvm.org/D60714

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@364502 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Decl.h
lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/CGDebugInfo.h
lib/CodeGen/CGExpr.cpp
test/CodeGen/debug-info-extern-call.c [new file with mode: 0644]

index ea272b114cfea6f3cb1c28d2af8f6ebc36c2395d..e593dafb5fc4da8e611f5d3e36486b72d9369c3f 100644 (file)
@@ -2396,6 +2396,8 @@ public:
 
   bool doesDeclarationForceExternallyVisibleDefinition() const;
 
+  bool isStatic() const { return getStorageClass() == SC_Static; }
+
   /// Whether this function declaration represents an C++ overloaded
   /// operator, e.g., "operator+".
   bool isOverloadedOperator() const {
index 2a701e04e17d8669011cf4794b1ff831ac496e54..f49d1ef8787cd1fb97eaa89c8c237d91f3abaa0a 100644 (file)
@@ -3619,7 +3619,7 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
 }
 
 void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
-                                   QualType FnType) {
+                                   QualType FnType, llvm::Function *Fn) {
   StringRef Name;
   StringRef LinkageName;
 
@@ -3629,7 +3629,9 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
 
   llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero;
   llvm::DIFile *Unit = getOrCreateFile(Loc);
-  llvm::DIScope *FDContext = getDeclContextDescriptor(D);
+  bool IsDeclForCallSite = Fn ? true : false;
+  llvm::DIScope *FDContext =
+      IsDeclForCallSite ? Unit : getDeclContextDescriptor(D);
   llvm::DINodeArray TParamsArray;
   if (isa<FunctionDecl>(D)) {
     // If there is a DISubprogram for this function available then use it.
@@ -3656,10 +3658,38 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
   if (CGM.getLangOpts().Optimize)
     SPFlags |= llvm::DISubprogram::SPFlagOptimized;
 
-  DBuilder.retainType(DBuilder.createFunction(
+  llvm::DISubprogram *SP = DBuilder.createFunction(
       FDContext, Name, LinkageName, Unit, LineNo,
       getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
-      TParamsArray.get(), getFunctionDeclaration(D)));
+      TParamsArray.get(), getFunctionDeclaration(D));
+
+  if (IsDeclForCallSite)
+    Fn->setSubprogram(SP);
+
+  DBuilder.retainType(SP);
+}
+
+void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
+                                          QualType CalleeType,
+                                          const FunctionDecl *CalleeDecl) {
+  auto &CGOpts = CGM.getCodeGenOpts();
+  if (!CGOpts.EnableDebugEntryValues || !CGM.getLangOpts().Optimize ||
+      !CallOrInvoke ||
+      CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo)
+    return;
+
+  auto *Func = CallOrInvoke->getCalledFunction();
+  if (!Func)
+    return;
+
+  // If there is no DISubprogram attached to the function being called,
+  // create the one describing the function in order to have complete
+  // call site debug info.
+  if (Func->getSubprogram())
+    return;
+
+  if (!CalleeDecl->isStatic() && !CalleeDecl->isInlined())
+    EmitFunctionDecl(CalleeDecl, CalleeDecl->getLocation(), CalleeType, Func);
 }
 
 void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) {
index e26088a63d0a47dea13a6dcb3cdfe68ebfa243d7..7edbea86633a39122a5d3382438218a724c5d82f 100644 (file)
@@ -409,7 +409,15 @@ public:
   void EmitInlineFunctionEnd(CGBuilderTy &Builder);
 
   /// Emit debug info for a function declaration.
-  void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, QualType FnType);
+  /// \p Fn is set only when a declaration for a debug call site gets created.
+  void EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,
+                        QualType FnType, llvm::Function *Fn = nullptr);
+
+  /// Emit debug info for an extern function being called.
+  /// This is needed for call site debug info.
+  void EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
+                               QualType CalleeType,
+                               const FunctionDecl *CalleeDecl);
 
   /// Constructs the debug code for exiting a function.
   void EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn);
index c2330e0844bae540873fb7125a6d82da6b511bed..abe10d383dcf79f6da637b899541d71abb811454 100644 (file)
@@ -4856,7 +4856,19 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee
     Callee.setFunctionPointer(CalleePtr);
   }
 
-  return EmitCall(FnInfo, Callee, ReturnValue, Args, nullptr, E->getExprLoc());
+  llvm::CallBase *CallOrInvoke = nullptr;
+  RValue Call = EmitCall(FnInfo, Callee, ReturnValue, Args, &CallOrInvoke,
+                         E->getExprLoc());
+
+  // Generate function declaration DISuprogram in order to be used
+  // in debug info about call sites.
+  if (CGDebugInfo *DI = getDebugInfo()) {
+    if (auto *CalleeDecl = dyn_cast_or_null<FunctionDecl>(TargetDecl))
+      DI->EmitFuncDeclForCallSite(CallOrInvoke, QualType(FnType, 0),
+                                  CalleeDecl);
+  }
+
+  return Call;
 }
 
 LValue CodeGenFunction::
diff --git a/test/CodeGen/debug-info-extern-call.c b/test/CodeGen/debug-info-extern-call.c
new file mode 100644 (file)
index 0000000..e35669b
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang -Xclang -femit-debug-entry-values -g -O2 -target x86_64-none-linux-gnu -S -emit-llvm %s -o - | FileCheck %s -check-prefix=CHECK-EXT
+// CHECK-EXT: !DISubprogram(name: "fn1"
+
+// RUN: %clang -g -O2 -target x86_64-none-linux-gnu -S -emit-llvm %s -o - | FileCheck %s
+// CHECK-NOT: !DISubprogram(name: "fn1"
+
+extern int fn1(int a, int b);
+
+int fn2 () {
+  int x = 4, y = 5;
+  int res = fn1(x, y);
+
+  return res;
+}
+