Skip to content

Commit 45fc41b

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. - Change global variables in TableGen.cpp to be static instead of being in an anonymous namespace per LLVM coding standards.
1 parent 6a38e19 commit 45fc41b

File tree

6 files changed

+109
-53
lines changed

6 files changed

+109
-53
lines changed

llvm/include/llvm/TableGen/TableGenBackend.h

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
#define LLVM_TABLEGEN_TABLEGENBACKEND_H
1515

1616
#include "llvm/ADT/StringRef.h"
17-
#include "llvm/Support/CommandLine.h"
18-
#include "llvm/Support/ManagedStatic.h"
1917
#include "llvm/TableGen/Record.h"
2018

2119
namespace llvm {
@@ -24,29 +22,38 @@ class RecordKeeper;
2422
class raw_ostream;
2523

2624
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;
25+
// Support const and non-const forms of callback functions.
26+
using FnNonConstT = void (*)(RecordKeeper &Records, raw_ostream &OS);
27+
using FnConstT = void (*)(const 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, FnNonConstT CB, StringRef Desc, bool ByDefault = false);
35+
Opt(StringRef Name, FnConstT CB, StringRef Desc, bool ByDefault = false);
4136
};
4237

38+
/// Convienence wrapper around `Opt` that registers `EmitterClass::run` as the
39+
/// callback.
4340
template <class EmitterC> class OptClass : Opt {
44-
static void run(RecordKeeper &RK, raw_ostream &OS) { EmitterC(RK).run(OS); }
41+
static constexpr bool UsesConstRef =
42+
std::is_invocable_v<decltype(&EmitterC::run), const RecordKeeper &,
43+
raw_ostream>;
44+
using RKType =
45+
std::conditional_t<UsesConstRef, const RecordKeeper &, RecordKeeper &>;
46+
47+
static void run(RKType RK, raw_ostream &OS) { EmitterC(RK).run(OS); }
4548

4649
public:
4750
OptClass(StringRef Name, StringRef Desc) : Opt(Name, run, Desc) {}
4851
};
4952

53+
/// Apply callback for any command line option registered above. Returns false
54+
/// is no callback was applied.
55+
bool ApplyCallback(RecordKeeper &Records, raw_ostream &OS);
56+
5057
} // namespace TableGen::Emitter
5158

5259
/// emitSourceFileHeader - Output an LLVM style file header to the specified

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: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,76 @@
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>
22+
#include <variant>
2023

2124
using namespace llvm;
25+
using namespace TableGen::Emitter;
2226

2327
const size_t MAX_LINE_LEN = 80U;
2428

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:"));
29+
using FnT = std::variant<FnNonConstT, FnConstT>;
30+
31+
// CommandLine options of class type are not directly supported with some
32+
// specific exceptions like std::string which are safe to copy. In our case,
33+
// the `FnT` variant object is also safe to copy. So provide a specialization
34+
// of `OptionValue` for `FnT` type that stores it as a copy. This is essentially
35+
// similar to OptionValue<std::string> specialization for strings.
36+
template <> struct cl::OptionValue<FnT> final : cl::OptionValueCopy<FnT> {
37+
OptionValue() = default;
38+
39+
OptionValue(const FnT &V) { this->setValue(V); }
40+
41+
OptionValue<FnT> &operator=(const FnT &V) {
42+
setValue(V);
43+
return *this;
44+
}
45+
46+
private:
47+
void anchor() override {}
48+
};
49+
50+
namespace {
51+
struct OptCreatorT {
52+
static void *call() {
53+
return new cl::opt<FnT>(cl::desc("Action to perform:"));
54+
}
55+
};
56+
} // namespace
57+
58+
static ManagedStatic<cl::opt<FnT>, OptCreatorT> CallbackFunction;
59+
60+
Opt::Opt(StringRef Name, FnNonConstT CB, StringRef Desc, bool ByDefault) {
61+
if (ByDefault)
62+
CallbackFunction->setInitialValue(CB);
63+
CallbackFunction->getParser().addLiteralOption(Name, FnT(CB), Desc);
64+
}
65+
66+
Opt::Opt(StringRef Name, FnConstT CB, StringRef Desc, bool ByDefault) {
67+
if (ByDefault)
68+
CallbackFunction->setInitialValue(CB);
69+
CallbackFunction->getParser().addLiteralOption(Name, FnT(CB), Desc);
70+
}
71+
72+
/// Apply callback specified on the command line. Returns false is no callback
73+
/// was applied.
74+
bool llvm::TableGen::Emitter::ApplyCallback(RecordKeeper &Records,
75+
raw_ostream &OS) {
76+
const FnT &CallBackFn = *CallbackFunction;
77+
if (auto *Fn = std::get_if<FnNonConstT>(&CallBackFn); Fn && *Fn)
78+
(*Fn)(Records, OS);
79+
else if (auto *Fn = std::get_if<FnConstT>(&CallBackFn); Fn && *Fn)
80+
(*Fn)(Records, OS);
81+
else
82+
return true;
83+
return false;
2984
}
30-
} // namespace llvm::TableGen::Emitter
3185

3286
static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill,
3387
StringRef Suffix) {

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
@@ -63,6 +63,14 @@ class IntrinsicEmitter {
6363
void EmitIntrinsicToBuiltinMap(const CodeGenIntrinsicTable &Ints,
6464
bool IsClang, raw_ostream &OS);
6565
};
66+
67+
// Helper class to use with `TableGen::Emitter::OptClass`.
68+
template <bool Enums> class IntrinsicEmitterOpt : public IntrinsicEmitter {
69+
public:
70+
IntrinsicEmitterOpt(const RecordKeeper &R) : IntrinsicEmitter(R) {}
71+
void run(raw_ostream &OS) { IntrinsicEmitter::run(OS, Enums); }
72+
};
73+
6674
} // End anonymous namespace
6775

6876
//===----------------------------------------------------------------------===//
@@ -681,16 +689,8 @@ void IntrinsicEmitter::EmitIntrinsicToBuiltinMap(
681689
OS << "#endif\n\n";
682690
}
683691

684-
static void EmitIntrinsicEnums(RecordKeeper &RK, raw_ostream &OS) {
685-
IntrinsicEmitter(RK).run(OS, /*Enums=*/true);
686-
}
687-
688-
static TableGen::Emitter::Opt X("gen-intrinsic-enums", EmitIntrinsicEnums,
689-
"Generate intrinsic enums");
690-
691-
static void EmitIntrinsicImpl(RecordKeeper &RK, raw_ostream &OS) {
692-
IntrinsicEmitter(RK).run(OS, /*Enums=*/false);
693-
}
692+
static TableGen::Emitter::OptClass<IntrinsicEmitterOpt</*Enums=*/true>>
693+
X("gen-intrinsic-enums", "Generate intrinsic enums");
694694

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

llvm/utils/TableGen/TableGen.cpp

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,50 +33,47 @@ cl::opt<bool> EmitLongStrLiterals(
3333
cl::Hidden, cl::init(true));
3434
} // end namespace llvm
3535

36-
namespace {
36+
static cl::OptionCategory PrintEnumsCat("Options for -print-enums");
37+
static cl::opt<std::string> Class("class",
38+
cl::desc("Print Enum list for this class"),
39+
cl::value_desc("class name"),
40+
cl::cat(PrintEnumsCat));
3741

38-
cl::OptionCategory PrintEnumsCat("Options for -print-enums");
39-
cl::opt<std::string> Class("class", cl::desc("Print Enum list for this class"),
40-
cl::value_desc("class name"),
41-
cl::cat(PrintEnumsCat));
42-
43-
void PrintRecords(RecordKeeper &Records, raw_ostream &OS) {
42+
static void PrintRecords(const RecordKeeper &Records, raw_ostream &OS) {
4443
OS << Records; // No argument, dump all contents
4544
}
4645

47-
void PrintEnums(RecordKeeper &Records, raw_ostream &OS) {
46+
static void PrintEnums(const RecordKeeper &Records, raw_ostream &OS) {
4847
for (Record *Rec : Records.getAllDerivedDefinitions(Class))
4948
OS << Rec->getName() << ", ";
5049
OS << "\n";
5150
}
5251

53-
void PrintSets(RecordKeeper &Records, raw_ostream &OS) {
52+
static void PrintSets(const RecordKeeper &Records, raw_ostream &OS) {
5453
SetTheory Sets;
5554
Sets.addFieldExpander("Set", "Elements");
5655
for (Record *Rec : Records.getAllDerivedDefinitions("Set")) {
5756
OS << Rec->getName() << " = [";
5857
const std::vector<Record *> *Elts = Sets.expand(Rec);
5958
assert(Elts && "Couldn't expand Set instance");
60-
for (Record *Elt : *Elts)
59+
for (const Record *Elt : *Elts)
6160
OS << ' ' << Elt->getName();
6261
OS << " ]\n";
6362
}
6463
}
6564

66-
TableGen::Emitter::Opt X[] = {
65+
static llvm::TableGen::Emitter::Opt X[] = {
6766
{"print-records", PrintRecords, "Print all records to stdout (default)",
6867
true},
6968
{"print-detailed-records", EmitDetailedRecords,
7069
"Print full details of all records to stdout"},
71-
{"null-backend", [](RecordKeeper &Records, raw_ostream &OS) {},
70+
{"null-backend", [](const RecordKeeper &Records, raw_ostream &OS) {},
7271
"Do nothing after parsing (useful for timing)"},
7372
{"dump-json", EmitJSON, "Dump all records as machine-readable JSON"},
7473
{"print-enums", PrintEnums, "Print enum values for a class"},
7574
{"print-sets", PrintSets, "Print expanded sets for testing DAG exprs"},
7675
};
7776

78-
} // namespace
79-
8077
int main(int argc, char **argv) {
8178
InitLLVM X(argc, argv);
8279
cl::ParseCommandLineOptions(argc, argv);

0 commit comments

Comments
 (0)