Skip to content

Commit 7c0eb46

Browse files
committed
[TableGen] Allow emitter callback to use const RecordKeeper &
- Refactor TableGen backend options to allow specifying a callback function that takes a const reference to `RecordKeeper`. This will enable gradual migration of code to use const references and pointers to `RecordKeeper` and `Record` in the TableGen backend. Add support for both forms of the callback to both `Opt` and `OptClass`. - 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 define their callbacks. - Change IntrinsicEmitter to use the `OptClass` to define its callbacks. It already uses a const reference.
1 parent 9ebe8b9 commit 7c0eb46

File tree

8 files changed

+98
-45
lines changed

8 files changed

+98
-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: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,65 @@
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+
private:
45+
void anchor() override {}
46+
};
47+
48+
namespace {
49+
struct OptCreatorT {
50+
static void *call() {
51+
return new cl::opt<FnT>(cl::desc("Action to perform:"));
52+
}
53+
};
54+
} // namespace
55+
56+
static ManagedStatic<cl::opt<FnT>, OptCreatorT> CallbackFunction;
57+
58+
Opt::Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault) {
59+
if (ByDefault)
60+
CallbackFunction->setInitialValue(CB);
61+
CallbackFunction->getParser().addLiteralOption(Name, CB, Desc);
62+
}
63+
64+
/// Apply callback specified on the command line. Returns true if no callback
65+
/// was applied.
66+
bool llvm::TableGen::Emitter::ApplyCallback(RecordKeeper &Records,
67+
raw_ostream &OS) {
68+
FnT Fn = CallbackFunction->getValue();
69+
if (!Fn)
70+
return true;
71+
Fn(Records, OS);
72+
return false;
2973
}
30-
} // namespace llvm::TableGen::Emitter
3174

3275
static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill,
3376
StringRef Suffix) {
@@ -59,7 +102,7 @@ void llvm::emitSourceFileHeader(StringRef Desc, raw_ostream &OS,
59102
printLine(OS, Prefix + "Automatically generated file, do not edit!", ' ',
60103
Suffix);
61104

62-
// Print the filename of source file
105+
// Print the filename of source file.
63106
if (!Record.getInputFilename().empty())
64107
printLine(
65108
OS, Prefix + "From: " + sys::path::filename(Record.getInputFilename()),

llvm/unittests/ADT/FunctionRefTest.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,12 @@ 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 = [] { return 2; };
65+
EXPECT_TRUE(!(X == Y));
66+
Y = X;
67+
EXPECT_EQ(X, Y);
68+
}
69+
6270
} // 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
//===----------------------------------------------------------------------===//
@@ -772,16 +780,8 @@ Intrinsic::getIntrinsicFor{1}Builtin(StringRef TargetPrefix,
772780
UpperCompilerName);
773781
}
774782

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

786-
static TableGen::Emitter::Opt Y("gen-intrinsic-impl", EmitIntrinsicImpl,
787-
"Generate intrinsic implementation code");
786+
static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/false>>
787+
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)