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