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 OS << formatv("\n{0} |{1}|\n", Rec->getNameInitAsString(), 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(std::string 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