Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/docs/TableGen/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ TableGen runs just like any other LLVM tool. The first (optional) argument
specifies the file to read. If a filename is not specified, ``llvm-tblgen``
reads from standard input.

The ``-o`` option specifies the output file or ``-`` to output to
stdout. Where TableGen produces multiple output files, the option
specifies the name of the main output file, which also works as the
name prefix for other output files.

To be useful, one of the `backends`_ must be used. These backends are
selectable on the command line (type '``llvm-tblgen -help``' for a list). For
example, to get a list of all of the definitions that subclass a particular type
Expand Down
17 changes: 16 additions & 1 deletion llvm/include/llvm/TableGen/Main.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,34 @@

#include "llvm/Support/CommandLine.h"
#include <functional>
#include <map>

namespace llvm {

class raw_ostream;
class RecordKeeper;

/// Perform the action using Records, and write output to OS.
struct TableGenOutputFiles {
std::string MainFile;

// Translates additional output file names to their contents.
std::map<StringRef, std::string> AdditionalFiles;
};

/// Returns true on error, false otherwise.
using TableGenMainFn = bool(raw_ostream &OS, const RecordKeeper &Records);

/// Perform the action using Records, and store output in OutFiles.
/// Returns true on error, false otherwise.
using MultiFileTableGenMainFn = bool(TableGenOutputFiles &OutFiles,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function_ref?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #167888.

const RecordKeeper &Records);

int TableGenMain(const char *argv0,
std::function<TableGenMainFn> MainFn = nullptr);

int TableGenMain(const char *argv0,
std::function<MultiFileTableGenMainFn> MainFn = nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function_ref?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #167888.


/// Controls emitting large character arrays as strings or character arrays.
/// Typically set to false when building with MSVC.
extern cl::opt<bool> EmitLongStrLiterals;
Expand Down
43 changes: 40 additions & 3 deletions llvm/include/llvm/TableGen/TableGenBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/TableGen/Main.h"
#include "llvm/TableGen/Record.h"

namespace llvm {
Expand All @@ -23,7 +24,27 @@ class RecordKeeper;
class raw_ostream;

namespace TableGen::Emitter {
using FnT = function_ref<void(const RecordKeeper &Records, raw_ostream &OS)>;

/// Represents the emitting function. Can produce a single or multple output
/// files.
struct FnT {
using SingleFileGeneratorType = void(const RecordKeeper &Records,
raw_ostream &OS);
using MultiFileGeneratorType = TableGenOutputFiles(
StringRef FilenamePrefix, const RecordKeeper &Records);

SingleFileGeneratorType *SingleFileGenerator = nullptr;
MultiFileGeneratorType *MultiFileGenerator = nullptr;

FnT() = default;
FnT(SingleFileGeneratorType *Gen) : SingleFileGenerator(Gen) {}
FnT(MultiFileGeneratorType *Gen) : MultiFileGenerator(Gen) {}

bool operator==(const FnT &Other) const {
return SingleFileGenerator == Other.SingleFileGenerator &&
MultiFileGenerator == Other.MultiFileGenerator;
}
};

/// Creating an `Opt` object registers the command line option \p Name with
/// TableGen backend and associates the callback \p CB with that option. If
Expand All @@ -36,17 +57,33 @@ struct Opt {
/// Convienence wrapper around `Opt` that registers `EmitterClass::run` as the
/// callback.
template <class EmitterC> class OptClass : Opt {
static void run(const RecordKeeper &RK, raw_ostream &OS) {
static TableGenOutputFiles run(StringRef /*FilenamePrefix*/,
const RecordKeeper &RK) {
std::string S;
raw_string_ostream OS(S);
EmitterC(RK).run(OS);
return {S, {}};
}

public:
OptClass(StringRef Name, StringRef Desc) : Opt(Name, run, Desc) {}
};

/// A version of the wrapper for backends emitting multiple files.
template <class EmitterC> class MultiFileOptClass : Opt {
static TableGenOutputFiles run(StringRef FilenamePrefix,
const RecordKeeper &RK) {
return EmitterC(RK).run(FilenamePrefix);
}

public:
MultiFileOptClass(StringRef Name, StringRef Desc) : Opt(Name, run, Desc) {}
};

/// Apply callback for any command line option registered above. Returns false
/// is no callback was applied.
bool ApplyCallback(const RecordKeeper &Records, raw_ostream &OS);
bool ApplyCallback(const RecordKeeper &Records, TableGenOutputFiles &OutFiles,
StringRef FilenamePrefix);

} // namespace TableGen::Emitter

Expand Down
76 changes: 52 additions & 24 deletions llvm/lib/TableGen/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/ToolOutputFile.h"
Expand Down Expand Up @@ -104,8 +105,30 @@ static int createDependencyFile(const TGParser &Parser, const char *argv0) {
return 0;
}

static int WriteOutput(const TGParser &Parser, const char *argv0,
StringRef Filename, StringRef Content) {
if (WriteIfChanged) {
// Only updates the real output file if there are any differences.
// This prevents recompilation of all the files depending on it if there
// aren't any.
if (auto ExistingOrErr = MemoryBuffer::getFile(Filename, /*IsText=*/true))
if (std::move(ExistingOrErr.get())->getBuffer() == Content)
return 0;
}
std::error_code EC;
ToolOutputFile OutFile(Filename, EC, sys::fs::OF_Text);
if (EC)
return reportError(argv0, "error opening " + Filename + ": " +
EC.message() + "\n");
OutFile.os() << Content;
if (ErrorsPrinted == 0)
OutFile.keep();

return 0;
}

int llvm::TableGenMain(const char *argv0,
std::function<TableGenMainFn> MainFn) {
std::function<MultiFileTableGenMainFn> MainFn) {
RecordKeeper Records;
TGTimer &Timer = Records.getTimer();

Expand Down Expand Up @@ -144,13 +167,14 @@ int llvm::TableGenMain(const char *argv0,

// Write output to memory.
Timer.startBackendTimer("Backend overall");
std::string OutString;
raw_string_ostream Out(OutString);
SmallString<128> FilenamePrefix(OutputFilename);
sys::path::replace_extension(FilenamePrefix, "");
TableGenOutputFiles OutFiles;
unsigned status = 0;
// ApplyCallback will return true if it did not apply any callback. In that
// case, attempt to apply the MainFn.
if (TableGen::Emitter::ApplyCallback(Records, Out))
status = MainFn ? MainFn(Out, Records) : 1;
if (TableGen::Emitter::ApplyCallback(Records, OutFiles, FilenamePrefix))
status = MainFn ? MainFn(OutFiles, Records) : 1;
Timer.stopBackendTimer();
if (status)
return 1;
Expand All @@ -165,25 +189,17 @@ int llvm::TableGenMain(const char *argv0,
}

Timer.startTimer("Write output");
bool WriteFile = true;
if (WriteIfChanged) {
// Only updates the real output file if there are any differences.
// This prevents recompilation of all the files depending on it if there
// aren't any.
if (auto ExistingOrErr =
MemoryBuffer::getFile(OutputFilename, /*IsText=*/true))
if (std::move(ExistingOrErr.get())->getBuffer() == OutString)
WriteFile = false;
}
if (WriteFile) {
std::error_code EC;
ToolOutputFile OutFile(OutputFilename, EC, sys::fs::OF_Text);
if (EC)
return reportError(argv0, "error opening " + OutputFilename + ": " +
EC.message() + "\n");
OutFile.os() << OutString;
if (ErrorsPrinted == 0)
OutFile.keep();
if (int Ret = WriteOutput(Parser, argv0, OutputFilename, OutFiles.MainFile))
return Ret;
for (auto [Suffix, Content] : OutFiles.AdditionalFiles) {
SmallString<128> Filename(OutputFilename);
// TODO: Format using the split-file convention when writing to stdout?
if (Filename != "-") {
Filename = FilenamePrefix;
Filename.append(Suffix);
}
if (int Ret = WriteOutput(Parser, argv0, Filename, Content))
return Ret;
}

Timer.stopTimer();
Expand All @@ -193,3 +209,15 @@ int llvm::TableGenMain(const char *argv0,
return reportError(argv0, Twine(ErrorsPrinted) + " errors.\n");
return 0;
}

int llvm::TableGenMain(const char *argv0,
std::function<TableGenMainFn> MainFn) {
return TableGenMain(argv0, [&MainFn](TableGenOutputFiles &OutFiles,
const RecordKeeper &Records) {
std::string S;
raw_string_ostream OS(S);
int Res = MainFn(OS, Records);
OutFiles = {S, {}};
return Res;
});
}
19 changes: 14 additions & 5 deletions llvm/lib/TableGen/TableGenBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,21 @@ Opt::Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault) {
/// Apply callback specified on the command line. Returns true if no callback
/// was applied.
bool llvm::TableGen::Emitter::ApplyCallback(const RecordKeeper &Records,
raw_ostream &OS) {
TableGenOutputFiles &OutFiles,
StringRef FilenamePrefix) {
FnT Fn = CallbackFunction->getValue();
if (!Fn)
return true;
Fn(Records, OS);
return false;
if (Fn.SingleFileGenerator) {
std::string S;
raw_string_ostream OS(S);
Fn.SingleFileGenerator(Records, OS);
OutFiles = {S, {}};
return false;
}
if (Fn.MultiFileGenerator) {
OutFiles = Fn.MultiFileGenerator(FilenamePrefix, Records);
return false;
}
return true;
}

static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill,
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AMDGPU/SIFoldOperands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1358,7 +1358,7 @@ void SIFoldOperandsImpl::foldOperand(
// Remove this if 16-bit SGPRs (i.e. SGPR_LO16) are added to the
// VS_16RegClass
//
// Excerpt from AMDGPUGenRegisterInfo.inc
// Excerpt from AMDGPUGenRegisterInfoEnums.inc
// NoSubRegister, //0
// hi16, // 1
// lo16, // 2
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/TableGen/ArtificialSubregs.td
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s --check-prefix=CHECK
include "llvm/Target/Target.td"

// This file tests that when using `isArtificial` for subregisters in
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/TableGen/ConcatenatedSubregs.td
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this change?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I understand, -o /dev/null is no longer useful because it will try to write to files like /dev/nullEnums.inc, right? Does this patch need any documentation updates for the tool and its command line options?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But -o - doesn't try to write files like -Enums.inc?
I don't think it is a good idea to abuse -o option this way. It specifies the single output file, not a prefix.
Maybe prohibit it when generating multiple files and add another option specifying the prefix? Or require -o (or its multi-file replacement) be specified multiple times

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-o still specifies the name of the main .inc file.

Updated documentation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I misunderstood the concept. I thought it would generate several files which are supposed to be included directly and not via the "main" include that includes everything.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I should have explained it. The general idea is to make the change as transparent to existing users as possible. They still include the same old .inc file but memory usage goes down anyway.

// Checks that tablegen correctly and completely infers subregister relations.
include "llvm/Target/Target.td"

Expand Down
2 changes: 1 addition & 1 deletion llvm/test/TableGen/HwModeBitSet.td
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// This is to test the scenario where different HwMode attributes coexist.
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-REG
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s --check-prefix=CHECK-REG
// RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SUBTARGET


Expand Down
2 changes: 1 addition & 1 deletion llvm/test/TableGen/HwModeSubRegs.td
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s
include "llvm/Target/Target.td"

def HasFeat : Predicate<"Subtarget->hasFeat()">;
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/TableGen/SubRegsAndAliases.td
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s
// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s
include "llvm/Target/Target.td"
def TestTarget : Target;

Expand Down
7 changes: 5 additions & 2 deletions llvm/utils/TableGen/Basic/TableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ static TableGen::Emitter::Opt X[] = {
true},
{"print-detailed-records", EmitDetailedRecords,
"Print full details of all records to stdout"},
{"null-backend", [](const RecordKeeper &Records, raw_ostream &OS) {},
{"null-backend",
TableGen::Emitter::FnT(
[](const RecordKeeper &Records, raw_ostream &OS) {}),
"Do nothing after parsing (useful for timing)"},
{"dump-json", EmitJSON, "Dump all records as machine-readable JSON"},
{"print-enums", printEnums, "Print enum values for a class"},
Expand All @@ -71,7 +73,8 @@ int tblgen_main(int argc, char **argv) {
InitLLVM X(argc, argv);
cl::ParseCommandLineOptions(argc, argv);

return TableGenMain(argv[0]);
std::function<MultiFileTableGenMainFn> MainFn = nullptr;
return TableGenMain(argv[0], MainFn);
}

#ifndef __has_feature
Expand Down
Loading
Loading