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