Skip to content

[TableGen] Allow emitter callbacks to use const RecordKeeper & #104716

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 26, 2024
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
4 changes: 4 additions & 0 deletions llvm/include/llvm/ADT/STLFunctionalExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ class function_ref<Ret(Params...)> {
}

explicit operator bool() const { return callback; }

bool operator==(const function_ref<Ret(Params...)> &Other) const {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this needed now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is needed now because of its use in cl::OptionValueCopy<FnT>, which uses the == operator.

return callable == Other.callable;
}
};

} // end namespace llvm
Expand Down
32 changes: 16 additions & 16 deletions llvm/include/llvm/TableGen/TableGenBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@
#ifndef LLVM_TABLEGEN_TABLEGENBACKEND_H
#define LLVM_TABLEGEN_TABLEGENBACKEND_H

#include "llvm/ADT/STLFunctionalExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/TableGen/Record.h"

namespace llvm {
Expand All @@ -24,36 +23,37 @@ class RecordKeeper;
class raw_ostream;

namespace TableGen::Emitter {
using FnT = void (*)(RecordKeeper &Records, raw_ostream &OS);

struct OptCreatorT {
static void *call();
};

extern ManagedStatic<cl::opt<FnT>, OptCreatorT> Action;
// Supports const and non-const forms of callback functions.
using FnT = function_ref<void(RecordKeeper &Records, raw_ostream &OS)>;

/// Creating an `Opt` object registers the command line option \p Name with
/// TableGen backend and associates the callback \p CB with that option. If
/// \p ByDefault is true, then that callback is applied by default if no
/// command line option was specified.
struct Opt {
Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault = false) {
if (ByDefault)
Action->setInitialValue(CB);
Action->getParser().addLiteralOption(Name, CB, Desc);
}
Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault = false);
};

/// Convienence wrapper around `Opt` that registers `EmitterClass::run` as the
/// callback.
template <class EmitterC> class OptClass : Opt {
static void run(RecordKeeper &RK, raw_ostream &OS) { EmitterC(RK).run(OS); }

public:
OptClass(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(RecordKeeper &Records, raw_ostream &OS);

} // namespace TableGen::Emitter

/// emitSourceFileHeader - Output an LLVM style file header to the specified
/// raw_ostream.
void emitSourceFileHeader(StringRef Desc, raw_ostream &OS,
const RecordKeeper &Record = RecordKeeper());

} // End llvm namespace
} // namespace llvm

#endif
#endif // LLVM_TABLEGEN_TABLEGENBACKEND_H
11 changes: 4 additions & 7 deletions llvm/lib/TableGen/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,10 @@ int llvm::TableGenMain(const char *argv0,
std::string OutString;
raw_string_ostream Out(OutString);
unsigned status = 0;
TableGen::Emitter::FnT ActionFn = TableGen::Emitter::Action->getValue();
if (ActionFn)
ActionFn(Records, Out);
else if (MainFn)
status = MainFn(Out, Records);
else
return 1;
// 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;
Records.stopBackendTimer();
if (status)
return 1;
Expand Down
52 changes: 46 additions & 6 deletions llvm/lib/TableGen/TableGenBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,62 @@

#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstddef>

using namespace llvm;
using namespace TableGen::Emitter;

const size_t MAX_LINE_LEN = 80U;

namespace llvm::TableGen::Emitter {
ManagedStatic<cl::opt<FnT>, OptCreatorT> Action;
void *OptCreatorT::call() {
return new cl::opt<FnT>(cl::desc("Action to perform:"));
// CommandLine options of class type are not directly supported with some
// specific exceptions like std::string which are safe to copy. In our case,
// the `FnT` function_ref object is also safe to copy. So provide a
// specialization of `OptionValue` for `FnT` type that stores it as a copy.
// This is essentially similar to OptionValue<std::string> specialization for
// strings.
template <> struct cl::OptionValue<FnT> final : cl::OptionValueCopy<FnT> {
OptionValue() = default;

OptionValue(const FnT &V) { this->setValue(V); }

OptionValue<FnT> &operator=(const FnT &V) {
setValue(V);
return *this;
}
};

namespace {
struct OptCreatorT {
static void *call() {
return new cl::opt<FnT>(cl::desc("Action to perform:"));
}
};
} // namespace

static ManagedStatic<cl::opt<FnT>, OptCreatorT> CallbackFunction;

Opt::Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault) {
if (ByDefault)
CallbackFunction->setInitialValue(CB);
CallbackFunction->getParser().addLiteralOption(Name, CB, Desc);
}

/// Apply callback specified on the command line. Returns true if no callback
/// was applied.
bool llvm::TableGen::Emitter::ApplyCallback(RecordKeeper &Records,
raw_ostream &OS) {
FnT Fn = CallbackFunction->getValue();
if (!Fn)
return true;
Fn(Records, OS);
return false;
}
} // namespace llvm::TableGen::Emitter

static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill,
StringRef Suffix) {
Expand Down Expand Up @@ -59,7 +99,7 @@ void llvm::emitSourceFileHeader(StringRef Desc, raw_ostream &OS,
printLine(OS, Prefix + "Automatically generated file, do not edit!", ' ',
Suffix);

// Print the filename of source file
// Print the filename of source file.
if (!Record.getInputFilename().empty())
printLine(
OS, Prefix + "From: " + sys::path::filename(Record.getInputFilename()),
Expand Down
10 changes: 10 additions & 0 deletions llvm/unittests/ADT/FunctionRefTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,14 @@ TEST(FunctionRefTest, SFINAE) {
EXPECT_EQ("string", returns([] { return "hello"; }));
}

TEST(FunctionRefTest, Equality) {
function_ref<int()> X = [] { return 1; };
function_ref<int()> Y = X;
EXPECT_EQ(X, Y);

const auto Lambda = []() { return 0; };
function_ref<int()> A(Lambda), B(Lambda);
EXPECT_EQ(A, B);
}

} // namespace
1 change: 1 addition & 0 deletions llvm/utils/TableGen/DisassemblerEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "WebAssemblyDisassemblerEmitter.h"
#include "X86DisassemblerTables.h"
#include "X86RecognizableInstr.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
Expand Down
24 changes: 12 additions & 12 deletions llvm/utils/TableGen/IntrinsicEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ class IntrinsicEmitter {
void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints,
bool IsClang, raw_ostream &OS);
};

// Helper class to use with `TableGen::Emitter::OptClass`.
template <bool Enums> class IntrinsicEmitterOpt : public IntrinsicEmitter {
public:
IntrinsicEmitterOpt(const RecordKeeper &R) : IntrinsicEmitter(R) {}
void run(raw_ostream &OS) { IntrinsicEmitter::run(OS, Enums); }
};

} // End anonymous namespace

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -770,16 +778,8 @@ Intrinsic::getIntrinsicFor{1}Builtin(StringRef TargetPrefix,
UpperCompilerName);
}

static void EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS) {
IntrinsicEmitter(RK).run(OS, /*Enums=*/true);
}

static TableGen::Emitter::Opt X("gen-intrinsic-enums", EmitIntrinsicEnums,
"Generate intrinsic enums");

static void EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS) {
IntrinsicEmitter(RK).run(OS, /*Enums=*/false);
}
static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/true>>
X("gen-intrinsic-enums", "Generate intrinsic enums");

static TableGen::Emitter::Opt Y("gen-intrinsic-impl", EmitIntrinsicImpl,
"Generate intrinsic implementation code");
static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/false>>
Y("gen-intrinsic-impl", "Generate intrinsic implementation code");
8 changes: 4 additions & 4 deletions llvm/utils/TableGen/TableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ static cl::opt<std::string> Class("class",
cl::value_desc("class name"),
cl::cat(PrintEnumsCat));

static void PrintRecords(RecordKeeper &Records, raw_ostream &OS) {
static void PrintRecords(const RecordKeeper &Records, raw_ostream &OS) {
OS << Records; // No argument, dump all contents
}

Expand All @@ -49,14 +49,14 @@ static void PrintEnums(RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
}

static void PrintSets(RecordKeeper &Records, raw_ostream &OS) {
static void PrintSets(const RecordKeeper &Records, raw_ostream &OS) {
SetTheory Sets;
Sets.addFieldExpander("Set", "Elements");
for (Record *Rec : Records.getAllDerivedDefinitions("Set")) {
OS << Rec->getName() << " = [";
const std::vector<Record *> *Elts = Sets.expand(Rec);
assert(Elts && "Couldn't expand Set instance");
for (Record *Elt : *Elts)
for (const Record *Elt : *Elts)
OS << ' ' << Elt->getName();
OS << " ]\n";
}
Expand All @@ -67,7 +67,7 @@ static TableGen::Emitter::Opt X[] = {
true},
{"print-detailed-records", EmitDetailedRecords,
"Print full details of all records to stdout"},
{"null-backend", [](RecordKeeper &Records, raw_ostream &OS) {},
{"null-backend", [](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 Down
Loading