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 ArrayRef<std::pair<const Record *, SMRange>> Superclasses = 156 Rec.getSuperClasses(); 157 if (Superclasses.empty()) { 158 OS << " Superclasses: (none)\n"; 159 return; 160 } 161 162 OS << " Superclasses:"; 163 for (const auto &[ClassRec, Loc] : Superclasses) { 164 if (Rec.hasDirectSuperClass(ClassRec)) 165 OS << formatv(" {0}", ClassRec->getNameInitAsString()); 166 else 167 OS << formatv(" ({0})", ClassRec->getNameInitAsString()); 168 } 169 OS << '\n'; 170 } 171 172 // Print the fields of a class or record, including their source locations. 173 void DetailedRecordsEmitter::printFields(const Record &Rec, raw_ostream &OS) { 174 const auto &ValueList = Rec.getValues(); 175 if (ValueList.empty()) { 176 OS << " Fields: (none)\n"; 177 return; 178 } 179 180 OS << " Fields:\n"; 181 for (const RecordVal &Value : ValueList) 182 if (!Rec.isTemplateArg(Value.getNameInit())) { 183 OS << " "; 184 Value.print(OS, false); 185 OS << formatv(" |{0}|\n", 186 SrcMgr.getFormattedLocationNoOffset(Value.getLoc())); 187 } 188 } 189 190 // This function is called by TableGen after parsing the files. 191 void llvm::EmitDetailedRecords(const RecordKeeper &RK, raw_ostream &OS) { 192 // Instantiate the emitter class and invoke run(). 193 DetailedRecordsEmitter(RK).run(OS); 194 } 195