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 33using namespace llvm; 34 35namespace { 36 37class DetailedRecordsEmitter { 38private: 39 RecordKeeper &Records; 40 41public: 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. 59void 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. 67void DetailedRecordsEmitter::printReportHeading(raw_ostream &OS) { 68 OS << formatv("DETAILED RECORDS for file {0}\n", Records.getInputFilename()); 69} 70 71// Print the global variables. 72void 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. 84void 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. 100void 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. 117void 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. 124void 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. 137void 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. 158void 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. 177void 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 194namespace llvm { 195 196// This function is called by TableGen after parsing the files. 197 198void 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