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