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