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