mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
[TableGen] New backend to print detailed records.
Pertinent lints are fixed.
This commit is contained in:
parent
d4e8ee9243
commit
6ec902749c
@ -690,11 +690,9 @@ Instances of the following classes can be printed using the ``<<`` operator:
|
||||
``RecordVal``, and
|
||||
``Init``.
|
||||
|
||||
A constant and two helper functions are provided for producing the output
|
||||
file. The constant ``MAX_LINE_LEN`` specifies the maximum length of output
|
||||
lines. The helper function ``printLine`` prints a horizontal line comment.
|
||||
The helper function ``emitSourceFileHeader`` prints the header comment that
|
||||
should be included at the top of every output file.
|
||||
The helper function ``emitSourceFileHeader()`` prints the header comment
|
||||
that should be included at the top of every output file. A call to it is
|
||||
included in the skeleton backend file ``TableGenBackendSkeleton.cpp``.
|
||||
|
||||
Printing Error Messages
|
||||
=======================
|
||||
@ -780,9 +778,53 @@ Classes are shown with their template arguments, parent classes (following
|
||||
fields. Note that anonymous records are named ``anonymous_0``,
|
||||
``anonymous_1``, etc.
|
||||
|
||||
|
||||
|
||||
The ``PrintDetailedRecords`` Backend
|
||||
------------------------------------
|
||||
|
||||
[to come]
|
||||
The TableGen command option ``--print-detailed-records`` invokes a backend
|
||||
that prints all the global variables, classes, and records defined in the
|
||||
source files. The output looks like this.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
DETAILED RECORDS for file llvm-project\llvm\lib\target\arc\arc.td
|
||||
|
||||
-------------------- Global Variables (5) --------------------
|
||||
|
||||
AMDGPUBufferIntrinsics = [int_amdgcn_buffer_load_format, ...
|
||||
AMDGPUImageDimAtomicIntrinsics = [int_amdgcn_image_atomic_swap_1d, ...
|
||||
...
|
||||
-------------------- Classes (758) --------------------
|
||||
|
||||
AMDGPUBufferLoad |IntrinsicsAMDGPU.td:879|
|
||||
Template args:
|
||||
LLVMType AMDGPUBufferLoad:data_ty = llvm_any_ty |IntrinsicsAMDGPU.td:879|
|
||||
Superclasses: (SDPatternOperator) Intrinsic AMDGPURsrcIntrinsic
|
||||
Fields:
|
||||
list<SDNodeProperty> Properties = [SDNPMemOperand] |Intrinsics.td:348|
|
||||
string LLVMName = "" |Intrinsics.td:343|
|
||||
...
|
||||
-------------------- Records (12303) --------------------
|
||||
|
||||
AMDGPUSample_lz_o |IntrinsicsAMDGPU.td:560|
|
||||
Defm sequence: |IntrinsicsAMDGPU.td:584| |IntrinsicsAMDGPU.td:566|
|
||||
Superclasses: AMDGPUSampleVariant
|
||||
Fields:
|
||||
string UpperCaseMod = "_LZ_O" |IntrinsicsAMDGPU.td:542|
|
||||
string LowerCaseMod = "_lz_o" |IntrinsicsAMDGPU.td:543|
|
||||
...
|
||||
|
||||
* Global variables defined with outer ``defvar`` statements are shown with
|
||||
their values.
|
||||
|
||||
* The classes are shown with their source location, template arguments,
|
||||
superclasses, and fields.
|
||||
|
||||
* The records are shown with their source location, ``defm`` sequence,
|
||||
superclasses, and fields.
|
||||
|
||||
Superclasses are shown in the order processed, with indirect superclasses in
|
||||
parentheses. Each field is shown with its value and the source location at
|
||||
which it was set.
|
||||
The ``defm`` sequence gives the locations of the ``defm`` statements that
|
||||
were involved in generating the record, in the order they were invoked.
|
@ -172,6 +172,11 @@ public:
|
||||
std::pair<unsigned, unsigned> getLineAndColumn(SMLoc Loc,
|
||||
unsigned BufferID = 0) const;
|
||||
|
||||
/// Get a string with the \p SMLoc filename and line number
|
||||
/// formatted in the standard style.
|
||||
std::string getFormattedLocationNoOffset(SMLoc Loc,
|
||||
bool IncludePath = false) const;
|
||||
|
||||
/// Given a line and column number in a mapped buffer, turn it into an SMLoc.
|
||||
/// This will return a null SMLoc if the line/column location is invalid.
|
||||
SMLoc FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,
|
||||
|
@ -1518,7 +1518,10 @@ public:
|
||||
return SuperClasses;
|
||||
}
|
||||
|
||||
/// Append the direct super classes of this record to Classes.
|
||||
/// Determine whether this record has the specified direct superclass.
|
||||
bool hasDirectSuperClass(const Record *SuperClass) const;
|
||||
|
||||
/// Append the direct superclasses of this record to Classes.
|
||||
void getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const;
|
||||
|
||||
bool isTemplateArg(Init *Name) const {
|
||||
@ -1710,19 +1713,27 @@ class RecordKeeper {
|
||||
friend class RecordRecTy;
|
||||
|
||||
using RecordMap = std::map<std::string, std::unique_ptr<Record>, std::less<>>;
|
||||
using GlobalMap = std::map<std::string, Init *, std::less<>>;
|
||||
|
||||
std::string InputFilename;
|
||||
RecordMap Classes, Defs;
|
||||
FoldingSet<RecordRecTy> RecordTypePool;
|
||||
std::map<std::string, Init *, std::less<>> ExtraGlobals;
|
||||
unsigned AnonCounter = 0;
|
||||
|
||||
public:
|
||||
/// Get the main TableGen input file's name.
|
||||
const std::string getInputFilename() const { return InputFilename; }
|
||||
|
||||
/// Get the map of classes.
|
||||
const RecordMap &getClasses() const { return Classes; }
|
||||
|
||||
/// Get the map of records (defs).
|
||||
const RecordMap &getDefs() const { return Defs; }
|
||||
|
||||
/// Get the map of global variables.
|
||||
const GlobalMap &getGlobals() const { return ExtraGlobals; }
|
||||
|
||||
/// Get the class with the specified name.
|
||||
Record *getClass(StringRef Name) const {
|
||||
auto I = Classes.find(Name);
|
||||
@ -1743,6 +1754,10 @@ public:
|
||||
return It == ExtraGlobals.end() ? nullptr : It->second;
|
||||
}
|
||||
|
||||
void saveInputFilename(std::string Filename) {
|
||||
InputFilename = Filename;
|
||||
}
|
||||
|
||||
void addClass(std::unique_ptr<Record> R) {
|
||||
bool Ins = Classes.insert(std::make_pair(std::string(R->getName()),
|
||||
std::move(R))).second;
|
||||
@ -2017,6 +2032,7 @@ public:
|
||||
Init *resolve(Init *VarName) override;
|
||||
};
|
||||
|
||||
void EmitDetailedRecords(RecordKeeper &RK, raw_ostream &OS);
|
||||
void EmitJSON(RecordKeeper &RK, raw_ostream &OS);
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -180,7 +180,7 @@ std::pair<unsigned, unsigned>
|
||||
SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
|
||||
if (!BufferID)
|
||||
BufferID = FindBufferContainingLoc(Loc);
|
||||
assert(BufferID && "Invalid Location!");
|
||||
assert(BufferID && "Invalid location!");
|
||||
|
||||
auto &SB = getBufferInfo(BufferID);
|
||||
const char *Ptr = Loc.getPointer();
|
||||
@ -193,6 +193,30 @@ SourceMgr::getLineAndColumn(SMLoc Loc, unsigned BufferID) const {
|
||||
return std::make_pair(LineNo, Ptr - BufStart - NewlineOffs);
|
||||
}
|
||||
|
||||
// FIXME: Note that the formatting of source locations is spread between
|
||||
// multiple functions, some in SourceMgr and some in SMDiagnostic. A better
|
||||
// solution would be a general-purpose source location formatter
|
||||
// in one of those two classes, or possibly in SMLoc.
|
||||
|
||||
/// Get a string with the source location formatted in the standard
|
||||
/// style, but without the line offset. If \p IncludePath is true, the path
|
||||
/// is included. If false, only the file name and extension are included.
|
||||
std::string SourceMgr::getFormattedLocationNoOffset(SMLoc Loc,
|
||||
bool IncludePath) const {
|
||||
auto BufferID = FindBufferContainingLoc(Loc);
|
||||
assert(BufferID && "Invalid location!");
|
||||
auto FileSpec = getBufferInfo(BufferID).Buffer->getBufferIdentifier();
|
||||
|
||||
if (IncludePath) {
|
||||
return FileSpec.str() + ":" + std::to_string(FindLineNumber(Loc, BufferID));
|
||||
} else {
|
||||
auto I = FileSpec.find_last_of("/\\");
|
||||
I = (I == FileSpec.size()) ? 0 : (I + 1);
|
||||
return FileSpec.substr(I).str() + ":" +
|
||||
std::to_string(FindLineNumber(Loc, BufferID));
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a line and column number in a mapped buffer, turn it into an SMLoc.
|
||||
/// This will return a null SMLoc if the line/column location is invalid.
|
||||
SMLoc SourceMgr::FindLocForLineAndColumn(unsigned BufferID, unsigned LineNo,
|
||||
|
@ -1,4 +1,5 @@
|
||||
add_llvm_component_library(LLVMTableGen
|
||||
DetailedRecordsBackend.cpp
|
||||
Error.cpp
|
||||
JSONBackend.cpp
|
||||
Main.cpp
|
||||
|
204
lib/TableGen/DetailedRecordsBackend.cpp
Normal file
204
lib/TableGen/DetailedRecordsBackend.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
//===- DetailedRecordBackend.cpp - Detailed Records Report -*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This Tablegen backend prints a report that includes all the global
|
||||
// variables, classes, and records in complete detail. It includes more
|
||||
// detail than the default TableGen printer backend.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/TableGen/Error.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define DEBUG_TYPE "detailed-records-backend"
|
||||
|
||||
#define NL "\n"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
class DetailedRecordsEmitter {
|
||||
private:
|
||||
RecordKeeper &Records;
|
||||
|
||||
public:
|
||||
DetailedRecordsEmitter(RecordKeeper &RK) : Records(RK) {}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
void printReportHeading(raw_ostream &OS);
|
||||
void printVariables(raw_ostream &OS);
|
||||
void printClasses(raw_ostream &OS);
|
||||
void printRecords(raw_ostream &OS);
|
||||
void printSectionHeading(std::string Title, int Count, raw_ostream &OS);
|
||||
void printDefms(Record *Rec, raw_ostream &OS);
|
||||
void printTemplateArgs(Record *Rec, raw_ostream &OS);
|
||||
void printSuperclasses(Record *Rec, raw_ostream &OS);
|
||||
void printFields(Record *Rec, raw_ostream &OS);
|
||||
std::string formatLocation(const SMLoc Loc);
|
||||
}; // emitter class
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Print the report.
|
||||
void DetailedRecordsEmitter::run(raw_ostream &OS) {
|
||||
printReportHeading(OS);
|
||||
printVariables(OS);
|
||||
printClasses(OS);
|
||||
printRecords(OS);
|
||||
}
|
||||
|
||||
// Print the report heading, including the source file name.
|
||||
void DetailedRecordsEmitter::printReportHeading(raw_ostream &OS) {
|
||||
OS << formatv("DETAILED RECORDS for file {0}\n", Records.getInputFilename());
|
||||
}
|
||||
|
||||
// Print the global variables.
|
||||
void DetailedRecordsEmitter::printVariables(raw_ostream &OS) {
|
||||
const auto GlobalList = Records.getGlobals();
|
||||
printSectionHeading("Global Variables", GlobalList.size(), OS);
|
||||
|
||||
OS << NL;
|
||||
for (const auto &Var : GlobalList) {
|
||||
OS << Var.first << " = " << Var.second->getAsString() << NL;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the classes, including the template arguments, superclasses,
|
||||
// and fields.
|
||||
void DetailedRecordsEmitter::printClasses(raw_ostream &OS) {
|
||||
const auto &ClassList = Records.getClasses();
|
||||
printSectionHeading("Classes", ClassList.size(), OS);
|
||||
|
||||
for (const auto &ClassPair : ClassList) {
|
||||
auto *const Class = ClassPair.second.get();
|
||||
OS << formatv("\n{0} |{1}|\n", Class->getNameInitAsString(),
|
||||
SrcMgr.getFormattedLocationNoOffset(Class->getLoc().front()));
|
||||
printTemplateArgs(Class, OS);
|
||||
printSuperclasses(Class, OS);
|
||||
printFields(Class, OS);
|
||||
}
|
||||
}
|
||||
|
||||
// Print the records, including the defm sequences, supercasses,
|
||||
// and fields.
|
||||
void DetailedRecordsEmitter::printRecords(raw_ostream &OS) {
|
||||
const auto &RecordList = Records.getDefs();
|
||||
printSectionHeading("Records", RecordList.size(), OS);
|
||||
|
||||
for (const auto &RecPair : RecordList) {
|
||||
auto *const Rec = RecPair.second.get();
|
||||
OS << formatv("\n{0} |{1}|\n", Rec->getNameInitAsString(),
|
||||
SrcMgr.getFormattedLocationNoOffset(Rec->getLoc().front()));
|
||||
printDefms(Rec, OS);
|
||||
printSuperclasses(Rec, OS);
|
||||
printFields(Rec, OS);
|
||||
}
|
||||
}
|
||||
|
||||
// Print a section heading with the name of the section and
|
||||
// the item count.
|
||||
void DetailedRecordsEmitter::printSectionHeading(std::string Title, int Count,
|
||||
raw_ostream &OS) {
|
||||
OS << formatv("\n{0} {1} ({2}) {0}\n", "--------------------", Title, Count);
|
||||
}
|
||||
|
||||
// Print the record's defm source locations, if any. Note that they
|
||||
// are stored in the reverse order of their invocation.
|
||||
void DetailedRecordsEmitter::printDefms(Record *Rec, raw_ostream &OS) {
|
||||
const auto &LocList = Rec->getLoc();
|
||||
if (LocList.size() < 2)
|
||||
return;
|
||||
|
||||
OS << " Defm sequence:";
|
||||
for (unsigned I = LocList.size() - 1; I >= 1; --I) {
|
||||
OS << formatv(" |{0}|", SrcMgr.getFormattedLocationNoOffset(LocList[I]));
|
||||
}
|
||||
OS << NL;
|
||||
}
|
||||
|
||||
// Print the template arguments of a class.
|
||||
void DetailedRecordsEmitter::printTemplateArgs(Record *Rec,
|
||||
raw_ostream &OS) {
|
||||
ArrayRef<Init *> Args = Rec->getTemplateArgs();
|
||||
if (Args.empty()) {
|
||||
OS << " Template args: (none)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " Template args:\n";
|
||||
for (const Init *ArgName : Args) {
|
||||
const RecordVal *Value = Rec->getValue(ArgName);
|
||||
assert(Value && "Template argument value not found.");
|
||||
OS << " ";
|
||||
Value->print(OS, false);
|
||||
OS << formatv(" |{0}|", SrcMgr.getFormattedLocationNoOffset(Value->getLoc()));
|
||||
OS << NL;
|
||||
}
|
||||
}
|
||||
|
||||
// Print the superclasses of a class or record. Indirect superclasses
|
||||
// are enclosed in parentheses.
|
||||
void DetailedRecordsEmitter::printSuperclasses(Record *Rec, raw_ostream &OS) {
|
||||
ArrayRef<std::pair<Record *, SMRange>> Superclasses = Rec->getSuperClasses();
|
||||
if (Superclasses.empty()) {
|
||||
OS << " Superclasses: (none)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " Superclasses:";
|
||||
for (const auto &SuperclassPair : Superclasses) {
|
||||
auto *ClassRec = SuperclassPair.first;
|
||||
if (Rec->hasDirectSuperClass(ClassRec))
|
||||
OS << formatv(" {0}", ClassRec->getNameInitAsString());
|
||||
else
|
||||
OS << formatv(" ({0})", ClassRec->getNameInitAsString());
|
||||
}
|
||||
OS << NL;
|
||||
}
|
||||
|
||||
// Print the fields of a class or record, including their source locations.
|
||||
void DetailedRecordsEmitter::printFields(Record *Rec, raw_ostream &OS) {
|
||||
const auto &ValueList = Rec->getValues();
|
||||
if (ValueList.empty()) {
|
||||
OS << " Fields: (none)\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " Fields:\n";
|
||||
for (const RecordVal &Value : ValueList)
|
||||
if (!Rec->isTemplateArg(Value.getNameInit())) {
|
||||
OS << " ";
|
||||
Value.print(OS, false);
|
||||
OS << formatv(" |{0}|\n",
|
||||
SrcMgr.getFormattedLocationNoOffset(Value.getLoc()));
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// This function is called by TableGen after parsing the files.
|
||||
|
||||
void EmitDetailedRecords(RecordKeeper &RK, raw_ostream &OS) {
|
||||
// Instantiate the emitter class and invoke run().
|
||||
DetailedRecordsEmitter(RK).run(OS);
|
||||
}
|
||||
|
||||
} // namespace llvm
|
@ -90,6 +90,8 @@ int llvm::TableGenMain(const char *argv0, TableGenMainFn *MainFn) {
|
||||
return reportError(argv0, "Could not open input file '" + InputFilename +
|
||||
"': " + EC.message() + "\n");
|
||||
|
||||
Records.saveInputFilename(InputFilename);
|
||||
|
||||
// Tell SrcMgr about this buffer, which is what TGParser will pick up.
|
||||
SrcMgr.AddNewSourceBuffer(std::move(*FileOrErr), SMLoc());
|
||||
|
||||
|
@ -2144,12 +2144,27 @@ void Record::setName(Init *NewName) {
|
||||
// this. See TGParser::ParseDef and TGParser::ParseDefm.
|
||||
}
|
||||
|
||||
// NOTE for the next two functions:
|
||||
// Superclasses are in post-order, so the final one is a direct
|
||||
// superclass. All of its transitive superclases immediately precede it,
|
||||
// so we can step through the direct superclasses in reverse order.
|
||||
|
||||
bool Record::hasDirectSuperClass(const Record *Superclass) const {
|
||||
ArrayRef<std::pair<Record *, SMRange>> SCs = getSuperClasses();
|
||||
|
||||
for (int I = SCs.size() - 1; I >= 0; --I) {
|
||||
const Record *SC = SCs[I].first;
|
||||
if (SC == Superclass)
|
||||
return true;
|
||||
I -= SC->getSuperClasses().size();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Record::getDirectSuperClasses(SmallVectorImpl<Record *> &Classes) const {
|
||||
ArrayRef<std::pair<Record *, SMRange>> SCs = getSuperClasses();
|
||||
|
||||
// Superclasses are in post-order, so the final one is a direct
|
||||
// superclass. All of its transitive superclases immediately precede it,
|
||||
// so we can step through the direct superclasses in reverse order.
|
||||
while (!SCs.empty()) {
|
||||
Record *SC = SCs.back().first;
|
||||
SCs = SCs.drop_back(1 + SC->getSuperClasses().size());
|
||||
|
@ -41,9 +41,9 @@ public:
|
||||
SkeletonEmitter(RecordKeeper &RK) : Records(RK) {}
|
||||
|
||||
void run(raw_ostream &OS);
|
||||
}; // End emitter class.
|
||||
}; // emitter class
|
||||
|
||||
} // End anonymous namespace.
|
||||
} // anonymous namespace
|
||||
|
||||
void SkeletonEmitter::run(raw_ostream &OS) {
|
||||
emitSourceFileHeader("Skeleton data structures", OS);
|
||||
@ -61,4 +61,4 @@ void EmitSkeleton(RecordKeeper &RK, raw_ostream &OS) {
|
||||
SkeletonEmitter(RK).run(OS);
|
||||
}
|
||||
|
||||
} // End llvm namespace.
|
||||
} // namespace llvm
|
||||
|
@ -21,6 +21,7 @@ using namespace llvm;
|
||||
|
||||
enum ActionType {
|
||||
PrintRecords,
|
||||
PrintDetailedRecords,
|
||||
DumpJSON,
|
||||
GenEmitter,
|
||||
GenRegisterInfo,
|
||||
@ -75,6 +76,8 @@ cl::opt<ActionType> Action(
|
||||
cl::values(
|
||||
clEnumValN(PrintRecords, "print-records",
|
||||
"Print all records to stdout (default)"),
|
||||
clEnumValN(PrintDetailedRecords, "print-detailed-records",
|
||||
"Print full details of all records to stdout"),
|
||||
clEnumValN(DumpJSON, "dump-json",
|
||||
"Dump all records as machine-readable JSON"),
|
||||
clEnumValN(GenEmitter, "gen-emitter", "Generate machine code emitter"),
|
||||
@ -152,6 +155,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
|
||||
case PrintRecords:
|
||||
OS << Records; // No argument, dump all contents
|
||||
break;
|
||||
case PrintDetailedRecords:
|
||||
EmitDetailedRecords(Records, OS);
|
||||
break;
|
||||
case DumpJSON:
|
||||
EmitJSON(Records, OS);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user