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("DETAILED RECORDS for file {0}\n", Records.getInputFilename()); 69 } 70 71 // Print the global variables. 72 void DetailedRecordsEmitter::printVariables(raw_ostream &OS) { 73 const auto GlobalList = Records.getGlobals(); 74 printSectionHeading("Global Variables", 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("Classes", ClassList.size(), OS); 87 88 for (const auto &ClassPair : ClassList) { 89 auto *const Class = ClassPair.second.get(); 90 OS << formatv("\n{0} |{1}|\n", Class->getNameInitAsString(), 91 SrcMgr.getFormattedLocationNoOffset(Class->getLoc().front())); 92 printTemplateArgs(Class, OS); 93 printSuperclasses(Class, OS); 94 printFields(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("Records", 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("\n{0} |{1}|\n", Name.empty() ? "\"\"" : Name, 108 SrcMgr.getFormattedLocationNoOffset(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("\n{0} {1} ({2}) {0}\n", "--------------------", Title, 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(" |{0}|", SrcMgr.getFormattedLocationNoOffset(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(ArgName); 148 assert(Value && "Template argument value not found."); 149 OS << " "; 150 Value->print(OS, false); 151 OS << formatv(" |{0}|", SrcMgr.getFormattedLocationNoOffset(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(ClassRec)) 169 OS << formatv(" {0}", ClassRec->getNameInitAsString()); 170 else 171 OS << formatv(" ({0})", 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(Value.getNameInit())) { 187 OS << " "; 188 Value.print(OS, false); 189 OS << formatv(" |{0}|\n", 190 SrcMgr.getFormattedLocationNoOffset(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