[llvm] [TableGen] Emit constexpr versions of some directive/clause functions (PR #194633)
Krzysztof Parzyszek via llvm-commits
llvm-commits at lists.llvm.org
Tue Apr 28 08:57:09 PDT 2026
https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/194633
>From 367d140414858c9a6c6296c32f42d9e632157593 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 28 Apr 2026 08:35:25 -0500
Subject: [PATCH 1/2] [TableGen] Emit constexpr versions of some
directive/clause functions
A variant of https://github.com/llvm/llvm-project/pull/176253 with a
change to reduce compile-time impact.
Since "llvm_unreachable" is actually allowed in constexpr functions,
simply emit the bodies of the selected functions in the header file.
In the previous PR the `isAllowedClauseForDirective` function was made
constexpr, but since it was very long it had a significant impact on
compilation time. In this PR that function is no longer constexpr.
---
llvm/test/TableGen/directive1.td | 53 +++++++++----------
llvm/test/TableGen/directive2.td | 53 +++++++++----------
.../utils/TableGen/Basic/DirectiveEmitter.cpp | 48 ++++++++---------
3 files changed, 73 insertions(+), 81 deletions(-)
diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index 3a9e8701c06eb..060c9d9bbbc49 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -135,6 +135,32 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: constexpr auto TDLCV_valb = AKind::TDLCV_valb;
// CHECK-NEXT: constexpr auto TDLCV_valc = AKind::TDLCV_valc;
// CHECK-EMPTY:
+// CHECK-NEXT: // Constexpr functions.
+// CHECK-EMPTY:
+// CHECK-NEXT: constexpr Association getDirectiveAssociation(Directive Dir) {
+// CHECK-NEXT: switch (Dir) {
+// CHECK-NEXT: case TDLD_dira:
+// CHECK-NEXT: return Association::None;
+// CHECK-NEXT: } // switch (Dir)
+// CHECK-NEXT: llvm_unreachable("Unexpected directive");
+// CHECK-NEXT: }
+// CHECK-EMPTY:
+// CHECK-NEXT: constexpr Category getDirectiveCategory(Directive Dir) {
+// CHECK-NEXT: switch (Dir) {
+// CHECK-NEXT: case TDLD_dira:
+// CHECK-NEXT: return Category::Executable;
+// CHECK-NEXT: } // switch (Dir)
+// CHECK-NEXT: llvm_unreachable("Unexpected directive");
+// CHECK-NEXT: }
+// CHECK-EMPTY:
+// CHECK-NEXT: constexpr SourceLanguage getDirectiveLanguages(Directive D) {
+// CHECK-NEXT: switch (D) {
+// CHECK-NEXT: case TDLD_dira:
+// CHECK-NEXT: return SourceLanguage::C | SourceLanguage::Fortran;
+// CHECK-NEXT: } // switch(D)
+// CHECK-NEXT: llvm_unreachable("Unexpected directive");
+// CHECK-NEXT: }
+// CHECK-EMPTY:
// CHECK-NEXT: // Enumeration helper functions
// CHECK-NEXT: LLVM_ABI std::pair<Directive, directive::VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
// CHECK-NEXT: inline Directive getTdlDirectiveKind(StringRef Str) {
@@ -155,9 +181,6 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: LLVM_ABI bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version);
// CHECK-EMPTY:
// CHECK-NEXT: constexpr std::size_t getMaxLeafCount() { return 0; }
-// CHECK-NEXT: LLVM_ABI Association getDirectiveAssociation(Directive D);
-// CHECK-NEXT: LLVM_ABI Category getDirectiveCategory(Directive D);
-// CHECK-NEXT: LLVM_ABI SourceLanguage getDirectiveLanguages(Directive D);
// CHECK-NEXT: LLVM_ABI AKind getAKind(StringRef Str);
// CHECK-NEXT: LLVM_ABI StringRef getTdlAKindName(AKind x);
// CHECK-EMPTY:
@@ -431,30 +454,6 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind");
// IMPL-NEXT: }
// IMPL-EMPTY:
-// IMPL-NEXT: llvm::tdl::Association llvm::tdl::getDirectiveAssociation(llvm::tdl::Directive Dir) {
-// IMPL-NEXT: switch (Dir) {
-// IMPL-NEXT: case TDLD_dira:
-// IMPL-NEXT: return Association::None;
-// IMPL-NEXT: } // switch (Dir)
-// IMPL-NEXT: llvm_unreachable("Unexpected directive");
-// IMPL-NEXT: }
-// IMPL-EMPTY:
-// IMPL-NEXT: llvm::tdl::Category llvm::tdl::getDirectiveCategory(llvm::tdl::Directive Dir) {
-// IMPL-NEXT: switch (Dir) {
-// IMPL-NEXT: case TDLD_dira:
-// IMPL-NEXT: return Category::Executable;
-// IMPL-NEXT: } // switch (Dir)
-// IMPL-NEXT: llvm_unreachable("Unexpected directive");
-// IMPL-NEXT: }
-// IMPL-EMPTY:
-// IMPL-NEXT: llvm::tdl::SourceLanguage llvm::tdl::getDirectiveLanguages(llvm::tdl::Directive D) {
-// IMPL-NEXT: switch (D) {
-// IMPL-NEXT: case TDLD_dira:
-// IMPL-NEXT: return SourceLanguage::C | SourceLanguage::Fortran;
-// IMPL-NEXT: } // switch(D)
-// IMPL-NEXT: llvm_unreachable("Unexpected directive");
-// IMPL-NEXT: }
-// IMPL-EMPTY:
// IMPL-NEXT: static_assert(sizeof(llvm::tdl::Directive) == sizeof(int));
// IMPL-NEXT: {{.*}} static const llvm::tdl::Directive LeafConstructTable[][2] = {
// IMPL-NEXT: {llvm::tdl::TDLD_dira, static_cast<llvm::tdl::Directive>(0),},
diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index 392423faed36f..e5cc0e677e922 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -111,6 +111,32 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-EMPTY:
// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 4;
// CHECK-EMPTY:
+// CHECK-NEXT: // Constexpr functions.
+// CHECK-EMPTY:
+// CHECK-NEXT: constexpr Association getDirectiveAssociation(Directive Dir) {
+// CHECK-NEXT: switch (Dir) {
+// CHECK-NEXT: case TDLD_dira:
+// CHECK-NEXT: return Association::Block;
+// CHECK-NEXT: } // switch (Dir)
+// CHECK-NEXT: llvm_unreachable("Unexpected directive");
+// CHECK-NEXT: }
+// CHECK-EMPTY:
+// CHECK-NEXT: constexpr Category getDirectiveCategory(Directive Dir) {
+// CHECK-NEXT: switch (Dir) {
+// CHECK-NEXT: case TDLD_dira:
+// CHECK-NEXT: return Category::Declarative;
+// CHECK-NEXT: } // switch (Dir)
+// CHECK-NEXT: llvm_unreachable("Unexpected directive");
+// CHECK-NEXT: }
+// CHECK-EMPTY:
+// CHECK-NEXT: constexpr SourceLanguage getDirectiveLanguages(Directive D) {
+// CHECK-NEXT: switch (D) {
+// CHECK-NEXT: case TDLD_dira:
+// CHECK-NEXT: return SourceLanguage::C | SourceLanguage::Fortran;
+// CHECK-NEXT: } // switch(D)
+// CHECK-NEXT: llvm_unreachable("Unexpected directive");
+// CHECK-NEXT: }
+// CHECK-EMPTY:
// CHECK-NEXT: // Enumeration helper functions
// CHECK-NEXT: LLVM_ABI std::pair<Directive, directive::VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
// CHECK-NEXT: inline Directive getTdlDirectiveKind(StringRef Str) {
@@ -131,9 +157,6 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// CHECK-NEXT: LLVM_ABI bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version);
// CHECK-EMPTY:
// CHECK-NEXT: constexpr std::size_t getMaxLeafCount() { return 0; }
-// CHECK-NEXT: LLVM_ABI Association getDirectiveAssociation(Directive D);
-// CHECK-NEXT: LLVM_ABI Category getDirectiveCategory(Directive D);
-// CHECK-NEXT: LLVM_ABI SourceLanguage getDirectiveLanguages(Directive D);
// CHECK-EMPTY:
// CHECK-NEXT: } // namespace tdl
// CHECK-EMPTY:
@@ -356,30 +379,6 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind");
// IMPL-NEXT: }
// IMPL-EMPTY:
-// IMPL-NEXT: llvm::tdl::Association llvm::tdl::getDirectiveAssociation(llvm::tdl::Directive Dir) {
-// IMPL-NEXT: switch (Dir) {
-// IMPL-NEXT: case TDLD_dira:
-// IMPL-NEXT: return Association::Block;
-// IMPL-NEXT: } // switch (Dir)
-// IMPL-NEXT: llvm_unreachable("Unexpected directive");
-// IMPL-NEXT: }
-// IMPL-EMPTY:
-// IMPL-NEXT: llvm::tdl::Category llvm::tdl::getDirectiveCategory(llvm::tdl::Directive Dir) {
-// IMPL-NEXT: switch (Dir) {
-// IMPL-NEXT: case TDLD_dira:
-// IMPL-NEXT: return Category::Declarative;
-// IMPL-NEXT: } // switch (Dir)
-// IMPL-NEXT: llvm_unreachable("Unexpected directive");
-// IMPL-NEXT: }
-// IMPL-EMPTY:
-// IMPL-NEXT: llvm::tdl::SourceLanguage llvm::tdl::getDirectiveLanguages(llvm::tdl::Directive D) {
-// IMPL-NEXT: switch (D) {
-// IMPL-NEXT: case TDLD_dira:
-// IMPL-NEXT: return SourceLanguage::C | SourceLanguage::Fortran;
-// IMPL-NEXT: } // switch(D)
-// IMPL-NEXT: llvm_unreachable("Unexpected directive");
-// IMPL-NEXT: }
-// IMPL-EMPTY:
// IMPL-NEXT: static_assert(sizeof(llvm::tdl::Directive) == sizeof(int));
// IMPL-NEXT: {{.*}} static const llvm::tdl::Directive LeafConstructTable[][2] = {
// IMPL-NEXT: {llvm::tdl::TDLD_dira, static_cast<llvm::tdl::Directive>(0),},
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index 1126c83034b54..77e4a579131a1 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -34,6 +34,9 @@ namespace {
enum class Frontend { LLVM, Flang, Clang };
} // namespace
+static void emitDirectivesConstexprImpl(const DirectiveLanguage &DirLang,
+ raw_ostream &OS);
+
static StringRef getFESpelling(Frontend FE) {
switch (FE) {
case Frontend::LLVM:
@@ -311,7 +314,11 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
std::string EnumHelperFuncs;
generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
+ // Emit constexpr functions
+ emitDirectivesConstexprImpl(DirLang, OS);
+
// Generic function signatures
+ OS << "\n";
OS << "// Enumeration helper functions\n";
OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> get" << Lang
@@ -346,9 +353,6 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
OS << "\n";
OS << "constexpr std::size_t getMaxLeafCount() { return "
<< getMaxLeafCount(DirLang) << "; }\n";
- OS << "LLVM_ABI Association getDirectiveAssociation(Directive D);\n";
- OS << "LLVM_ABI Category getDirectiveCategory(Directive D);\n";
- OS << "LLVM_ABI SourceLanguage getDirectiveLanguages(Directive D);\n";
OS << EnumHelperFuncs;
} // close DirLangNS
@@ -834,13 +838,9 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
for (const Record *R : DirLang.getDirectives())
CompAssocImpl(R, CompAssocImpl); // Updates AsMap.
- OS << '\n';
-
StringRef Prefix = DirLang.getDirectivePrefix();
- std::string Qual = getQualifier(DirLang);
- OS << Qual << "Association " << Qual << "getDirectiveAssociation(" << Qual
- << "Directive Dir) {\n";
+ OS << "constexpr Association getDirectiveAssociation(Directive Dir) {\n";
OS << " switch (Dir) {\n";
for (const Record *R : DirLang.getDirectives()) {
if (auto F = AsMap.find(R); F != AsMap.end()) {
@@ -855,11 +855,7 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang,
raw_ostream &OS) {
- std::string Qual = getQualifier(DirLang);
-
- OS << '\n';
- OS << Qual << "Category " << Qual << "getDirectiveCategory(" << Qual
- << "Directive Dir) {\n";
+ OS << "constexpr Category getDirectiveCategory(Directive Dir) {\n";
OS << " switch (Dir) {\n";
StringRef Prefix = DirLang.getDirectivePrefix();
@@ -877,11 +873,7 @@ static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang,
static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang,
raw_ostream &OS) {
- std::string Qual = getQualifier(DirLang);
-
- OS << '\n';
- OS << Qual << "SourceLanguage " << Qual << "getDirectiveLanguages(" << Qual
- << "Directive D) {\n";
+ OS << "constexpr SourceLanguage getDirectiveLanguages(Directive D) {\n";
OS << " switch (D) {\n";
StringRef Prefix = DirLang.getDirectivePrefix();
@@ -1310,6 +1302,17 @@ static void generateClauseClassMacro(const DirectiveLanguage &DirLang,
OS << "#undef CLAUSE\n";
}
+static void emitDirectivesConstexprImpl(const DirectiveLanguage &DirLang,
+ raw_ostream &OS) {
+ OS << "// Constexpr functions.\n";
+ OS << "\n";
+ generateGetDirectiveAssociation(DirLang, OS);
+ OS << "\n";
+ generateGetDirectiveCategory(DirLang, OS);
+ OS << "\n";
+ generateGetDirectiveLanguages(DirLang, OS);
+}
+
// Generate the implemenation for the enumeration in the directive
// language. This code can be included in library.
void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
@@ -1344,15 +1347,6 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
// isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)
generateIsAllowedClause(DirLang, OS);
- // getDirectiveAssociation(Directive D)
- generateGetDirectiveAssociation(DirLang, OS);
-
- // getDirectiveCategory(Directive D)
- generateGetDirectiveCategory(DirLang, OS);
-
- // getDirectiveLanguages(Directive D)
- generateGetDirectiveLanguages(DirLang, OS);
-
// Leaf table for getLeafConstructs, etc.
emitLeafTable(DirLang, OS, "LeafConstructTable");
}
>From ae813390d67d8fba275d4e9b81ba07531869a625 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Tue, 28 Apr 2026 10:56:59 -0500
Subject: [PATCH 2/2] Update DirectiveEmitter.cpp
---
llvm/utils/TableGen/Basic/DirectiveEmitter.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index 77e4a579131a1..ba6e10f7042cc 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -314,7 +314,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
std::string EnumHelperFuncs;
generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);
- // Emit constexpr functions
+ // Emit constexpr functions.
emitDirectivesConstexprImpl(DirLang, OS);
// Generic function signatures
More information about the llvm-commits
mailing list