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