Skip to content

Conversation

@kparzysz
Copy link
Contributor

Remove most redundant function calls. Unify enum identifier name generation (via getIdentifierName), and namespace qualification (via getQualifier).

Remove most redundant function calls. Unify enum identifier name
generation (via getIdentifierName), and namespace qualification
(via getQualifier).
@llvmbot
Copy link
Member

llvmbot commented May 20, 2025

@llvm/pr-subscribers-tablegen

Author: Krzysztof Parzyszek (kparzysz)

Changes

Remove most redundant function calls. Unify enum identifier name generation (via getIdentifierName), and namespace qualification (via getQualifier).


Patch is 40.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/140772.diff

2 Files Affected:

  • (modified) llvm/include/llvm/TableGen/DirectiveEmitter.h (+6-3)
  • (modified) llvm/utils/TableGen/Basic/DirectiveEmitter.cpp (+229-226)
diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h
index 234979eebc881..6defc8722d810 100644
--- a/llvm/include/llvm/TableGen/DirectiveEmitter.h
+++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h
@@ -113,20 +113,23 @@ class BaseRecord {
 
   // Returns the name of the directive formatted for output. Whitespace are
   // replaced with underscores.
-  static std::string getFormattedName(const Record *R) {
-    StringRef Name = R->getValueAsString("name");
+  static std::string formatName(StringRef Name) {
     std::string N = Name.str();
     llvm::replace(N, ' ', '_');
     return N;
   }
 
-  std::string getFormattedName() const { return getFormattedName(Def); }
+  std::string getFormattedName() const {
+    return formatName(Def->getValueAsString("name"));
+  }
 
   bool isDefault() const { return Def->getValueAsBit("isDefault"); }
 
   // Returns the record name.
   StringRef getRecordName() const { return Def->getName(); }
 
+  const Record *getRecord() const { return Def; }
+
 protected:
   const Record *Def;
 };
diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
index acad5fe6f2cf3..3d1795c5a6ff5 100644
--- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
@@ -45,17 +45,55 @@ class IfDefScope {
 };
 } // namespace
 
+namespace {
+enum class Frontend { LLVM, Flang, Clang };
+
+StringRef getFESpelling(Frontend FE) {
+  switch (FE) {
+  case Frontend::LLVM:
+    return "llvm";
+  case Frontend::Flang:
+    return "flang";
+  case Frontend::Clang:
+    return "clang";
+  }
+  llvm_unreachable("unknown FE kind");
+}
+} // namespace
+
+// Get the full namespace qualifier for the directive language.
+static std::string getQualifier(const DirectiveLanguage &DirLang,
+                                Frontend FE = Frontend::LLVM) {
+  return (Twine(getFESpelling(FE)) + "::" + DirLang.getCppNamespace().str() +
+          "::")
+      .str();
+}
+
+// Get prefixed formatted name, e.g. for "target data", get "OMPD_target_data".
+// This should work for any Record as long as BaseRecord::getFormattedName
+// works.
+static std::string getIdentifierName(const Record *Rec, StringRef Prefix) {
+  return Prefix.str() + BaseRecord(Rec).getFormattedName();
+}
+
+static void generateEnumExports(ArrayRef<const Record *> Records,
+                                raw_ostream &OS, StringRef Enum,
+                                StringRef Prefix) {
+  for (const Record *R : Records) {
+    std::string N = getIdentifierName(R, Prefix);
+    OS << "constexpr auto " << N << " = " << Enum << "::" << N << ";\n";
+  }
+}
+
 // Generate enum class. Entries are emitted in the order in which they appear
 // in the `Records` vector.
 static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS,
                               StringRef Enum, StringRef Prefix,
-                              const DirectiveLanguage &DirLang,
                               bool ExportEnums) {
   OS << "\n";
   OS << "enum class " << Enum << " {\n";
-  for (const auto &R : Records) {
-    BaseRecord Rec(R);
-    OS << "  " << Prefix << Rec.getFormattedName() << ",\n";
+  for (const Record *R : Records) {
+    OS << "  " << getIdentifierName(R, Prefix) << ",\n";
   }
   OS << "};\n";
   OS << "\n";
@@ -69,11 +107,7 @@ static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS,
   // cast.
   if (ExportEnums) {
     OS << "\n";
-    for (const auto &R : Records) {
-      BaseRecord Rec(R);
-      OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
-         << Enum << "::" << Prefix << Rec.getFormattedName() << ";\n";
-    }
+    generateEnumExports(Records, OS, Enum, Prefix);
   }
 }
 
@@ -82,9 +116,7 @@ static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS,
 // vector.
 static void generateEnumBitmask(ArrayRef<const Record *> Records,
                                 raw_ostream &OS, StringRef Enum,
-                                StringRef Prefix,
-                                const DirectiveLanguage &DirLang,
-                                bool ExportEnums) {
+                                StringRef Prefix, bool ExportEnums) {
   assert(Records.size() <= 64 && "Too many values for a bitmask");
   StringRef Type = Records.size() <= 32 ? "uint32_t" : "uint64_t";
   StringRef TypeSuffix = Records.size() <= 32 ? "U" : "ULL";
@@ -93,8 +125,7 @@ static void generateEnumBitmask(ArrayRef<const Record *> Records,
   OS << "enum class " << Enum << " : " << Type << " {\n";
   std::string LastName;
   for (auto [I, R] : llvm::enumerate(Records)) {
-    BaseRecord Rec(R);
-    LastName = Prefix.str() + Rec.getFormattedName();
+    LastName = getIdentifierName(R, Prefix);
     OS << "  " << LastName << " = " << (1ull << I) << TypeSuffix << ",\n";
   }
   OS << "  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/" << LastName << ")\n";
@@ -110,11 +141,7 @@ static void generateEnumBitmask(ArrayRef<const Record *> Records,
   // cast.
   if (ExportEnums) {
     OS << "\n";
-    for (const auto &R : Records) {
-      BaseRecord Rec(R);
-      OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = "
-         << Enum << "::" << Prefix << Rec.getFormattedName() << ";\n";
-    }
+    generateEnumExports(Records, OS, Enum, Prefix);
   }
 }
 
@@ -124,21 +151,21 @@ static void generateEnumClauseVal(ArrayRef<const Record *> Records,
                                   raw_ostream &OS,
                                   const DirectiveLanguage &DirLang,
                                   std::string &EnumHelperFuncs) {
-  for (const auto &R : Records) {
+  for (const Record *R : Records) {
     Clause C(R);
     const auto &ClauseVals = C.getClauseVals();
     if (ClauseVals.size() <= 0)
       continue;
 
-    const auto &EnumName = C.getEnumName();
-    if (EnumName.empty()) {
+    StringRef Enum = C.getEnumName();
+    if (Enum.empty()) {
       PrintError("enumClauseValue field not set in Clause" +
                  C.getFormattedName() + ".");
       return;
     }
 
     OS << "\n";
-    OS << "enum class " << EnumName << " {\n";
+    OS << "enum class " << Enum << " {\n";
     for (const ClauseVal CVal : ClauseVals)
       OS << "  " << CVal.getRecordName() << "=" << CVal.getValue() << ",\n";
     OS << "};\n";
@@ -146,16 +173,16 @@ static void generateEnumClauseVal(ArrayRef<const Record *> Records,
     if (DirLang.hasMakeEnumAvailableInNamespace()) {
       OS << "\n";
       for (const auto &CV : ClauseVals) {
-        OS << "constexpr auto " << CV->getName() << " = " << EnumName
+        OS << "constexpr auto " << CV->getName() << " = " << Enum
            << "::" << CV->getName() << ";\n";
       }
-      EnumHelperFuncs += (Twine("LLVM_ABI ") + Twine(EnumName) + Twine(" get") +
-                          Twine(EnumName) + Twine("(StringRef Str);\n"))
+      EnumHelperFuncs += (Twine("LLVM_ABI ") + Twine(Enum) + Twine(" get") +
+                          Twine(Enum) + Twine("(StringRef Str);\n"))
                              .str();
 
       EnumHelperFuncs +=
           (Twine("LLVM_ABI StringRef get") + Twine(DirLang.getName()) +
-           Twine(EnumName) + Twine("Name(") + Twine(EnumName) + Twine(" x);\n"))
+           Twine(Enum) + Twine("Name(") + Twine(Enum) + Twine(" x);\n"))
               .str();
     }
   }
@@ -231,8 +258,10 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
   if (DirLang.HasValidityErrors())
     return;
 
-  OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n";
-  OS << "#define LLVM_" << DirLang.getName() << "_INC\n";
+  StringRef Lang = DirLang.getName();
+
+  OS << "#ifndef LLVM_" << Lang << "_INC\n";
+  OS << "#define LLVM_" << Lang << "_INC\n";
   OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n";
 
   if (DirLang.hasEnableBitmaskEnumInNamespace())
@@ -259,22 +288,22 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
           // Skip the "special" value
           [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; });
   generateEnumClass(Associations, OS, "Association",
-                    /*Prefix=*/"", DirLang, /*ExportEnums=*/false);
+                    /*Prefix=*/"", /*ExportEnums=*/false);
 
   generateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"",
-                    DirLang, /*ExportEnums=*/false);
+                    /*ExportEnums=*/false);
 
   generateEnumBitmask(DirLang.getSourceLanguages(), OS, "SourceLanguage",
-                      /*Prefix=*/"", DirLang, /*ExportEnums=*/false);
+                      /*Prefix=*/"", /*ExportEnums=*/false);
 
   // Emit Directive enumeration
   generateEnumClass(DirLang.getDirectives(), OS, "Directive",
-                    DirLang.getDirectivePrefix(), DirLang,
+                    DirLang.getDirectivePrefix(),
                     DirLang.hasMakeEnumAvailableInNamespace());
 
   // Emit Clause enumeration
   generateEnumClass(DirLang.getClauses(), OS, "Clause",
-                    DirLang.getClausePrefix(), DirLang,
+                    DirLang.getClausePrefix(),
                     DirLang.hasMakeEnumAvailableInNamespace());
 
   // Emit ClauseVal enumeration
@@ -284,9 +313,9 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
   // Generic function signatures
   OS << "\n";
   OS << "// Enumeration helper functions\n";
-  OS << "LLVM_ABI Directive get" << DirLang.getName()
-     << "DirectiveKind(StringRef Str);\n";
+  OS << "LLVM_ABI Directive get" << Lang << "DirectiveKind(StringRef Str);\n";
   OS << "\n";
+
   // For OpenMP the signature is
   //   getOpenMPDirectiveName(Directive D, unsigned V)
   OS << "LLVM_ABI StringRef get" << DirLang.getName()
@@ -295,11 +324,10 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
     OS << ", unsigned = 0";
   OS << ");\n";
   OS << "\n";
-  OS << "LLVM_ABI Clause get" << DirLang.getName()
-     << "ClauseKind(StringRef Str);\n";
+
+  OS << "LLVM_ABI Clause get" << Lang << "ClauseKind(StringRef Str);\n";
   OS << "\n";
-  OS << "LLVM_ABI StringRef get" << DirLang.getName()
-     << "ClauseName(Clause C);\n";
+  OS << "LLVM_ABI StringRef get" << Lang << "ClauseName(Clause C);\n";
   OS << "\n";
   OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "
      << "Version.\n";
@@ -322,30 +350,30 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
 
   OS << "} // namespace llvm\n";
 
-  OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n";
+  OS << "#endif // LLVM_" << Lang << "_INC\n";
 }
 
 // Generate function implementation for get<Enum>Name(StringRef Str)
 static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,
                             StringRef Enum, const DirectiveLanguage &DirLang,
                             StringRef Prefix) {
+  StringRef Lang = DirLang.getName();
+  std::string Qual = getQualifier(DirLang);
   // For OpenMP the "Directive" signature is
   //   getOpenMPDirectiveName(Directive D, unsigned V)
   OS << "\n";
-  OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
-     << DirLang.getName() << Enum << "Name(llvm::" << DirLang.getCppNamespace()
-     << "::" << Enum << " Kind";
+  OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual
+     << Enum << " Kind";
   if (DirLang.getCppNamespace() == "omp" && Enum == "Directive")
     OS << ", unsigned";
   OS << ") {\n";
   OS << "  switch (Kind) {\n";
-  for (const BaseRecord Rec : Records) {
-    OS << "    case " << Prefix << Rec.getFormattedName() << ":\n";
-    OS << "      return \"" << Rec.getName() << "\";\n";
+  for (const Record *R : Records) {
+    OS << "    case " << getIdentifierName(R, Prefix) << ":\n";
+    OS << "      return \"" << BaseRecord(R).getName() << "\";\n";
   }
   OS << "  }\n"; // switch
-  OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum
-     << " kind\");\n";
+  OS << "  llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n";
   OS << "}\n";
 }
 
@@ -363,30 +391,33 @@ static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS,
   }
 
   BaseRecord DefaultRec(*DefaultIt);
+  std::string Qual = getQualifier(DirLang);
+  std::string DefaultName = getIdentifierName(*DefaultIt, Prefix);
 
   OS << "\n";
-  OS << "llvm::" << DirLang.getCppNamespace() << "::" << Enum
-     << " llvm::" << DirLang.getCppNamespace() << "::get" << DirLang.getName()
-     << Enum << "Kind(llvm::StringRef Str) {\n";
+  OS << Qual << Enum << " " << Qual << "get" << DirLang.getName() << Enum
+     << "Kind(llvm::StringRef Str) {\n";
   OS << "  return StringSwitch<" << Enum << ">(Str)\n";
 
-  for (const auto &R : Records) {
+  for (const Record *R : Records) {
     BaseRecord Rec(R);
     if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
-      OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
-         << DefaultRec.getFormattedName() << ")\n";
+      OS << "    .Case(\"" << Rec.getName() << "\"," << DefaultName << ")\n";
     } else {
-      OS << "    .Case(\"" << Rec.getName() << "\"," << Prefix
-         << Rec.getFormattedName() << ")\n";
+      OS << "    .Case(\"" << Rec.getName() << "\","
+         << getIdentifierName(R, Prefix) << ")\n";
     }
   }
-  OS << "    .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n";
+  OS << "    .Default(" << DefaultName << ");\n";
   OS << "}\n";
 }
 
 // Generate function implementation for get<ClauseVal>Kind(StringRef Str)
 static void generateGetKindClauseVal(const DirectiveLanguage &DirLang,
                                      raw_ostream &OS) {
+  StringRef Lang = DirLang.getName();
+  std::string Qual = getQualifier(DirLang);
+
   for (const Clause C : DirLang.getClauses()) {
     const auto &ClauseVals = C.getClauseVals();
     if (ClauseVals.size() <= 0)
@@ -403,18 +434,17 @@ static void generateGetKindClauseVal(const DirectiveLanguage &DirLang,
     }
     const auto DefaultName = (*DefaultIt)->getName();
 
-    const auto &EnumName = C.getEnumName();
-    if (EnumName.empty()) {
+    StringRef Enum = C.getEnumName();
+    if (Enum.empty()) {
       PrintError("enumClauseValue field not set in Clause" +
                  C.getFormattedName() + ".");
       return;
     }
 
     OS << "\n";
-    OS << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName
-       << " llvm::" << DirLang.getCppNamespace() << "::get" << EnumName
+    OS << Qual << Enum << " " << Qual << "get" << Enum
        << "(llvm::StringRef Str) {\n";
-    OS << "  return StringSwitch<" << EnumName << ">(Str)\n";
+    OS << "  return StringSwitch<" << Enum << ">(Str)\n";
     for (const auto &CV : ClauseVals) {
       ClauseVal CVal(CV);
       OS << "    .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName()
@@ -424,10 +454,8 @@ static void generateGetKindClauseVal(const DirectiveLanguage &DirLang,
     OS << "}\n";
 
     OS << "\n";
-    OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get"
-       << DirLang.getName() << EnumName
-       << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName
-       << " x) {\n";
+    OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual
+       << Enum << " x) {\n";
     OS << "  switch (x) {\n";
     for (const auto &CV : ClauseVals) {
       ClauseVal CVal(CV);
@@ -435,57 +463,46 @@ static void generateGetKindClauseVal(const DirectiveLanguage &DirLang,
       OS << "      return \"" << CVal.getFormattedName() << "\";\n";
     }
     OS << "  }\n"; // switch
-    OS << "  llvm_unreachable(\"Invalid " << DirLang.getName() << " "
-       << EnumName << " kind\");\n";
+    OS << "  llvm_unreachable(\"Invalid " << Lang << " " << Enum
+       << " kind\");\n";
     OS << "}\n";
   }
 }
 
-static void generateCaseForVersionedClauses(ArrayRef<const Record *> Clauses,
+static void generateCaseForVersionedClauses(ArrayRef<const Record *> VerClauses,
                                             raw_ostream &OS,
                                             const DirectiveLanguage &DirLang,
                                             StringSet<> &Cases) {
-  for (const VersionedClause VerClause : Clauses) {
-    const auto ClauseFormattedName = VerClause.getClause().getFormattedName();
-
-    if (Cases.insert(ClauseFormattedName).second) {
-      OS << "        case " << DirLang.getClausePrefix() << ClauseFormattedName
-         << ":\n";
+  StringRef Prefix = DirLang.getClausePrefix();
+  for (const Record *R : VerClauses) {
+    VersionedClause VerClause(R);
+    std::string Name =
+        getIdentifierName(VerClause.getClause().getRecord(), Prefix);
+    if (Cases.insert(Name).second) {
+      OS << "        case " << Name << ":\n";
       OS << "          return " << VerClause.getMinVersion()
          << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";
     }
   }
 }
 
-static std::string getDirectiveName(const DirectiveLanguage &DirLang,
-                                    const Record *Rec) {
-  Directive Dir(Rec);
-  return (Twine("llvm::") + DirLang.getCppNamespace() +
-          "::" + DirLang.getDirectivePrefix() + Dir.getFormattedName())
-      .str();
-}
-
-static std::string getDirectiveType(const DirectiveLanguage &DirLang) {
-  return (Twine("llvm::") + DirLang.getCppNamespace() + "::Directive").str();
-}
-
 // Generate the isAllowedClauseForDirective function implementation.
 static void generateIsAllowedClause(const DirectiveLanguage &DirLang,
                                     raw_ostream &OS) {
+  std::string Qual = getQualifier(DirLang);
+
   OS << "\n";
-  OS << "bool llvm::" << DirLang.getCppNamespace()
-     << "::isAllowedClauseForDirective("
-     << "llvm::" << DirLang.getCppNamespace()
-     << "::Directive D, llvm::" << DirLang.getCppNamespace()
-     << "::Clause C, unsigned Version) {\n";
+  OS << "bool " << Qual << "isAllowedClauseForDirective(" << Qual
+     << "Directive D, " << Qual << "Clause C, unsigned Version) {\n";
   OS << "  assert(unsigned(D) <= Directive_enumSize);\n";
   OS << "  assert(unsigned(C) <= Clause_enumSize);\n";
 
   OS << "  switch (D) {\n";
 
-  for (const Directive Dir : DirLang.getDirectives()) {
-    OS << "    case " << DirLang.getDirectivePrefix() << Dir.getFormattedName()
-       << ":\n";
+  StringRef Prefix = DirLang.getDirectivePrefix();
+  for (const Record *R : DirLang.getDirectives()) {
+    Directive Dir(R);
+    OS << "    case " << getIdentifierName(R, Prefix) << ":\n";
     if (Dir.getAllowedClauses().empty() &&
         Dir.getAllowedOnceClauses().empty() &&
         Dir.getAllowedExclusiveClauses().empty() &&
@@ -611,19 +628,22 @@ static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS,
   // type is `int` (by default). The code above uses `int` to store directive
   // ids, so make sure that we catch it when something changes in the
   // underlying type.
-  std::string DirectiveType = getDirectiveType(DirLang);
+  StringRef Prefix = DirLang.getDirectivePrefix();
+  std::string Qual = getQualifier(DirLang);
+  std::string DirectiveType = Qual + "Directive";
   OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n";
 
   OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName
      << "[][" << MaxLeafCount + 2 << "] = {\n";
   for (size_t I = 0, E = Directives.size(); I != E; ++I) {
     auto &Leaves = LeafTable[Ordering[I]];
-    OS << "    {" << getDirectiveName(DirLang, Directives[Leaves[0]]);
+    OS << "    {" << Qual << getIdentifierName(Directives[Leaves[0]], Prefix);
     OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),";
     for (size_t I = 2, E = Leaves.size(); I != E; ++I) {
       int Idx = Leaves[I];
       if (Idx >= 0)
-        OS << ' ' << getDirectiveName(DirLang, Directives[Leaves[I]]) << ',';
+        OS << ' ' << Qual << getIdentifierName(Directives[Leaves[I]], Prefix)
+           << ',';
       else
         OS << " static_cast<" << DirectiveType << ">(-1),";
     }
@@ -761,18 +781,15 @@ static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang,
 
   OS << '\n';
 
-  std::string DirectiveTypeName =
-      "llvm::" + DirLang.getCppNamespace().str() + "::Directive";
+  StringRef Prefix = DirLang.g...
[truncated]

Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, nice cleanup

Copy link
Contributor

@clementval clementval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kparzysz kparzysz merged commit 70f9a81 into main May 21, 2025
13 checks passed
@kparzysz kparzysz deleted the users/kparzysz/spr/t03-cleanup branch May 21, 2025 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants