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("DETAILED RECORDS for file {0}\n", 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("\n{0} {1} ({2}) {0}\n", "--------------------", Title, Count); 71 } 72 73 // Print the global variables. 74 void DetailedRecordsEmitter::printVariables(raw_ostream &OS) { 75 const auto GlobalList = Records.getGlobals(); 76 printSectionHeading("Global Variables", 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("Classes", ClassList.size(), OS); 87 88 for (const auto &[Name, Class] : ClassList) { 89 OS << formatv("\n{0} |{1}|\n", Class->getNameInitAsString(), 90 SrcMgr.getFormattedLocationNoOffset(Class->getLoc().front())); 91 printTemplateArgs(*Class, OS); 92 printSuperclasses(*Class, OS); 93 printFields(*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("Records", RecordList.size(), OS); 101 102 for (const auto &[DefName, Rec] : RecordList) { 103 std::string Name = Rec->getNameInitAsString(); 104 OS << formatv("\n{0} |{1}|\n", Name.empty() ? "\"\"" : Name, 105 SrcMgr.getFormattedLocationNoOffset(Rec->getLoc().front())); 106 printDefms(*Rec, OS); 107 printSuperclasses(*Rec, OS); 108 printFields(*Rec, OS); 109 } 110 } 111 112 // Print memory allocation related stats. 113 void DetailedRecordsEmitter::printAllocationStats(raw_ostream &OS) { 114 OS << formatv("\n{0} Memory Allocation Stats {0}\n", "--------------------"); 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(LocList)) 127 OS << formatv(" |{0}|", 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(ArgName); 143 assert(Value && "Template argument value not found."); 144 OS << " "; 145 Value->print(OS, false); 146 OS << formatv(" |{0}|\n", 147 SrcMgr.getFormattedLocationNoOffset(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(ClassRec)) 164 OS << formatv(" {0}", ClassRec->getNameInitAsString()); 165 else 166 OS << formatv(" ({0})", 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(Value.getNameInit())) { 182 OS << " "; 183 Value.print(OS, false); 184 OS << formatv(" |{0}|\n", 185 SrcMgr.getFormattedLocationNoOffset(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