[llvm] 0c1bb4f - [TableGen] New backend to print detailed records.

Paul C. Anagnostopoulos via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 2 07:23:47 PDT 2020


Author: Paul C. Anagnostopoulos
Date: 2020-10-02T10:22:13-04:00
New Revision: 0c1bb4f8851b87224f33abafbaae805942009a7f

URL: https://github.com/llvm/llvm-project/commit/0c1bb4f8851b87224f33abafbaae805942009a7f
DIFF: https://github.com/llvm/llvm-project/commit/0c1bb4f8851b87224f33abafbaae805942009a7f.diff

LOG: [TableGen] New backend to print detailed records.
Pertinent lints are fixed.

Added: 
    llvm/lib/TableGen/DetailedRecordsBackend.cpp

Modified: 
    llvm/docs/TableGen/BackGuide.rst
    llvm/include/llvm/Support/SourceMgr.h
    llvm/include/llvm/TableGen/Record.h
    llvm/lib/Support/SourceMgr.cpp
    llvm/lib/TableGen/CMakeLists.txt
    llvm/lib/TableGen/Main.cpp
    llvm/lib/TableGen/Record.cpp
    llvm/lib/TableGen/TableGenBackendSkeleton.cpp
    llvm/utils/TableGen/TableGen.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/TableGen/BackGuide.rst b/llvm/docs/TableGen/BackGuide.rst
index 3d7244053055..4ee5453f7292 100644
--- a/llvm/docs/TableGen/BackGuide.rst
+++ b/llvm/docs/TableGen/BackGuide.rst
@@ -690,11 +690,9 @@ Instances of the following classes can be printed using the ``<<`` operator:
 ``RecordVal``, and
 ``Init``.
 
-A constant and two helper functions are provided for producing the output
-file.  The constant ``MAX_LINE_LEN`` specifies the maximum length of output
-lines.  The helper function ``printLine`` prints a horizontal line comment.
-The helper function ``emitSourceFileHeader`` prints the header comment that
-should be included at the top of every output file.
+The helper function ``emitSourceFileHeader()`` prints the header comment
+that should be included at the top of every output file. A call to it is
+included in the skeleton backend file ``TableGenBackendSkeleton.cpp``.
 
 Printing Error Messages
 =======================
@@ -780,9 +778,53 @@ Classes are shown with their template arguments, parent classes (following
 fields. Note that anonymous records are named ``anonymous_0``,
 ``anonymous_1``, etc.
 
-
-
 The ``PrintDetailedRecords`` Backend
 ------------------------------------
 
-[to come]
+The TableGen command option ``--print-detailed-records`` invokes a backend
+that prints all the global variables, classes, and records defined in the
+source files. The output looks like this.
+
+.. code-block:: text
+
+  DETAILED RECORDS for file llvm-project\llvm\lib\target\arc\arc.td
+  
+  -------------------- Global Variables (5) --------------------
+  
+  AMDGPUBufferIntrinsics = [int_amdgcn_buffer_load_format, ...
+  AMDGPUImageDimAtomicIntrinsics = [int_amdgcn_image_atomic_swap_1d, ...
+  ...
+  -------------------- Classes (758) --------------------
+  
+  AMDGPUBufferLoad  |IntrinsicsAMDGPU.td:879|
+    Template args:
+      LLVMType AMDGPUBufferLoad:data_ty = llvm_any_ty  |IntrinsicsAMDGPU.td:879|
+    Superclasses: (SDPatternOperator) Intrinsic AMDGPURsrcIntrinsic
+    Fields:
+      list<SDNodeProperty> Properties = [SDNPMemOperand]  |Intrinsics.td:348|
+      string LLVMName = ""  |Intrinsics.td:343|
+  ...
+  -------------------- Records (12303) --------------------
+  
+  AMDGPUSample_lz_o  |IntrinsicsAMDGPU.td:560|
+    Defm sequence: |IntrinsicsAMDGPU.td:584| |IntrinsicsAMDGPU.td:566|
+    Superclasses: AMDGPUSampleVariant
+    Fields:
+      string UpperCaseMod = "_LZ_O"  |IntrinsicsAMDGPU.td:542|
+      string LowerCaseMod = "_lz_o"  |IntrinsicsAMDGPU.td:543|
+  ...
+
+* Global variables defined with outer ``defvar`` statements are shown with
+  their values.
+
+* The classes are shown with their source location, template arguments,
+  superclasses, and fields. 
+
+* The records are shown with their source location, ``defm`` sequence,
+  superclasses, and fields.
+
+Superclasses are shown in the order processed, with indirect superclasses in
+parentheses. Each field is shown with its value and the source location at
+which it was set.
+The ``defm`` sequence gives the locations of the ``defm`` statements that
+were involved in generating the record, in the order they were invoked.
\ No newline at end of file

diff  --git a/llvm/include/llvm/Support/SourceMgr.h b/llvm/include/llvm/Support/SourceMgr.h
index a0bd3ca2e0c1..28716b42f4ab 100644
--- a/llvm/include/llvm/Support/SourceMgr.h
+++ b/llvm/include/llvm/Support/SourceMgr.h
@@ -172,6 +172,11 @@ class SourceMgr {
   std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc,
                                                  unsigned BufferID = 0) const;
 
+  /// Get a string with the \p SMLoc filename and line number
+  /// formatted in the standard style.
+  std::string getFormattedLocationNoOffset(SMLoc Loc,
+                                           bool IncludePath = false) const;
+
   /// Given a line and column number in a mapped buffer, turn it into an SMLoc.
   /// This will return a null SMLoc if the line/column location is invalid.
   SMLoc FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,

diff  --git a/llvm/include/llvm/TableGen/Record.h b/llvm/include/llvm/TableGen/Record.h
index 1c46fce3f994..2a02093ba531 100644
--- a/llvm/include/llvm/TableGen/Record.h
+++ b/llvm/include/llvm/TableGen/Record.h
@@ -1518,7 +1518,10 @@ class Record {
     return SuperClasses;
   }
 
-  /// Append the direct super classes of this record to Classes.
+  /// Determine whether this record has the specified direct superclass.
+  bool hasDirectSuperClass(const Record *SuperClass) const;
+
+  /// Append the direct superclasses of this record to Classes.
   void getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const;
 
   bool isTemplateArg(Init *Name) const {
@@ -1710,19 +1713,27 @@ class RecordKeeper {
   friend class RecordRecTy;
 
   using RecordMap = std::map<std::string, std::unique_ptr<Record>, std::less<>>;
+  using GlobalMap = std::map<std::string, Init *, std::less<>>;
 
+  std::string InputFilename;
   RecordMap Classes, Defs;
   FoldingSet<RecordRecTy> RecordTypePool;
   std::map<std::string, Init *, std::less<>> ExtraGlobals;
   unsigned AnonCounter = 0;
 
 public:
+  /// Get the main TableGen input file's name.
+  const std::string getInputFilename() const { return InputFilename; }
+
   /// Get the map of classes.
   const RecordMap &getClasses() const { return Classes; }
 
   /// Get the map of records (defs).
   const RecordMap &getDefs() const { return Defs; }
 
+  /// Get the map of global variables.
+  const GlobalMap &getGlobals() const { return ExtraGlobals; }
+
   /// Get the class with the specified name.
   Record *getClass(StringRef Name) const {
     auto I = Classes.find(Name);
@@ -1743,6 +1754,10 @@ class RecordKeeper {
     return It == ExtraGlobals.end() ? nullptr : It->second;
   }
 
+  void saveInputFilename(std::string Filename) {
+    InputFilename = Filename;
+  }
+
   void addClass(std::unique_ptr<Record> R) {
     bool Ins = Classes.insert(std::make_pair(std::string(R->getName()),
                                              std::move(R))).second;
@@ -2017,6 +2032,7 @@ class HasReferenceResolver final : public Resolver {
   Init *resolve(Init *VarName) override;
 };
 
+void EmitDetailedRecords(RecordKeeper &RK, raw_ostream &OS);
 void EmitJSON(RecordKeeper &RK, raw_ostream &OS);
 
 } // end namespace llvm

diff  --git a/llvm/lib/Support/SourceMgr.cpp b/llvm/lib/Support/SourceMgr.cpp
index 9cc69732a964..e50cf5b4a834 100644
--- a/llvm/lib/Support/SourceMgr.cpp
+++ b/llvm/lib/Support/SourceMgr.cpp
@@ -180,7 +180,7 @@ std::pair<unsigned, unsigned>
 SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
   if (!BufferID)
     BufferID = FindBufferContainingLoc(Loc);
-  assert(BufferID && "Invalid Location!");
+  assert(BufferID && "Invalid location!");
 
   auto &SB = getBufferInfo(BufferID);
   const char *Ptr = Loc.getPointer();
@@ -193,6 +193,30 @@ SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
   return std::make_pair(LineNo, Ptr - BufStart - NewlineOffs);
 }
 
+// FIXME: Note that the formatting of source locations is spread between
+// multiple functions, some in SourceMgr and some in SMDiagnostic. A better
+// solution would be a general-purpose source location formatter
+// in one of those two classes, or possibly in SMLoc.
+
+/// Get a string with the source location formatted in the standard
+/// style, but without the line offset. If \p IncludePath is true, the path
+/// is included. If false, only the file name and extension are included.
+std::string SourceMgr::getFormattedLocationNoOffset(SMLoc Loc,
+                                                    bool IncludePath) const {
+  auto BufferID = FindBufferContainingLoc(Loc);
+  assert(BufferID && "Invalid location!");
+  auto FileSpec = getBufferInfo(BufferID).Buffer->getBufferIdentifier();
+
+  if (IncludePath) {
+    return FileSpec.str() + ":" + std::to_string(FindLineNumber(Loc, BufferID));
+  } else {
+    auto I = FileSpec.find_last_of("/\\");
+    I = (I == FileSpec.size()) ? 0 : (I + 1);
+    return FileSpec.substr(I).str() + ":" +
+           std::to_string(FindLineNumber(Loc, BufferID));
+  }
+}
+
 /// Given a line and column number in a mapped buffer, turn it into an SMLoc.
 /// This will return a null SMLoc if the line/column location is invalid.
 SMLoc SourceMgr::FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,

diff  --git a/llvm/lib/TableGen/CMakeLists.txt b/llvm/lib/TableGen/CMakeLists.txt
index 0a0a56c6285c..c8ccbe85e36c 100644
--- a/llvm/lib/TableGen/CMakeLists.txt
+++ b/llvm/lib/TableGen/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_llvm_component_library(LLVMTableGen
+  DetailedRecordsBackend.cpp
   Error.cpp
   JSONBackend.cpp
   Main.cpp

diff  --git a/llvm/lib/TableGen/DetailedRecordsBackend.cpp b/llvm/lib/TableGen/DetailedRecordsBackend.cpp
new file mode 100644
index 000000000000..1b6b675081ed
--- /dev/null
+++ b/llvm/lib/TableGen/DetailedRecordsBackend.cpp
@@ -0,0 +1,204 @@
+//===- DetailedRecordBackend.cpp - Detailed Records Report      -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This Tablegen backend prints a report that includes all the global 
+// variables, classes, and records in complete detail. It includes more
+// detail than the default TableGen printer backend.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+#include <algorithm>
+#include <set>
+#include <string>
+#include <vector>
+
+#define DEBUG_TYPE "detailed-records-backend"
+
+#define NL "\n"
+
+using namespace llvm;
+
+namespace {
+
+class DetailedRecordsEmitter {
+private:
+  RecordKeeper &Records;
+
+public:
+  DetailedRecordsEmitter(RecordKeeper &RK) : Records(RK) {}
+
+  void run(raw_ostream &OS);
+  void printReportHeading(raw_ostream &OS);
+  void printVariables(raw_ostream &OS);
+  void printClasses(raw_ostream &OS);
+  void printRecords(raw_ostream &OS);
+  void printSectionHeading(std::string Title, int Count, raw_ostream &OS);
+  void printDefms(Record *Rec, raw_ostream &OS);
+  void printTemplateArgs(Record *Rec, raw_ostream &OS);
+  void printSuperclasses(Record *Rec, raw_ostream &OS);
+  void printFields(Record *Rec, raw_ostream &OS);
+  std::string formatLocation(const SMLoc Loc);
+}; // emitter class
+
+} // anonymous namespace
+
+// Print the report.
+void DetailedRecordsEmitter::run(raw_ostream &OS) {
+  printReportHeading(OS);
+  printVariables(OS);
+  printClasses(OS);
+  printRecords(OS);
+}
+
+// Print the report heading, including the source file name.
+void DetailedRecordsEmitter::printReportHeading(raw_ostream &OS) {
+  OS << formatv("DETAILED RECORDS for file {0}\n", Records.getInputFilename());
+}
+
+// Print the global variables.
+void DetailedRecordsEmitter::printVariables(raw_ostream &OS) {
+  const auto GlobalList = Records.getGlobals();
+  printSectionHeading("Global Variables", GlobalList.size(), OS);
+
+  OS << NL;
+  for (const auto &Var : GlobalList) {
+    OS << Var.first << " = " << Var.second->getAsString() << NL;
+  }
+}
+
+// Print the classes, including the template arguments, superclasses,
+// and fields.
+void DetailedRecordsEmitter::printClasses(raw_ostream &OS) {
+  const auto &ClassList = Records.getClasses();
+  printSectionHeading("Classes", ClassList.size(), OS);
+
+  for (const auto &ClassPair : ClassList) {
+    auto *const Class = ClassPair.second.get();
+    OS << formatv("\n{0}  |{1}|\n", Class->getNameInitAsString(),
+                  SrcMgr.getFormattedLocationNoOffset(Class->getLoc().front()));
+    printTemplateArgs(Class, OS);
+    printSuperclasses(Class, OS);
+    printFields(Class, OS);
+  }
+}
+
+// Print the records, including the defm sequences, supercasses,
+// and fields.
+void DetailedRecordsEmitter::printRecords(raw_ostream &OS) {
+  const auto &RecordList = Records.getDefs();
+  printSectionHeading("Records", RecordList.size(), OS);
+
+  for (const auto &RecPair : RecordList) {
+    auto *const Rec = RecPair.second.get();
+    OS << formatv("\n{0}  |{1}|\n", Rec->getNameInitAsString(),
+                  SrcMgr.getFormattedLocationNoOffset(Rec->getLoc().front()));
+    printDefms(Rec, OS);
+    printSuperclasses(Rec, OS);
+    printFields(Rec, OS);
+  }
+}
+
+// Print a section heading with the name of the section and
+// the item count.
+void DetailedRecordsEmitter::printSectionHeading(std::string Title, int Count,
+                                                 raw_ostream &OS) {
+  OS << formatv("\n{0} {1} ({2}) {0}\n", "--------------------", Title, Count);
+}
+
+// Print the record's defm source locations, if any. Note that they
+// are stored in the reverse order of their invocation.
+void DetailedRecordsEmitter::printDefms(Record *Rec, raw_ostream &OS) {
+  const auto &LocList = Rec->getLoc();
+  if (LocList.size() < 2)
+    return;
+
+  OS << "  Defm sequence:";
+  for (unsigned I = LocList.size() - 1; I >= 1; --I) {
+    OS << formatv(" |{0}|", SrcMgr.getFormattedLocationNoOffset(LocList[I]));
+  }
+  OS << NL;
+}
+
+// Print the template arguments of a class.
+void DetailedRecordsEmitter::printTemplateArgs(Record *Rec,
+                                               raw_ostream &OS) {
+  ArrayRef<Init *> Args = Rec->getTemplateArgs();
+  if (Args.empty()) {
+    OS << "  Template args: (none)\n";
+    return;
+  }
+
+  OS << "  Template args:\n";
+  for (const Init *ArgName : Args) {
+    const RecordVal *Value = Rec->getValue(ArgName);
+    assert(Value && "Template argument value not found.");
+    OS << "    ";
+    Value->print(OS, false);
+    OS << formatv("  |{0}|", SrcMgr.getFormattedLocationNoOffset(Value->getLoc()));
+    OS << NL;
+  }
+}
+
+// Print the superclasses of a class or record. Indirect superclasses
+// are enclosed in parentheses.
+void DetailedRecordsEmitter::printSuperclasses(Record *Rec, raw_ostream &OS) {
+  ArrayRef<std::pair<Record *, SMRange>> Superclasses = Rec->getSuperClasses();
+  if (Superclasses.empty()) {
+    OS << "  Superclasses: (none)\n";
+    return;
+  }
+
+  OS << "  Superclasses:";
+  for (const auto &SuperclassPair : Superclasses) {
+    auto *ClassRec = SuperclassPair.first;
+    if (Rec->hasDirectSuperClass(ClassRec))
+      OS << formatv(" {0}", ClassRec->getNameInitAsString());
+    else
+      OS << formatv(" ({0})", ClassRec->getNameInitAsString());
+  }
+  OS << NL;
+}
+
+// Print the fields of a class or record, including their source locations.
+void DetailedRecordsEmitter::printFields(Record *Rec, raw_ostream &OS) {
+  const auto &ValueList = Rec->getValues();
+  if (ValueList.empty()) {
+    OS << "  Fields: (none)\n";
+    return;
+  }
+
+  OS << "  Fields:\n";
+  for (const RecordVal &Value : ValueList)
+    if (!Rec->isTemplateArg(Value.getNameInit())) {
+      OS << "    ";
+      Value.print(OS, false);
+      OS << formatv("  |{0}|\n",
+                    SrcMgr.getFormattedLocationNoOffset(Value.getLoc()));
+    }
+}
+
+namespace llvm {
+
+// This function is called by TableGen after parsing the files.
+
+void EmitDetailedRecords(RecordKeeper &RK, raw_ostream &OS) {
+  // Instantiate the emitter class and invoke run().
+  DetailedRecordsEmitter(RK).run(OS);
+}
+
+} // namespace llvm

diff  --git a/llvm/lib/TableGen/Main.cpp b/llvm/lib/TableGen/Main.cpp
index 77f1b61cf930..d7c73d2f6f02 100644
--- a/llvm/lib/TableGen/Main.cpp
+++ b/llvm/lib/TableGen/Main.cpp
@@ -90,6 +90,8 @@ int llvm::TableGenMain(const char *argv0, TableGenMainFn *MainFn) {
     return reportError(argv0, "Could not open input file '" + InputFilename +
                                   "': " + EC.message() + "\n");
 
+  Records.saveInputFilename(InputFilename);
+
   // Tell SrcMgr about this buffer, which is what TGParser will pick up.
   SrcMgr.AddNewSourceBuffer(std::move(*FileOrErr), SMLoc());
 

diff  --git a/llvm/lib/TableGen/Record.cpp b/llvm/lib/TableGen/Record.cpp
index ae8fe0316c42..260cca6b59e5 100644
--- a/llvm/lib/TableGen/Record.cpp
+++ b/llvm/lib/TableGen/Record.cpp
@@ -2144,12 +2144,27 @@ void Record::setName(Init *NewName) {
   // this.  See TGParser::ParseDef and TGParser::ParseDefm.
 }
 
+// NOTE for the next two functions:
+// Superclasses are in post-order, so the final one is a direct
+// superclass. All of its transitive superclases immediately precede it,
+// so we can step through the direct superclasses in reverse order.
+
+bool Record::hasDirectSuperClass(const Record *Superclass) const {
+  ArrayRef<std::pair<Record *, SMRange>> SCs = getSuperClasses();
+
+  for (int I = SCs.size() - 1; I >= 0; --I) {
+    const Record *SC = SCs[I].first;
+    if (SC == Superclass)
+      return true;
+    I -= SC->getSuperClasses().size();
+  }
+
+  return false;
+}
+
 void Record::getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const {
   ArrayRef<std::pair<Record *, SMRange>> SCs = getSuperClasses();
 
-  // Superclasses are in post-order, so the final one is a direct
-  // superclass. All of its transitive superclases immediately precede it,
-  // so we can step through the direct superclasses in reverse order.
   while (!SCs.empty()) {
     Record *SC = SCs.back().first;
     SCs = SCs.drop_back(1 + SC->getSuperClasses().size());

diff  --git a/llvm/lib/TableGen/TableGenBackendSkeleton.cpp b/llvm/lib/TableGen/TableGenBackendSkeleton.cpp
index bf1fccdee404..4ce88e003e65 100644
--- a/llvm/lib/TableGen/TableGenBackendSkeleton.cpp
+++ b/llvm/lib/TableGen/TableGenBackendSkeleton.cpp
@@ -41,9 +41,9 @@ class SkeletonEmitter {
   SkeletonEmitter(RecordKeeper &RK) : Records(RK) {}
 
   void run(raw_ostream &OS);
-}; // End emitter class.
+}; // emitter class
 
-} // End anonymous namespace.
+} // anonymous namespace
 
 void SkeletonEmitter::run(raw_ostream &OS) {
   emitSourceFileHeader("Skeleton data structures", OS);
@@ -61,4 +61,4 @@ void EmitSkeleton(RecordKeeper &RK, raw_ostream &OS) {
   SkeletonEmitter(RK).run(OS);
 }
 
-} // End llvm namespace.
+} // namespace llvm

diff  --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp
index 5215c30b707f..65e63ff487f5 100644
--- a/llvm/utils/TableGen/TableGen.cpp
+++ b/llvm/utils/TableGen/TableGen.cpp
@@ -21,6 +21,7 @@ using namespace llvm;
 
 enum ActionType {
   PrintRecords,
+  PrintDetailedRecords,
   DumpJSON,
   GenEmitter,
   GenRegisterInfo,
@@ -75,6 +76,8 @@ cl::opt<ActionType> Action(
     cl::values(
         clEnumValN(PrintRecords, "print-records",
                    "Print all records to stdout (default)"),
+        clEnumValN(PrintDetailedRecords, "print-detailed-records",
+                   "Print full details of all records to stdout"),
         clEnumValN(DumpJSON, "dump-json",
                    "Dump all records as machine-readable JSON"),
         clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"),
@@ -152,6 +155,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
   case PrintRecords:
     OS << Records;           // No argument, dump all contents
     break;
+  case PrintDetailedRecords:
+    EmitDetailedRecords(Records, OS);
+    break;
   case DumpJSON:
     EmitJSON(Records, OS);
     break;


        


More information about the llvm-commits mailing list