xref: /llvm-project/llvm/lib/TableGen/DetailedRecordsBackend.cpp (revision 62e2c7fb2d18b43149a07526f6a3c0563d50e2fa)
10c1bb4f8SPaul C. Anagnostopoulos //===- DetailedRecordBackend.cpp - Detailed Records Report      -*- C++ -*-===//
20c1bb4f8SPaul C. Anagnostopoulos //
30c1bb4f8SPaul C. Anagnostopoulos // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40c1bb4f8SPaul C. Anagnostopoulos // See https://llvm.org/LICENSE.txt for license information.
50c1bb4f8SPaul C. Anagnostopoulos // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60c1bb4f8SPaul C. Anagnostopoulos //
70c1bb4f8SPaul C. Anagnostopoulos //===----------------------------------------------------------------------===//
80c1bb4f8SPaul C. Anagnostopoulos //
90c1bb4f8SPaul C. Anagnostopoulos // This Tablegen backend prints a report that includes all the global
100c1bb4f8SPaul C. Anagnostopoulos // variables, classes, and records in complete detail. It includes more
110c1bb4f8SPaul C. Anagnostopoulos // detail than the default TableGen printer backend.
120c1bb4f8SPaul C. Anagnostopoulos //
130c1bb4f8SPaul C. Anagnostopoulos //===----------------------------------------------------------------------===//
140c1bb4f8SPaul C. Anagnostopoulos 
150c1bb4f8SPaul C. Anagnostopoulos #include "llvm/ADT/ArrayRef.h"
1692f49b89Sserge-sans-paille #include "llvm/ADT/StringRef.h"
1792f49b89Sserge-sans-paille #include "llvm/Support/ErrorHandling.h"
180c1bb4f8SPaul C. Anagnostopoulos #include "llvm/Support/FormatVariadic.h"
1992f49b89Sserge-sans-paille #include "llvm/Support/SMLoc.h"
200c1bb4f8SPaul C. Anagnostopoulos #include "llvm/Support/SourceMgr.h"
2192f49b89Sserge-sans-paille #include "llvm/Support/raw_ostream.h"
220c1bb4f8SPaul C. Anagnostopoulos #include "llvm/TableGen/Error.h"
230c1bb4f8SPaul C. Anagnostopoulos #include "llvm/TableGen/Record.h"
240c1bb4f8SPaul C. Anagnostopoulos #include <string>
25a03d09f4SSimon Pilgrim #include <utility>
260c1bb4f8SPaul C. Anagnostopoulos 
270c1bb4f8SPaul C. Anagnostopoulos using namespace llvm;
280c1bb4f8SPaul C. Anagnostopoulos 
290c1bb4f8SPaul C. Anagnostopoulos namespace {
300c1bb4f8SPaul C. Anagnostopoulos 
310c1bb4f8SPaul C. Anagnostopoulos class DetailedRecordsEmitter {
320c1bb4f8SPaul C. Anagnostopoulos private:
33bcde45baSRahul Joshi   const RecordKeeper &Records;
340c1bb4f8SPaul C. Anagnostopoulos 
350c1bb4f8SPaul C. Anagnostopoulos public:
36bcde45baSRahul Joshi   explicit DetailedRecordsEmitter(const RecordKeeper &RK) : Records(RK) {}
370c1bb4f8SPaul C. Anagnostopoulos 
380c1bb4f8SPaul C. Anagnostopoulos   void run(raw_ostream &OS);
390c1bb4f8SPaul C. Anagnostopoulos   void printReportHeading(raw_ostream &OS);
40bcde45baSRahul Joshi   void printSectionHeading(StringRef Title, int Count, raw_ostream &OS);
410c1bb4f8SPaul C. Anagnostopoulos   void printVariables(raw_ostream &OS);
420c1bb4f8SPaul C. Anagnostopoulos   void printClasses(raw_ostream &OS);
430c1bb4f8SPaul C. Anagnostopoulos   void printRecords(raw_ostream &OS);
4430f1cfb4SRahul Joshi   void printAllocationStats(raw_ostream &OS);
45bcde45baSRahul Joshi   void printDefms(const Record &Rec, raw_ostream &OS);
46bcde45baSRahul Joshi   void printTemplateArgs(const Record &Rec, raw_ostream &OS);
47bcde45baSRahul Joshi   void printSuperclasses(const Record &Rec, raw_ostream &OS);
48bcde45baSRahul Joshi   void printFields(const Record &Rec, raw_ostream &OS);
490c1bb4f8SPaul C. Anagnostopoulos }; // emitter class
500c1bb4f8SPaul C. Anagnostopoulos 
510c1bb4f8SPaul C. Anagnostopoulos } // anonymous namespace
520c1bb4f8SPaul C. Anagnostopoulos 
530c1bb4f8SPaul C. Anagnostopoulos // Print the report.
540c1bb4f8SPaul C. Anagnostopoulos void DetailedRecordsEmitter::run(raw_ostream &OS) {
550c1bb4f8SPaul C. Anagnostopoulos   printReportHeading(OS);
560c1bb4f8SPaul C. Anagnostopoulos   printVariables(OS);
570c1bb4f8SPaul C. Anagnostopoulos   printClasses(OS);
580c1bb4f8SPaul C. Anagnostopoulos   printRecords(OS);
5930f1cfb4SRahul Joshi   printAllocationStats(OS);
600c1bb4f8SPaul C. Anagnostopoulos }
610c1bb4f8SPaul C. Anagnostopoulos 
620c1bb4f8SPaul C. Anagnostopoulos // Print the report heading, including the source file name.
630c1bb4f8SPaul C. Anagnostopoulos void DetailedRecordsEmitter::printReportHeading(raw_ostream &OS) {
640c1bb4f8SPaul C. Anagnostopoulos   OS << formatv("DETAILED RECORDS for file {0}\n", Records.getInputFilename());
650c1bb4f8SPaul C. Anagnostopoulos }
660c1bb4f8SPaul C. Anagnostopoulos 
6730f1cfb4SRahul Joshi // Print a section heading with the name of the section and the item count.
68bcde45baSRahul Joshi void DetailedRecordsEmitter::printSectionHeading(StringRef Title, int Count,
69bcde45baSRahul Joshi                                                  raw_ostream &OS) {
70bcde45baSRahul Joshi   OS << formatv("\n{0} {1} ({2}) {0}\n", "--------------------", Title, Count);
71bcde45baSRahul Joshi }
72bcde45baSRahul Joshi 
730c1bb4f8SPaul C. Anagnostopoulos // Print the global variables.
740c1bb4f8SPaul C. Anagnostopoulos void DetailedRecordsEmitter::printVariables(raw_ostream &OS) {
750c1bb4f8SPaul C. Anagnostopoulos   const auto GlobalList = Records.getGlobals();
760c1bb4f8SPaul C. Anagnostopoulos   printSectionHeading("Global Variables", GlobalList.size(), OS);
770c1bb4f8SPaul C. Anagnostopoulos 
78bcde45baSRahul Joshi   OS << '\n';
79bcde45baSRahul Joshi   for (const auto &Var : GlobalList)
80bcde45baSRahul Joshi     OS << Var.first << " = " << Var.second->getAsString() << '\n';
810c1bb4f8SPaul C. Anagnostopoulos }
820c1bb4f8SPaul C. Anagnostopoulos 
8330f1cfb4SRahul Joshi // Print classes, including the template arguments, superclasses, and fields.
840c1bb4f8SPaul C. Anagnostopoulos void DetailedRecordsEmitter::printClasses(raw_ostream &OS) {
850c1bb4f8SPaul C. Anagnostopoulos   const auto &ClassList = Records.getClasses();
860c1bb4f8SPaul C. Anagnostopoulos   printSectionHeading("Classes", ClassList.size(), OS);
870c1bb4f8SPaul C. Anagnostopoulos 
88bcde45baSRahul Joshi   for (const auto &[Name, Class] : ClassList) {
890c1bb4f8SPaul C. Anagnostopoulos     OS << formatv("\n{0}  |{1}|\n", Class->getNameInitAsString(),
900c1bb4f8SPaul C. Anagnostopoulos                   SrcMgr.getFormattedLocationNoOffset(Class->getLoc().front()));
91bcde45baSRahul Joshi     printTemplateArgs(*Class, OS);
92bcde45baSRahul Joshi     printSuperclasses(*Class, OS);
93bcde45baSRahul Joshi     printFields(*Class, OS);
940c1bb4f8SPaul C. Anagnostopoulos   }
950c1bb4f8SPaul C. Anagnostopoulos }
960c1bb4f8SPaul C. Anagnostopoulos 
9730f1cfb4SRahul Joshi // Print the records, including the defm sequences, supercasses, and fields.
980c1bb4f8SPaul C. Anagnostopoulos void DetailedRecordsEmitter::printRecords(raw_ostream &OS) {
990c1bb4f8SPaul C. Anagnostopoulos   const auto &RecordList = Records.getDefs();
1000c1bb4f8SPaul C. Anagnostopoulos   printSectionHeading("Records", RecordList.size(), OS);
1010c1bb4f8SPaul C. Anagnostopoulos 
102bcde45baSRahul Joshi   for (const auto &[DefName, Rec] : RecordList) {
103f3449ed6SPaul C. Anagnostopoulos     std::string Name = Rec->getNameInitAsString();
104f3449ed6SPaul C. Anagnostopoulos     OS << formatv("\n{0}  |{1}|\n", Name.empty() ? "\"\"" : Name,
1050c1bb4f8SPaul C. Anagnostopoulos                   SrcMgr.getFormattedLocationNoOffset(Rec->getLoc().front()));
106bcde45baSRahul Joshi     printDefms(*Rec, OS);
107bcde45baSRahul Joshi     printSuperclasses(*Rec, OS);
108bcde45baSRahul Joshi     printFields(*Rec, OS);
1090c1bb4f8SPaul C. Anagnostopoulos   }
1100c1bb4f8SPaul C. Anagnostopoulos }
1110c1bb4f8SPaul C. Anagnostopoulos 
11230f1cfb4SRahul Joshi // Print memory allocation related stats.
11330f1cfb4SRahul Joshi void DetailedRecordsEmitter::printAllocationStats(raw_ostream &OS) {
11430f1cfb4SRahul Joshi   OS << formatv("\n{0} Memory Allocation Stats {0}\n", "--------------------");
11530f1cfb4SRahul Joshi   Records.dumpAllocationStats(OS);
11630f1cfb4SRahul Joshi }
11730f1cfb4SRahul Joshi 
1180c1bb4f8SPaul C. Anagnostopoulos // Print the record's defm source locations, if any. Note that they
1190c1bb4f8SPaul C. Anagnostopoulos // are stored in the reverse order of their invocation.
120bcde45baSRahul Joshi void DetailedRecordsEmitter::printDefms(const Record &Rec, raw_ostream &OS) {
121bcde45baSRahul Joshi   const auto &LocList = Rec.getLoc();
1220c1bb4f8SPaul C. Anagnostopoulos   if (LocList.size() < 2)
1230c1bb4f8SPaul C. Anagnostopoulos     return;
1240c1bb4f8SPaul C. Anagnostopoulos 
1250c1bb4f8SPaul C. Anagnostopoulos   OS << "  Defm sequence:";
126bcde45baSRahul Joshi   for (const SMLoc Loc : reverse(LocList))
127bcde45baSRahul Joshi     OS << formatv(" |{0}|", SrcMgr.getFormattedLocationNoOffset(Loc));
128bcde45baSRahul Joshi   OS << '\n';
1290c1bb4f8SPaul C. Anagnostopoulos }
1300c1bb4f8SPaul C. Anagnostopoulos 
1310c1bb4f8SPaul C. Anagnostopoulos // Print the template arguments of a class.
132bcde45baSRahul Joshi void DetailedRecordsEmitter::printTemplateArgs(const Record &Rec,
1330c1bb4f8SPaul C. Anagnostopoulos                                                raw_ostream &OS) {
134*62e2c7fbSRahul Joshi   ArrayRef<const Init *> Args = Rec.getTemplateArgs();
1350c1bb4f8SPaul C. Anagnostopoulos   if (Args.empty()) {
1360c1bb4f8SPaul C. Anagnostopoulos     OS << "  Template args: (none)\n";
1370c1bb4f8SPaul C. Anagnostopoulos     return;
1380c1bb4f8SPaul C. Anagnostopoulos   }
1390c1bb4f8SPaul C. Anagnostopoulos 
1400c1bb4f8SPaul C. Anagnostopoulos   OS << "  Template args:\n";
1410c1bb4f8SPaul C. Anagnostopoulos   for (const Init *ArgName : Args) {
142bcde45baSRahul Joshi     const RecordVal *Value = Rec.getValue(ArgName);
1430c1bb4f8SPaul C. Anagnostopoulos     assert(Value && "Template argument value not found.");
1440c1bb4f8SPaul C. Anagnostopoulos     OS << "    ";
1450c1bb4f8SPaul C. Anagnostopoulos     Value->print(OS, false);
146bcde45baSRahul Joshi     OS << formatv("  |{0}|\n",
147bcde45baSRahul Joshi                   SrcMgr.getFormattedLocationNoOffset(Value->getLoc()));
1480c1bb4f8SPaul C. Anagnostopoulos   }
1490c1bb4f8SPaul C. Anagnostopoulos }
1500c1bb4f8SPaul C. Anagnostopoulos 
1510c1bb4f8SPaul C. Anagnostopoulos // Print the superclasses of a class or record. Indirect superclasses
1520c1bb4f8SPaul C. Anagnostopoulos // are enclosed in parentheses.
153bcde45baSRahul Joshi void DetailedRecordsEmitter::printSuperclasses(const Record &Rec,
154bcde45baSRahul Joshi                                                raw_ostream &OS) {
15565e69f74SRahul Joshi   ArrayRef<std::pair<const Record *, SMRange>> Superclasses =
15665e69f74SRahul Joshi       Rec.getSuperClasses();
1570c1bb4f8SPaul C. Anagnostopoulos   if (Superclasses.empty()) {
1580c1bb4f8SPaul C. Anagnostopoulos     OS << "  Superclasses: (none)\n";
1590c1bb4f8SPaul C. Anagnostopoulos     return;
1600c1bb4f8SPaul C. Anagnostopoulos   }
1610c1bb4f8SPaul C. Anagnostopoulos 
1620c1bb4f8SPaul C. Anagnostopoulos   OS << "  Superclasses:";
163bcde45baSRahul Joshi   for (const auto &[ClassRec, Loc] : Superclasses) {
164bcde45baSRahul Joshi     if (Rec.hasDirectSuperClass(ClassRec))
1650c1bb4f8SPaul C. Anagnostopoulos       OS << formatv(" {0}", ClassRec->getNameInitAsString());
1660c1bb4f8SPaul C. Anagnostopoulos     else
1670c1bb4f8SPaul C. Anagnostopoulos       OS << formatv(" ({0})", ClassRec->getNameInitAsString());
1680c1bb4f8SPaul C. Anagnostopoulos   }
169bcde45baSRahul Joshi   OS << '\n';
1700c1bb4f8SPaul C. Anagnostopoulos }
1710c1bb4f8SPaul C. Anagnostopoulos 
1720c1bb4f8SPaul C. Anagnostopoulos // Print the fields of a class or record, including their source locations.
173bcde45baSRahul Joshi void DetailedRecordsEmitter::printFields(const Record &Rec, raw_ostream &OS) {
174bcde45baSRahul Joshi   const auto &ValueList = Rec.getValues();
1750c1bb4f8SPaul C. Anagnostopoulos   if (ValueList.empty()) {
1760c1bb4f8SPaul C. Anagnostopoulos     OS << "  Fields: (none)\n";
1770c1bb4f8SPaul C. Anagnostopoulos     return;
1780c1bb4f8SPaul C. Anagnostopoulos   }
1790c1bb4f8SPaul C. Anagnostopoulos 
1800c1bb4f8SPaul C. Anagnostopoulos   OS << "  Fields:\n";
1810c1bb4f8SPaul C. Anagnostopoulos   for (const RecordVal &Value : ValueList)
182bcde45baSRahul Joshi     if (!Rec.isTemplateArg(Value.getNameInit())) {
1830c1bb4f8SPaul C. Anagnostopoulos       OS << "    ";
1840c1bb4f8SPaul C. Anagnostopoulos       Value.print(OS, false);
1850c1bb4f8SPaul C. Anagnostopoulos       OS << formatv("  |{0}|\n",
1860c1bb4f8SPaul C. Anagnostopoulos                     SrcMgr.getFormattedLocationNoOffset(Value.getLoc()));
1870c1bb4f8SPaul C. Anagnostopoulos     }
1880c1bb4f8SPaul C. Anagnostopoulos }
1890c1bb4f8SPaul C. Anagnostopoulos 
1900c1bb4f8SPaul C. Anagnostopoulos // This function is called by TableGen after parsing the files.
191bcde45baSRahul Joshi void llvm::EmitDetailedRecords(const RecordKeeper &RK, raw_ostream &OS) {
1920c1bb4f8SPaul C. Anagnostopoulos   // Instantiate the emitter class and invoke run().
1930c1bb4f8SPaul C. Anagnostopoulos   DetailedRecordsEmitter(RK).run(OS);
1940c1bb4f8SPaul C. Anagnostopoulos }
195