[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