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