Skip to content

Commit 0c1bb4f

Browse files
author
Paul C. Anagnostopoulos
committed
[TableGen] New backend to print detailed records.
Pertinent lints are fixed.
1 parent 36501b1 commit 0c1bb4f

File tree

10 files changed

+331
-16
lines changed

10 files changed

+331
-16
lines changed

llvm/docs/TableGen/BackGuide.rst

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -690,11 +690,9 @@ Instances of the following classes can be printed using the ``<<`` operator:
690690
``RecordVal``, and
691691
``Init``.
692692

693-
A constant and two helper functions are provided for producing the output
694-
file. The constant ``MAX_LINE_LEN`` specifies the maximum length of output
695-
lines. The helper function ``printLine`` prints a horizontal line comment.
696-
The helper function ``emitSourceFileHeader`` prints the header comment that
697-
should be included at the top of every output file.
693+
The helper function ``emitSourceFileHeader()`` prints the header comment
694+
that should be included at the top of every output file. A call to it is
695+
included in the skeleton backend file ``TableGenBackendSkeleton.cpp``.
698696

699697
Printing Error Messages
700698
=======================
@@ -780,9 +778,53 @@ Classes are shown with their template arguments, parent classes (following
780778
fields. Note that anonymous records are named ``anonymous_0``,
781779
``anonymous_1``, etc.
782780

783-
784-
785781
The ``PrintDetailedRecords`` Backend
786782
------------------------------------
787783

788-
[to come]
784+
The TableGen command option ``--print-detailed-records`` invokes a backend
785+
that prints all the global variables, classes, and records defined in the
786+
source files. The output looks like this.
787+
788+
.. code-block:: text
789+
790+
DETAILED RECORDS for file llvm-project\llvm\lib\target\arc\arc.td
791+
792+
-------------------- Global Variables (5) --------------------
793+
794+
AMDGPUBufferIntrinsics = [int_amdgcn_buffer_load_format, ...
795+
AMDGPUImageDimAtomicIntrinsics = [int_amdgcn_image_atomic_swap_1d, ...
796+
...
797+
-------------------- Classes (758) --------------------
798+
799+
AMDGPUBufferLoad |IntrinsicsAMDGPU.td:879|
800+
Template args:
801+
LLVMType AMDGPUBufferLoad:data_ty = llvm_any_ty |IntrinsicsAMDGPU.td:879|
802+
Superclasses: (SDPatternOperator) Intrinsic AMDGPURsrcIntrinsic
803+
Fields:
804+
list<SDNodeProperty> Properties = [SDNPMemOperand] |Intrinsics.td:348|
805+
string LLVMName = "" |Intrinsics.td:343|
806+
...
807+
-------------------- Records (12303) --------------------
808+
809+
AMDGPUSample_lz_o |IntrinsicsAMDGPU.td:560|
810+
Defm sequence: |IntrinsicsAMDGPU.td:584| |IntrinsicsAMDGPU.td:566|
811+
Superclasses: AMDGPUSampleVariant
812+
Fields:
813+
string UpperCaseMod = "_LZ_O" |IntrinsicsAMDGPU.td:542|
814+
string LowerCaseMod = "_lz_o" |IntrinsicsAMDGPU.td:543|
815+
...
816+
817+
* Global variables defined with outer ``defvar`` statements are shown with
818+
their values.
819+
820+
* The classes are shown with their source location, template arguments,
821+
superclasses, and fields.
822+
823+
* The records are shown with their source location, ``defm`` sequence,
824+
superclasses, and fields.
825+
826+
Superclasses are shown in the order processed, with indirect superclasses in
827+
parentheses. Each field is shown with its value and the source location at
828+
which it was set.
829+
The ``defm`` sequence gives the locations of the ``defm`` statements that
830+
were involved in generating the record, in the order they were invoked.

llvm/include/llvm/Support/SourceMgr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ class SourceMgr {
172172
std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc,
173173
unsigned BufferID = 0) const;
174174

175+
/// Get a string with the \p SMLoc filename and line number
176+
/// formatted in the standard style.
177+
std::string getFormattedLocationNoOffset(SMLoc Loc,
178+
bool IncludePath = false) const;
179+
175180
/// Given a line and column number in a mapped buffer, turn it into an SMLoc.
176181
/// This will return a null SMLoc if the line/column location is invalid.
177182
SMLoc FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,

llvm/include/llvm/TableGen/Record.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1518,7 +1518,10 @@ class Record {
15181518
return SuperClasses;
15191519
}
15201520

1521-
/// Append the direct super classes of this record to Classes.
1521+
/// Determine whether this record has the specified direct superclass.
1522+
bool hasDirectSuperClass(const Record *SuperClass) const;
1523+
1524+
/// Append the direct superclasses of this record to Classes.
15221525
void getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const;
15231526

15241527
bool isTemplateArg(Init *Name) const {
@@ -1710,19 +1713,27 @@ class RecordKeeper {
17101713
friend class RecordRecTy;
17111714

17121715
using RecordMap = std::map<std::string, std::unique_ptr<Record>, std::less<>>;
1716+
using GlobalMap = std::map<std::string, Init *, std::less<>>;
17131717

1718+
std::string InputFilename;
17141719
RecordMap Classes, Defs;
17151720
FoldingSet<RecordRecTy> RecordTypePool;
17161721
std::map<std::string, Init *, std::less<>> ExtraGlobals;
17171722
unsigned AnonCounter = 0;
17181723

17191724
public:
1725+
/// Get the main TableGen input file's name.
1726+
const std::string getInputFilename() const { return InputFilename; }
1727+
17201728
/// Get the map of classes.
17211729
const RecordMap &getClasses() const { return Classes; }
17221730

17231731
/// Get the map of records (defs).
17241732
const RecordMap &getDefs() const { return Defs; }
17251733

1734+
/// Get the map of global variables.
1735+
const GlobalMap &getGlobals() const { return ExtraGlobals; }
1736+
17261737
/// Get the class with the specified name.
17271738
Record *getClass(StringRef Name) const {
17281739
auto I = Classes.find(Name);
@@ -1743,6 +1754,10 @@ class RecordKeeper {
17431754
return It == ExtraGlobals.end() ? nullptr : It->second;
17441755
}
17451756

1757+
void saveInputFilename(std::string Filename) {
1758+
InputFilename = Filename;
1759+
}
1760+
17461761
void addClass(std::unique_ptr<Record> R) {
17471762
bool Ins = Classes.insert(std::make_pair(std::string(R->getName()),
17481763
std::move(R))).second;
@@ -2017,6 +2032,7 @@ class HasReferenceResolver final : public Resolver {
20172032
Init *resolve(Init *VarName) override;
20182033
};
20192034

2035+
void EmitDetailedRecords(RecordKeeper &RK, raw_ostream &OS);
20202036
void EmitJSON(RecordKeeper &RK, raw_ostream &OS);
20212037

20222038
} // end namespace llvm

llvm/lib/Support/SourceMgr.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ std::pair<unsigned, unsigned>
180180
SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
181181
if (!BufferID)
182182
BufferID = FindBufferContainingLoc(Loc);
183-
assert(BufferID && "Invalid Location!");
183+
assert(BufferID && "Invalid location!");
184184

185185
auto &SB = getBufferInfo(BufferID);
186186
const char *Ptr = Loc.getPointer();
@@ -193,6 +193,30 @@ SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
193193
return std::make_pair(LineNo, Ptr - BufStart - NewlineOffs);
194194
}
195195

196+
// FIXME: Note that the formatting of source locations is spread between
197+
// multiple functions, some in SourceMgr and some in SMDiagnostic. A better
198+
// solution would be a general-purpose source location formatter
199+
// in one of those two classes, or possibly in SMLoc.
200+
201+
/// Get a string with the source location formatted in the standard
202+
/// style, but without the line offset. If \p IncludePath is true, the path
203+
/// is included. If false, only the file name and extension are included.
204+
std::string SourceMgr::getFormattedLocationNoOffset(SMLoc Loc,
205+
bool IncludePath) const {
206+
auto BufferID = FindBufferContainingLoc(Loc);
207+
assert(BufferID && "Invalid location!");
208+
auto FileSpec = getBufferInfo(BufferID).Buffer->getBufferIdentifier();
209+
210+
if (IncludePath) {
211+
return FileSpec.str() + ":" + std::to_string(FindLineNumber(Loc, BufferID));
212+
} else {
213+
auto I = FileSpec.find_last_of("/\\");
214+
I = (I == FileSpec.size()) ? 0 : (I + 1);
215+
return FileSpec.substr(I).str() + ":" +
216+
std::to_string(FindLineNumber(Loc, BufferID));
217+
}
218+
}
219+
196220
/// Given a line and column number in a mapped buffer, turn it into an SMLoc.
197221
/// This will return a null SMLoc if the line/column location is invalid.
198222
SMLoc SourceMgr::FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,

llvm/lib/TableGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_llvm_component_library(LLVMTableGen
2+
DetailedRecordsBackend.cpp
23
Error.cpp
34
JSONBackend.cpp
45
Main.cpp
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
//===- DetailedRecordBackend.cpp - Detailed Records Report -*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This Tablegen backend prints a report that includes all the global
10+
// variables, classes, and records in complete detail. It includes more
11+
// detail than the default TableGen printer backend.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "llvm/ADT/ArrayRef.h"
16+
#include "llvm/ADT/DenseMap.h"
17+
#include "llvm/ADT/StringExtras.h"
18+
#include "llvm/Support/Format.h"
19+
#include "llvm/Support/FormatVariadic.h"
20+
#include "llvm/Support/MemoryBuffer.h"
21+
#include "llvm/Support/SourceMgr.h"
22+
#include "llvm/TableGen/Error.h"
23+
#include "llvm/TableGen/Record.h"
24+
#include "llvm/TableGen/TableGenBackend.h"
25+
#include <algorithm>
26+
#include <set>
27+
#include <string>
28+
#include <vector>
29+
30+
#define DEBUG_TYPE "detailed-records-backend"
31+
32+
#define NL "\n"
33+
34+
using namespace llvm;
35+
36+
namespace {
37+
38+
class DetailedRecordsEmitter {
39+
private:
40+
RecordKeeper &Records;
41+
42+
public:
43+
DetailedRecordsEmitter(RecordKeeper &RK) : Records(RK) {}
44+
45+
void run(raw_ostream &OS);
46+
void printReportHeading(raw_ostream &OS);
47+
void printVariables(raw_ostream &OS);
48+
void printClasses(raw_ostream &OS);
49+
void printRecords(raw_ostream &OS);
50+
void printSectionHeading(std::string Title, int Count, raw_ostream &OS);
51+
void printDefms(Record *Rec, raw_ostream &OS);
52+
void printTemplateArgs(Record *Rec, raw_ostream &OS);
53+
void printSuperclasses(Record *Rec, raw_ostream &OS);
54+
void printFields(Record *Rec, raw_ostream &OS);
55+
std::string formatLocation(const SMLoc Loc);
56+
}; // emitter class
57+
58+
} // anonymous namespace
59+
60+
// Print the report.
61+
void DetailedRecordsEmitter::run(raw_ostream &OS) {
62+
printReportHeading(OS);
63+
printVariables(OS);
64+
printClasses(OS);
65+
printRecords(OS);
66+
}
67+
68+
// Print the report heading, including the source file name.
69+
void DetailedRecordsEmitter::printReportHeading(raw_ostream &OS) {
70+
OS << formatv("DETAILED RECORDS for file {0}\n", Records.getInputFilename());
71+
}
72+
73+
// Print the global variables.
74+
void DetailedRecordsEmitter::printVariables(raw_ostream &OS) {
75+
const auto GlobalList = Records.getGlobals();
76+
printSectionHeading("Global Variables", GlobalList.size(), OS);
77+
78+
OS << NL;
79+
for (const auto &Var : GlobalList) {
80+
OS << Var.first << " = " << Var.second->getAsString() << NL;
81+
}
82+
}
83+
84+
// Print the classes, including the template arguments, superclasses,
85+
// and fields.
86+
void DetailedRecordsEmitter::printClasses(raw_ostream &OS) {
87+
const auto &ClassList = Records.getClasses();
88+
printSectionHeading("Classes", ClassList.size(), OS);
89+
90+
for (const auto &ClassPair : ClassList) {
91+
auto *const Class = ClassPair.second.get();
92+
OS << formatv("\n{0} |{1}|\n", Class->getNameInitAsString(),
93+
SrcMgr.getFormattedLocationNoOffset(Class->getLoc().front()));
94+
printTemplateArgs(Class, OS);
95+
printSuperclasses(Class, OS);
96+
printFields(Class, OS);
97+
}
98+
}
99+
100+
// Print the records, including the defm sequences, supercasses,
101+
// and fields.
102+
void DetailedRecordsEmitter::printRecords(raw_ostream &OS) {
103+
const auto &RecordList = Records.getDefs();
104+
printSectionHeading("Records", RecordList.size(), OS);
105+
106+
for (const auto &RecPair : RecordList) {
107+
auto *const Rec = RecPair.second.get();
108+
OS << formatv("\n{0} |{1}|\n", Rec->getNameInitAsString(),
109+
SrcMgr.getFormattedLocationNoOffset(Rec->getLoc().front()));
110+
printDefms(Rec, OS);
111+
printSuperclasses(Rec, OS);
112+
printFields(Rec, OS);
113+
}
114+
}
115+
116+
// Print a section heading with the name of the section and
117+
// the item count.
118+
void DetailedRecordsEmitter::printSectionHeading(std::string Title, int Count,
119+
raw_ostream &OS) {
120+
OS << formatv("\n{0} {1} ({2}) {0}\n", "--------------------", Title, Count);
121+
}
122+
123+
// Print the record's defm source locations, if any. Note that they
124+
// are stored in the reverse order of their invocation.
125+
void DetailedRecordsEmitter::printDefms(Record *Rec, raw_ostream &OS) {
126+
const auto &LocList = Rec->getLoc();
127+
if (LocList.size() < 2)
128+
return;
129+
130+
OS << " Defm sequence:";
131+
for (unsigned I = LocList.size() - 1; I >= 1; --I) {
132+
OS << formatv(" |{0}|", SrcMgr.getFormattedLocationNoOffset(LocList[I]));
133+
}
134+
OS << NL;
135+
}
136+
137+
// Print the template arguments of a class.
138+
void DetailedRecordsEmitter::printTemplateArgs(Record *Rec,
139+
raw_ostream &OS) {
140+
ArrayRef<Init *> Args = Rec->getTemplateArgs();
141+
if (Args.empty()) {
142+
OS << " Template args: (none)\n";
143+
return;
144+
}
145+
146+
OS << " Template args:\n";
147+
for (const Init *ArgName : Args) {
148+
const RecordVal *Value = Rec->getValue(ArgName);
149+
assert(Value && "Template argument value not found.");
150+
OS << " ";
151+
Value->print(OS, false);
152+
OS << formatv(" |{0}|", SrcMgr.getFormattedLocationNoOffset(Value->getLoc()));
153+
OS << NL;
154+
}
155+
}
156+
157+
// Print the superclasses of a class or record. Indirect superclasses
158+
// are enclosed in parentheses.
159+
void DetailedRecordsEmitter::printSuperclasses(Record *Rec, raw_ostream &OS) {
160+
ArrayRef<std::pair<Record *, SMRange>> Superclasses = Rec->getSuperClasses();
161+
if (Superclasses.empty()) {
162+
OS << " Superclasses: (none)\n";
163+
return;
164+
}
165+
166+
OS << " Superclasses:";
167+
for (const auto &SuperclassPair : Superclasses) {
168+
auto *ClassRec = SuperclassPair.first;
169+
if (Rec->hasDirectSuperClass(ClassRec))
170+
OS << formatv(" {0}", ClassRec->getNameInitAsString());
171+
else
172+
OS << formatv(" ({0})", ClassRec->getNameInitAsString());
173+
}
174+
OS << NL;
175+
}
176+
177+
// Print the fields of a class or record, including their source locations.
178+
void DetailedRecordsEmitter::printFields(Record *Rec, raw_ostream &OS) {
179+
const auto &ValueList = Rec->getValues();
180+
if (ValueList.empty()) {
181+
OS << " Fields: (none)\n";
182+
return;
183+
}
184+
185+
OS << " Fields:\n";
186+
for (const RecordVal &Value : ValueList)
187+
if (!Rec->isTemplateArg(Value.getNameInit())) {
188+
OS << " ";
189+
Value.print(OS, false);
190+
OS << formatv(" |{0}|\n",
191+
SrcMgr.getFormattedLocationNoOffset(Value.getLoc()));
192+
}
193+
}
194+
195+
namespace llvm {
196+
197+
// This function is called by TableGen after parsing the files.
198+
199+
void EmitDetailedRecords(RecordKeeper &RK, raw_ostream &OS) {
200+
// Instantiate the emitter class and invoke run().
201+
DetailedRecordsEmitter(RK).run(OS);
202+
}
203+
204+
} // namespace llvm

0 commit comments

Comments
 (0)