1
0
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:
Paul C. Anagnostopoulos 2020-09-22 13:58:54 -04:00
parent d4e8ee9243
commit 6ec902749c
10 changed files with 331 additions and 16 deletions

View File

@ -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.

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -1,4 +1,5 @@
add_llvm_component_library(LLVMTableGen
DetailedRecordsBackend.cpp
Error.cpp
JSONBackend.cpp
Main.cpp

View 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

View File

@ -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());

View File

@ -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());

View File

@ -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

View File

@ -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;