Skip to content

Commit 34dee0a

Browse files
authored
[TableGen] Allow emitter callbacks to use const RecordKeeper & (#104716)
- Refactor TableGen backend options to allow specifying a callback function that takes either a const reference or a non-const reference to `RecordKeeper`. This will enable gradual migration of code to use const references and pointers to `RecordKeeper` and `Record` in the TableGen backends. - Refactor handling of the callback command line options. Move variable for the command line option from the header to the CPP file, and add a function `ApplyCallback` to apply the selected callback. - Change callbacks in TableGen.cpp to take const reference. They use the `Opt` class to register their callbacks. - Change IntrinsicEmitter to use the `OptClass` to define its callbacks. It already uses a const reference in the implementation.
1 parent b1e0589 commit 34dee0a

File tree

8 files changed

+97
-45
lines changed

8 files changed

+97
-45
lines changed

llvm/include/llvm/ADT/STLFunctionalExtras.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ class function_ref<Ret(Params...)> {
6969
}
7070

7171
explicit operator bool() const { return callback; }
72+
73+
bool operator==(const function_ref<Ret(Params...)> &Other) const {
74+
return callable == Other.callable;
75+
}
7276
};
7377

7478
} // end namespace llvm

llvm/include/llvm/TableGen/TableGenBackend.h

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@
1313
#ifndef LLVM_TABLEGEN_TABLEGENBACKEND_H
1414
#define LLVM_TABLEGEN_TABLEGENBACKEND_H
1515

16+
#include "llvm/ADT/STLFunctionalExtras.h"
1617
#include "llvm/ADT/StringRef.h"
17-
#include "llvm/Support/CommandLine.h"
18-
#include "llvm/Support/ManagedStatic.h"
1918
#include "llvm/TableGen/Record.h"
2019

2120
namespace llvm {
@@ -24,36 +23,37 @@ class RecordKeeper;
2423
class raw_ostream;
2524

2625
namespace TableGen::Emitter {
27-
using FnT = void (*)(RecordKeeper &Records, raw_ostream &OS);
28-
29-
struct OptCreatorT {
30-
static void *call();
31-
};
32-
33-
extern ManagedStatic<cl::opt<FnT>, OptCreatorT> Action;
26+
// Supports const and non-const forms of callback functions.
27+
using FnT = function_ref<void(RecordKeeper &Records, raw_ostream &OS)>;
3428

29+
/// Creating an `Opt` object registers the command line option \p Name with
30+
/// TableGen backend and associates the callback \p CB with that option. If
31+
/// \p ByDefault is true, then that callback is applied by default if no
32+
/// command line option was specified.
3533
struct Opt {
36-
Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault = false) {
37-
if (ByDefault)
38-
Action->setInitialValue(CB);
39-
Action->getParser().addLiteralOption(Name, CB, Desc);
40-
}
34+
Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault = false);
4135
};
4236

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

4642
public:
4743
OptClass(StringRef Name, StringRef Desc) : Opt(Name, run, Desc) {}
4844
};
4945

46+
/// Apply callback for any command line option registered above. Returns false
47+
/// is no callback was applied.
48+
bool ApplyCallback(RecordKeeper &Records, raw_ostream &OS);
49+
5050
} // namespace TableGen::Emitter
5151

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

57-
} // End llvm namespace
57+
} // namespace llvm
5858

59-
#endif
59+
#endif // LLVM_TABLEGEN_TABLEGENBACKEND_H

llvm/lib/TableGen/Main.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,10 @@ int llvm::TableGenMain(const char *argv0,
131131
std::string OutString;
132132
raw_string_ostream Out(OutString);
133133
unsigned status = 0;
134-
TableGen::Emitter::FnT ActionFn = TableGen::Emitter::Action->getValue();
135-
if (ActionFn)
136-
ActionFn(Records, Out);
137-
else if (MainFn)
138-
status = MainFn(Out, Records);
139-
else
140-
return 1;
134+
// ApplyCallback will return true if it did not apply any callback. In that
135+
// case, attempt to apply the MainFn.
136+
if (TableGen::Emitter::ApplyCallback(Records, Out))
137+
status = MainFn ? MainFn(Out, Records) : 1;
141138
Records.stopBackendTimer();
142139
if (status)
143140
return 1;

llvm/lib/TableGen/TableGenBackend.cpp

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,62 @@
1212

1313
#include "llvm/TableGen/TableGenBackend.h"
1414
#include "llvm/ADT/Twine.h"
15+
#include "llvm/Support/CommandLine.h"
16+
#include "llvm/Support/ManagedStatic.h"
1517
#include "llvm/Support/Path.h"
1618
#include "llvm/Support/raw_ostream.h"
1719
#include <algorithm>
1820
#include <cassert>
1921
#include <cstddef>
2022

2123
using namespace llvm;
24+
using namespace TableGen::Emitter;
2225

2326
const size_t MAX_LINE_LEN = 80U;
2427

25-
namespace llvm::TableGen::Emitter {
26-
ManagedStatic<cl::opt<FnT>, OptCreatorT> Action;
27-
void *OptCreatorT::call() {
28-
return new cl::opt<FnT>(cl::desc("Action to perform:"));
28+
// CommandLine options of class type are not directly supported with some
29+
// specific exceptions like std::string which are safe to copy. In our case,
30+
// the `FnT` function_ref object is also safe to copy. So provide a
31+
// specialization of `OptionValue` for `FnT` type that stores it as a copy.
32+
// This is essentially similar to OptionValue<std::string> specialization for
33+
// strings.
34+
template <> struct cl::OptionValue<FnT> final : cl::OptionValueCopy<FnT> {
35+
OptionValue() = default;
36+
37+
OptionValue(const FnT &V) { this->setValue(V); }
38+
39+
OptionValue<FnT> &operator=(const FnT &V) {
40+
setValue(V);
41+
return *this;
42+
}
43+
};
44+
45+
namespace {
46+
struct OptCreatorT {
47+
static void *call() {
48+
return new cl::opt<FnT>(cl::desc("Action to perform:"));
49+
}
50+
};
51+
} // namespace
52+
53+
static ManagedStatic<cl::opt<FnT>, OptCreatorT> CallbackFunction;
54+
55+
Opt::Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault) {
56+
if (ByDefault)
57+
CallbackFunction->setInitialValue(CB);
58+
CallbackFunction->getParser().addLiteralOption(Name, CB, Desc);
59+
}
60+
61+
/// Apply callback specified on the command line. Returns true if no callback
62+
/// was applied.
63+
bool llvm::TableGen::Emitter::ApplyCallback(RecordKeeper &Records,
64+
raw_ostream &OS) {
65+
FnT Fn = CallbackFunction->getValue();
66+
if (!Fn)
67+
return true;
68+
Fn(Records, OS);
69+
return false;
2970
}
30-
} // namespace llvm::TableGen::Emitter
3171

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

62-
// Print the filename of source file
102+
// Print the filename of source file.
63103
if (!Record.getInputFilename().empty())
64104
printLine(
65105
OS, Prefix + "From: " + sys::path::filename(Record.getInputFilename()),

llvm/unittests/ADT/FunctionRefTest.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,14 @@ TEST(FunctionRefTest, SFINAE) {
5959
EXPECT_EQ("string", returns([] { return "hello"; }));
6060
}
6161

62+
TEST(FunctionRefTest, Equality) {
63+
function_ref<int()> X = [] { return 1; };
64+
function_ref<int()> Y = X;
65+
EXPECT_EQ(X, Y);
66+
67+
const auto Lambda = []() { return 0; };
68+
function_ref<int()> A(Lambda), B(Lambda);
69+
EXPECT_EQ(A, B);
70+
}
71+
6272
} // namespace

llvm/utils/TableGen/DisassemblerEmitter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "WebAssemblyDisassemblerEmitter.h"
1212
#include "X86DisassemblerTables.h"
1313
#include "X86RecognizableInstr.h"
14+
#include "llvm/Support/CommandLine.h"
1415
#include "llvm/TableGen/Error.h"
1516
#include "llvm/TableGen/Record.h"
1617
#include "llvm/TableGen/TableGenBackend.h"

llvm/utils/TableGen/IntrinsicEmitter.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ class IntrinsicEmitter {
6565
void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints,
6666
bool IsClang, raw_ostream &OS);
6767
};
68+
69+
// Helper class to use with `TableGen::Emitter::OptClass`.
70+
template <bool Enums> class IntrinsicEmitterOpt : public IntrinsicEmitter {
71+
public:
72+
IntrinsicEmitterOpt(const RecordKeeper &R) : IntrinsicEmitter(R) {}
73+
void run(raw_ostream &OS) { IntrinsicEmitter::run(OS, Enums); }
74+
};
75+
6876
} // End anonymous namespace
6977

7078
//===----------------------------------------------------------------------===//
@@ -770,16 +778,8 @@ Intrinsic::getIntrinsicFor{1}Builtin(StringRef TargetPrefix,
770778
UpperCompilerName);
771779
}
772780

773-
static void EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS) {
774-
IntrinsicEmitter(RK).run(OS, /*Enums=*/true);
775-
}
776-
777-
static TableGen::Emitter::Opt X("gen-intrinsic-enums", EmitIntrinsicEnums,
778-
"Generate intrinsic enums");
779-
780-
static void EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS) {
781-
IntrinsicEmitter(RK).run(OS, /*Enums=*/false);
782-
}
781+
static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/true>>
782+
X("gen-intrinsic-enums", "Generate intrinsic enums");
783783

784-
static TableGen::Emitter::Opt Y("gen-intrinsic-impl", EmitIntrinsicImpl,
785-
"Generate intrinsic implementation code");
784+
static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/false>>
785+
Y("gen-intrinsic-impl", "Generate intrinsic implementation code");

llvm/utils/TableGen/TableGen.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ static cl::opt<std::string> Class("class",
3939
cl::value_desc("class name"),
4040
cl::cat(PrintEnumsCat));
4141

42-
static void PrintRecords(RecordKeeper &Records, raw_ostream &OS) {
42+
static void PrintRecords(const RecordKeeper &Records, raw_ostream &OS) {
4343
OS << Records; // No argument, dump all contents
4444
}
4545

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

52-
static void PrintSets(RecordKeeper &Records, raw_ostream &OS) {
52+
static void PrintSets(const RecordKeeper &Records, raw_ostream &OS) {
5353
SetTheory Sets;
5454
Sets.addFieldExpander("Set", "Elements");
5555
for (Record *Rec : Records.getAllDerivedDefinitions("Set")) {
5656
OS << Rec->getName() << " = [";
5757
const std::vector<Record *> *Elts = Sets.expand(Rec);
5858
assert(Elts && "Couldn't expand Set instance");
59-
for (Record *Elt : *Elts)
59+
for (const Record *Elt : *Elts)
6060
OS << ' ' << Elt->getName();
6161
OS << " ]\n";
6262
}
@@ -67,7 +67,7 @@ static TableGen::Emitter::Opt X[] = {
6767
true},
6868
{"print-detailed-records", EmitDetailedRecords,
6969
"Print full details of all records to stdout"},
70-
{"null-backend", [](RecordKeeper &Records, raw_ostream &OS) {},
70+
{"null-backend", [](const RecordKeeper &Records, raw_ostream &OS) {},
7171
"Do nothing after parsing (useful for timing)"},
7272
{"dump-json", EmitJSON, "Dump all records as machine-readable JSON"},
7373
{"print-enums", PrintEnums, "Print enum values for a class"},

0 commit comments

Comments
 (0)