aaboud updated this revision to Diff 82696.
aaboud added a comment.
Herald added subscribers: mgorny, nemanjai.

Improved code based on Richard's comments.
Removed the change to ASTConsumer, now it does not need to know anything about 
PP consumer.
However, I still needed to change the CodeGenerator ASTConsumer to return the 
CGDebugInfo class.

Richard, please review the new patch.
This time I made sure to add the "MacroPPCallbacks.*" new files.


https://reviews.llvm.org/D16135

Files:
  include/clang/CodeGen/ModuleBuilder.h
  lib/CodeGen/CGDebugInfo.cpp
  lib/CodeGen/CGDebugInfo.h
  lib/CodeGen/CMakeLists.txt
  lib/CodeGen/CodeGenAction.cpp
  lib/CodeGen/MacroPPCallbacks.cpp
  lib/CodeGen/MacroPPCallbacks.h
  lib/CodeGen/ModuleBuilder.cpp
  test/CodeGen/debug-info-global-constant.c

Index: lib/CodeGen/ModuleBuilder.cpp
===================================================================
--- lib/CodeGen/ModuleBuilder.cpp
+++ lib/CodeGen/ModuleBuilder.cpp
@@ -65,6 +65,7 @@
 
   private:
     SmallVector<CXXMethodDecl *, 8> DeferredInlineMethodDefinitions;
+    CGDebugInfo *DebugInfoRef;
 
   public:
     CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
@@ -74,7 +75,8 @@
                       CoverageSourceInfo *CoverageInfo = nullptr)
         : Diags(diags), Ctx(nullptr), HeaderSearchOpts(HSO),
           PreprocessorOpts(PPO), CodeGenOpts(CGO), HandlingTopLevelDecls(0),
-          CoverageInfo(CoverageInfo), M(new llvm::Module(ModuleName, C)) {
+          CoverageInfo(CoverageInfo), M(new llvm::Module(ModuleName, C)),
+          DebugInfoRef(nullptr) {
       C.setDiscardValueNames(CGO.DiscardValueNames);
     }
 
@@ -92,6 +94,10 @@
       return M.get();
     }
 
+    CGDebugInfo *&getModuleDebugInfoRef() {
+      return DebugInfoRef;
+    }
+
     llvm::Module *ReleaseModule() {
       return M.release();
     }
@@ -124,6 +130,9 @@
                                                PreprocessorOpts, CodeGenOpts,
                                                *M, Diags, CoverageInfo));
 
+      // Initialize the place holder for the CGDebugInfo.
+      DebugInfoRef = Builder->getModuleDebugInfo();
+
       for (auto &&Lib : CodeGenOpts.DependentLibraries)
         Builder->AddDependentLib(Lib);
       for (auto &&Opt : CodeGenOpts.LinkerOptions)
@@ -299,6 +308,10 @@
   return static_cast<CodeGeneratorImpl*>(this)->ReleaseModule();
 }
 
+CGDebugInfo *&CodeGenerator::getModuleDebugInfoRef() {
+  return static_cast<CodeGeneratorImpl*>(this)->getModuleDebugInfoRef();
+}
+
 const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) {
   return static_cast<CodeGeneratorImpl*>(this)->GetDeclForMangledName(name);
 }
Index: lib/CodeGen/MacroPPCallbacks.h
===================================================================
--- lib/CodeGen/MacroPPCallbacks.h
+++ lib/CodeGen/MacroPPCallbacks.h
@@ -0,0 +1,110 @@
+//===--- MacroPPCallbacks.h -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines implementation for the macro preprocessors callbacks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/PPCallbacks.h"
+
+namespace llvm {
+class DIMacroFile;
+class DIMacroNode;
+}
+namespace clang {
+class Preprocessor;
+class MacroInfo;
+
+namespace CodeGen {
+class CGDebugInfo;
+}
+
+class MacroPPCallbacks : public PPCallbacks {
+  /// A reference pointer to debug info code generator.
+  CodeGen::CGDebugInfo *&DebugInfo;
+
+  /// Preprocessor.
+  Preprocessor &PP;
+
+  /// Location of recent included file, used for line number.
+  SourceLocation LastHashLoc;
+
+  /// Location of main file, used for file info.
+  SourceLocation MainFileLoc;
+
+  /// Counts current number of command line included files, which was entered
+  /// and was not exited yet.
+  int CommandIncludeFiles;
+
+  enum FileScopeStatus {
+    NoScope,                  // Scope is not initialized yet.
+    InitializedScope,         // Main file scope is initialized but not set yet.
+    BuiltinScope,             // <built-in> file scope.
+    CommandLineScope,         // <command line> file scope.
+    CommandLineScopeIncludes, // Included file, from <command line> file, scope.
+    MainFileScope             // Main file scope.
+  };
+  FileScopeStatus Status;
+
+  /// Parent contains all entered files that were not exited yet according to
+  /// the inclusion order.
+  llvm::SmallVector<llvm::DIMacroFile *, 4> Scopes;
+
+  /// Get current DIMacroFile scope.
+  /// \return current DIMacroFile scope or nullptr if there is no such scope.
+  llvm::DIMacroFile *getCurrentScope();
+
+  /// Get current line location or invalid location.
+  /// \param Loc current line location.
+  /// \return current line location \p `Loc`, or invalid location if it's in a
+  ///         skipped file scope.
+  SourceLocation getCorrectLocation(SourceLocation Loc);
+
+  /// Use the passed preprocessor to calculate the macro name and value from
+  /// the given macro info and identifier info.
+  ///
+  /// \param II Identifier info, used to get the Macro name.
+  /// \param MI Macro info, used to get the Macro argumets and values.
+  /// \param PP Preprocessor.
+  /// \param [out] Name Place holder for returned macro name and arguments.
+  /// \param [out] Value Place holder for returned macro value.
+  static void calculatMacroDefinition(const IdentifierInfo &II,
+                                      const MacroInfo &MI, Preprocessor &PP,
+                                      raw_ostream &Name, raw_ostream &Value);
+
+public:
+  MacroPPCallbacks(CodeGen::CGDebugInfo *&DI, Preprocessor &PP);
+
+  /// Callback invoked whenever a source file is entered or exited.
+  ///
+  /// \param Loc Indicates the new location.
+  /// \param PrevFID the file that was exited if \p Reason is ExitFile.
+  void FileChanged(SourceLocation Loc, FileChangeReason Reason,
+                   SrcMgr::CharacteristicKind FileType,
+                   FileID PrevFID = FileID()) override;
+
+  /// Callback invoked whenever a directive (#xxx) is processed.
+  void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
+                          StringRef FileName, bool IsAngled,
+                          CharSourceRange FilenameRange, const FileEntry *File,
+                          StringRef SearchPath, StringRef RelativePath,
+                          const Module *Imported) override;
+
+  /// Hook called whenever a macro definition is seen.
+  void MacroDefined(const Token &MacroNameTok,
+                    const MacroDirective *MD) override;
+
+  /// Hook called whenever a macro \#undef is seen.
+  ///
+  /// MD is released immediately following this callback.
+  void MacroUndefined(const Token &MacroNameTok,
+                      const MacroDefinition &MD) override;
+};
+
+} // end namespace clang
Index: lib/CodeGen/CMakeLists.txt
===================================================================
--- lib/CodeGen/CMakeLists.txt
+++ lib/CodeGen/CMakeLists.txt
@@ -77,6 +77,7 @@
   CodeGenTypes.cpp
   CoverageMappingGen.cpp
   ItaniumCXXABI.cpp
+  MacroPPCallbacks.cpp
   MicrosoftCXXABI.cpp
   ModuleBuilder.cpp
   ObjectFilePCHContainerOperations.cpp
Index: lib/CodeGen/CGDebugInfo.h
===================================================================
--- lib/CodeGen/CGDebugInfo.h
+++ lib/CodeGen/CGDebugInfo.h
@@ -412,6 +412,15 @@
 
   void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
 
+  /// Get macro debug info.
+  llvm::DIMacro *CreateMacro(llvm::DIMacroFile *Parent, unsigned MType,
+                             SourceLocation LineLoc, StringRef Name,
+                             StringRef Value);
+
+  /// Get temporary macro file debug info.
+  llvm::DIMacroFile *CreateTempMacroFile(llvm::DIMacroFile *Parent,
+                                         SourceLocation LineLoc,
+                                         SourceLocation FileLoc);
 private:
   /// Emit call to llvm.dbg.declare for a variable declaration.
   void EmitDeclare(const VarDecl *decl, llvm::Value *AI,
Index: lib/CodeGen/CodeGenAction.cpp
===================================================================
--- lib/CodeGen/CodeGenAction.cpp
+++ lib/CodeGen/CodeGenAction.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "CoverageMappingGen.h"
+#include "MacroPPCallbacks.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclCXX.h"
@@ -40,6 +41,11 @@
 using namespace llvm;
 
 namespace clang {
+
+namespace CodeGen {
+class CGDebugInfo;
+}
+
   class BackendConsumer : public ASTConsumer {
     virtual void anchor();
     DiagnosticsEngine &Diags;
@@ -98,6 +104,10 @@
         I.second.release();
     }
 
+    CodeGen::CGDebugInfo *&getModuleDebugInfo() {
+      return Gen->getModuleDebugInfoRef();
+    }
+
     void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override {
       Gen->HandleCXXStaticMemberVarInstantiation(VD);
     }
@@ -812,6 +822,15 @@
       CI.getLangOpts(), CI.getFrontendOpts().ShowTimers, InFile, LinkModules,
       std::move(OS), *VMContext, CoverageInfo));
   BEConsumer = Result.get();
+
+  // Enable generating macro debug info only in FullDebugInfo mode.
+  if (CI.getCodeGenOpts().getDebugInfo() == codegenoptions::FullDebugInfo) {
+    std::unique_ptr<PPCallbacks> Callbacks =
+        llvm::make_unique<MacroPPCallbacks>(BEConsumer->getModuleDebugInfo(),
+                                            CI.getPreprocessor());
+    CI.getPreprocessor().addPPCallbacks(std::move(Callbacks));
+  }
+
   return std::move(Result);
 }
 
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp
+++ lib/CodeGen/CGDebugInfo.cpp
@@ -2408,6 +2408,22 @@
                                         FullName);
 }
 
+llvm::DIMacro *CGDebugInfo::CreateMacro(llvm::DIMacroFile *Parent,
+                                        unsigned MType, SourceLocation LineLoc,
+                                        StringRef Name, StringRef Value) {
+  unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
+  return DBuilder.createMacro(Parent, Line, MType, Name, Value);
+}
+
+llvm::DIMacroFile *CGDebugInfo::CreateTempMacroFile(llvm::DIMacroFile *Parent,
+                                                    SourceLocation LineLoc,
+                                                    SourceLocation FileLoc) {
+  llvm::DIFile *FName = getOrCreateFile(FileLoc);
+  unsigned Line = LineLoc.isInvalid() ? 0 : getLineNumber(LineLoc);
+  return DBuilder.createTempMacroFile(Parent, Line, FName,
+                                      llvm::DIMacroNodeArray());
+}
+
 static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) {
   Qualifiers Quals;
   do {
Index: lib/CodeGen/MacroPPCallbacks.cpp
===================================================================
--- lib/CodeGen/MacroPPCallbacks.cpp
+++ lib/CodeGen/MacroPPCallbacks.cpp
@@ -0,0 +1,189 @@
+//===--- MacroPPCallbacks.h -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file contains implementation for the macro preprocessors callbacks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MacroPPCallbacks.h"
+#include "CGDebugInfo.h"
+#include "clang/Parse/Parser.h"
+
+using namespace clang;
+
+void MacroPPCallbacks::calculatMacroDefinition(const IdentifierInfo &II,
+                                               const MacroInfo &MI,
+                                               Preprocessor &PP,
+                                               raw_ostream &Name,
+                                               raw_ostream &Value) {
+  Name << II.getName();
+
+  if (MI.isFunctionLike()) {
+    Name << '(';
+    if (!MI.arg_empty()) {
+      MacroInfo::arg_iterator AI = MI.arg_begin(), E = MI.arg_end();
+      for (; AI + 1 != E; ++AI) {
+        Name << (*AI)->getName();
+        Name << ',';
+      }
+
+      // Last argument.
+      if ((*AI)->getName() == "__VA_ARGS__")
+        Name << "...";
+      else
+        Name << (*AI)->getName();
+    }
+
+    if (MI.isGNUVarargs())
+      Name << "..."; // #define foo(x...)
+
+    Name << ')';
+  }
+
+  SmallString<128> SpellingBuffer;
+  bool First = true;
+  for (const auto &T : MI.tokens()) {
+    if (!First && T.hasLeadingSpace())
+      Value << ' ';
+
+    Value << PP.getSpelling(T, SpellingBuffer);
+    First = false;
+  }
+}
+
+MacroPPCallbacks::MacroPPCallbacks(CodeGen::CGDebugInfo *&DI, Preprocessor &PP)
+    : DebugInfo(DI), PP(PP), Status(NoScope),
+      // CommandIncludeFiles counts the number of currently processed files,
+      // which are included from command line. Initialized to zero.
+      CommandIncludeFiles(0) {}
+
+llvm::DIMacroFile *MacroPPCallbacks::getCurrentScope() {
+  switch (Status) {
+  default:
+    return nullptr;
+  case CommandLineScopeIncludes:
+  case MainFileScope:
+    return Scopes.back();
+  }
+}
+
+SourceLocation MacroPPCallbacks::getCorrectLocation(SourceLocation Loc) {
+  switch (Status) {
+  default:
+    break;
+  case CommandLineScopeIncludes:
+    if (!CommandIncludeFiles)
+      break;
+  // Fall though!
+  case MainFileScope:
+    return Loc;
+  }
+  // While parsing skipped files, location of macros is invalid.
+  // Invalid location represents line zero.
+  return SourceLocation();
+}
+
+void MacroPPCallbacks::FileChanged(SourceLocation Loc, FileChangeReason Reason,
+                                   SrcMgr::CharacteristicKind FileType,
+                                   FileID PrevFID) {
+  // Only care about enter file or exit file changes.
+  if (Reason != EnterFile && Reason != ExitFile)
+    return;
+
+  bool CreateMainFile = false;
+  bool CreateMacroFile = false;
+  bool PopScope = false;
+  SourceLocation LineLoc = getCorrectLocation(LastHashLoc);
+  switch (Status) {
+  case NoScope:
+    MainFileLoc = Loc;
+    Status = InitializedScope;
+    break;
+  case InitializedScope:
+    Status = BuiltinScope;
+    break;
+  case BuiltinScope:
+    Status = CommandLineScope;
+    break;
+  case CommandLineScope:
+    Status = CommandLineScopeIncludes;
+    CreateMainFile = true;
+    break;
+  case CommandLineScopeIncludes:
+    if (Reason == EnterFile) {
+      CommandIncludeFiles++;
+      CreateMacroFile = true;
+    } else if (Reason == ExitFile) {
+      if (!CommandIncludeFiles)
+        Status = MainFileScope;
+      else {
+        CommandIncludeFiles--;
+        PopScope = true;
+      }
+    }
+    break;
+  case MainFileScope:
+    if (Reason == EnterFile)
+      CreateMacroFile = true;
+    else if (Reason == ExitFile)
+      PopScope = true;
+    // No need to change status, already in the final status.
+    break;
+  }
+
+  if (CreateMainFile)
+    Scopes.push_back(
+        DebugInfo->CreateTempMacroFile(nullptr, LineLoc, MainFileLoc));
+  if (CreateMacroFile)
+    Scopes.push_back(
+        DebugInfo->CreateTempMacroFile(getCurrentScope(), LineLoc, Loc));
+  if (PopScope)
+    Scopes.pop_back();
+}
+
+void MacroPPCallbacks::InclusionDirective(
+    SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName,
+    bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File,
+    StringRef SearchPath, StringRef RelativePath, const Module *Imported) {
+  // Only care about "include" directives.
+  if (!IncludeTok.is(tok::identifier))
+    return;
+  auto PPKeywordID = IncludeTok.getIdentifierInfo()->getPPKeywordID();
+  switch (PPKeywordID) {
+  default:
+    return;
+  case tok::pp_include:
+  case tok::pp_include_next:
+  case tok::pp___include_macros:
+    break;
+  }
+
+  // Record the line location of the current included file.
+  LastHashLoc = HashLoc;
+}
+
+void MacroPPCallbacks::MacroDefined(const Token &MacroNameTok,
+                                    const MacroDirective *MD) {
+  IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
+  SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
+  std::string NameBuffer, ValueBuffer;
+  llvm::raw_string_ostream Name(NameBuffer);
+  llvm::raw_string_ostream Value(ValueBuffer);
+  calculatMacroDefinition(*Id, *MD->getMacroInfo(), PP, Name, Value);
+  DebugInfo->CreateMacro(getCurrentScope(), llvm::dwarf::DW_MACINFO_define,
+                         location, Name.str(), Value.str());
+}
+
+void MacroPPCallbacks::MacroUndefined(const Token &MacroNameTok,
+                                      const MacroDefinition &MD) {
+  IdentifierInfo *Id = MacroNameTok.getIdentifierInfo();
+  SourceLocation location = getCorrectLocation(MacroNameTok.getLocation());
+  DebugInfo->CreateMacro(getCurrentScope(), llvm::dwarf::DW_MACINFO_undef,
+                         location, Id->getName(), "");
+}
Index: include/clang/CodeGen/ModuleBuilder.h
===================================================================
--- include/clang/CodeGen/ModuleBuilder.h
+++ include/clang/CodeGen/ModuleBuilder.h
@@ -35,6 +35,7 @@
 
 namespace CodeGen {
   class CodeGenModule;
+  class CGDebugInfo;
 }
 
 /// The primary public interface to the Clang code generator.
@@ -65,6 +66,14 @@
   /// CodeGenerator after releasing its module.
   llvm::Module *ReleaseModule();
 
+  /// Return reference to CGDebugInfo place holder.
+  ///
+  /// This methods can be called before initializing the CGDebugInfo calss.
+  /// But the returned value should not be used until after initialization.
+  /// It is caller responsibility to validate that the place holder was
+  /// initialized before start using it.
+  CodeGen::CGDebugInfo *&CodeGenerator::getModuleDebugInfoRef();
+
   /// Given a mangled name, return a declaration which mangles that way
   /// which has been added to this code generator via a Handle method.
   ///
Index: test/CodeGen/debug-info-global-constant.c
===================================================================
--- test/CodeGen/debug-info-global-constant.c
+++ test/CodeGen/debug-info-global-constant.c
@@ -7,7 +7,7 @@
 // CHECK: @i = internal constant i32 1, align 4, !dbg ![[I:[0-9]+]]
 // CHECK: ![[I]] = !DIGlobalVariableExpression(var: ![[VAR:.*]], expr: ![[EXPR:[0-9]+]])
 // CHECK: ![[VAR]] = distinct !DIGlobalVariable(name: "i",
-// CHECK: !DICompileUnit({{.*}}globals: ![[GLOBALS:[0-9]+]])
+// CHECK: !DICompileUnit({{.*}}globals: ![[GLOBALS:[0-9]+]]
 // CHECK: ![[GLOBALS]] = !{![[I]]}
 // CHECK: ![[EXPR]] = !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)
 static const int i = 1;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D16135: Macro Debug In... Amjad Aboud via Phabricator via cfe-commits

Reply via email to