[llvm] [NFC][TableGen] Adopt CodeGenHelpers in SubtargetEmitter (PR #163820)

via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 29 12:43:55 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-tablegen

Author: Rahul Joshi (jurahul)

<details>
<summary>Changes</summary>

- Adopt ifdef and namespace emitters in SubtargeEmitter.
- To aid that, factor out emission of different sections of the code into individual helper functions.

---
Full diff: https://github.com/llvm/llvm-project/pull/163820.diff


2 Files Affected:

- (modified) llvm/include/llvm/TableGen/CodeGenHelpers.h (+37-7) 
- (modified) llvm/utils/TableGen/SubtargetEmitter.cpp (+68-70) 


``````````diff
diff --git a/llvm/include/llvm/TableGen/CodeGenHelpers.h b/llvm/include/llvm/TableGen/CodeGenHelpers.h
index e22c6d4f6d390..053f7e4aab866 100644
--- a/llvm/include/llvm/TableGen/CodeGenHelpers.h
+++ b/llvm/include/llvm/TableGen/CodeGenHelpers.h
@@ -20,18 +20,37 @@
 #include <string>
 
 namespace llvm {
-// Simple RAII helper for emitting ifdef-undef-endif scope.
+// Simple RAII helper for emitting ifdef-undef-endif scope. `LateUndef` controls
+// whether the undef is emitted at the start of the scope (false) or at the end
+// of the scope (true).
 class IfDefEmitter {
 public:
-  IfDefEmitter(raw_ostream &OS, StringRef Name) : Name(Name.str()), OS(OS) {
-    OS << "#ifdef " << Name << "\n"
-       << "#undef " << Name << "\n\n";
+  IfDefEmitter(raw_ostream &OS, StringRef Name, bool LateUndef = false)
+      : Name(Name.str()), OS(OS), LateUndef(LateUndef) {
+    OS << "#ifdef " << Name << "\n";
+    if (!LateUndef)
+      OS << "#undef " << Name << "\n";
+    OS << "\n";
+  }
+  ~IfDefEmitter() { close(); }
+
+  // Explicit function to close the ifdef scopes.
+  void close() {
+    if (Closed)
+      return;
+
+    OS << "\n";
+    if (LateUndef)
+      OS << "#undef " << Name << "\n";
+    OS << "#endif // " << Name << "\n\n";
+    Closed = true;
   }
-  ~IfDefEmitter() { OS << "\n#endif // " << Name << "\n\n"; }
 
 private:
   std::string Name;
   raw_ostream &OS;
+  bool LateUndef;
+  bool Closed = false;
 };
 
 // Simple RAII helper for emitting header include guard (ifndef-define-endif).
@@ -42,11 +61,20 @@ class IncludeGuardEmitter {
     OS << "#ifndef " << Name << "\n"
        << "#define " << Name << "\n\n";
   }
-  ~IncludeGuardEmitter() { OS << "\n#endif // " << Name << "\n"; }
+  ~IncludeGuardEmitter() { close(); }
+
+  // Explicit function to close the ifdef scopes.
+  void close() {
+    if (Closed)
+      return;
+    OS << "\n#endif // " << Name << "\n\n";
+    Closed = true;
+  }
 
 private:
   std::string Name;
   raw_ostream &OS;
+  bool Closed = false;
 };
 
 // Simple RAII helper for emitting namespace scope. Name can be a single
@@ -64,7 +92,9 @@ class NamespaceEmitter {
 
   // Explicit function to close the namespace scopes.
   void close() {
-    if (!Closed && !Name.empty())
+    if (Closed)
+      return;
+    if (!Name.empty())
       OS << "} // namespace " << Name << "\n";
     Closed = true;
   }
diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp
index 2f15cc8c76548..c3fb089d3f608 100644
--- a/llvm/utils/TableGen/SubtargetEmitter.cpp
+++ b/llvm/utils/TableGen/SubtargetEmitter.cpp
@@ -27,6 +27,7 @@
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Format.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/TableGen/CodeGenHelpers.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
 #include "llvm/TableGen/StringToOffsetTable.h"
@@ -75,7 +76,15 @@ class SubtargetEmitter : TargetFeaturesEmitter {
   CodeGenTarget TGT;
   CodeGenSchedModels &SchedModels;
 
+  FeatureMapTy emitEnums(raw_ostream &OS);
   void emitSubtargetInfoMacroCalls(raw_ostream &OS);
+  std::tuple<unsigned, unsigned, unsigned>
+  emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap);
+  void emitTargetDesc(raw_ostream &OS);
+  void emitHeader(raw_ostream &OS);
+  void emitCtor(raw_ostream &OS, unsigned NumNames, unsigned NumFeatures,
+                unsigned NumProcs);
+
   unsigned featureKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
   unsigned cpuKeyValues(raw_ostream &OS, const FeatureMapTy &FeatureMap);
   unsigned cpuNames(raw_ostream &OS);
@@ -141,7 +150,9 @@ class SubtargetEmitter : TargetFeaturesEmitter {
 /// Emit some information about the SubtargetFeature as calls to a macro so
 /// that they can be used from C++.
 void SubtargetEmitter::emitSubtargetInfoMacroCalls(raw_ostream &OS) {
-  OS << "\n#ifdef GET_SUBTARGETINFO_MACRO\n";
+  // Undef the GET_SUBTARGETINFO_MACRO macro at the end of the scope since its
+  // used within the scope.
+  IfDefEmitter IfDefMacro(OS, "GET_SUBTARGETINFO_MACRO", /*LateUndef=*/true);
 
   std::vector<const Record *> FeatureList =
       Records.getAllDerivedDefinitions("SubtargetFeature");
@@ -167,14 +178,6 @@ void SubtargetEmitter::emitSubtargetInfoMacroCalls(raw_ostream &OS) {
     OS << "GET_SUBTARGETINFO_MACRO(" << FieldName << ", " << Default << ", "
        << Getter << ")\n";
   }
-  OS << "#undef GET_SUBTARGETINFO_MACRO\n";
-  OS << "#endif // GET_SUBTARGETINFO_MACRO\n\n";
-
-  OS << "\n#ifdef GET_SUBTARGETINFO_MC_DESC\n";
-  OS << "#undef GET_SUBTARGETINFO_MC_DESC\n\n";
-
-  if (Target == "AArch64")
-    OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";
 }
 
 //
@@ -440,26 +443,24 @@ void SubtargetEmitter::emitStageAndOperandCycleData(
       continue;
 
     StringRef Name = ProcModel.ItinsDef->getName();
-    OS << "\n// Functional units for \"" << Name << "\"\n"
-       << "namespace " << Name << "FU {\n";
+    OS << "\n// Functional units for \"" << Name << "\"\n";
+    NamespaceEmitter FUNamespace(OS, (Name + Twine("FU")).str());
 
     for (const auto &[Idx, FU] : enumerate(FUs))
       OS << "  const InstrStage::FuncUnits " << FU->getName() << " = 1ULL << "
          << Idx << ";\n";
 
-    OS << "} // end namespace " << Name << "FU\n";
+    FUNamespace.close();
 
     ConstRecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP");
     if (BPs.empty())
       continue;
-    OS << "\n// Pipeline forwarding paths for itineraries \"" << Name << "\"\n"
-       << "namespace " << Name << "Bypass {\n";
+    OS << "\n// Pipeline forwarding paths for itineraries \"" << Name << "\"\n";
+    NamespaceEmitter BypassNamespace(OS, (Name + Twine("Bypass")).str());
 
     OS << "  const unsigned NoBypass = 0;\n";
     for (const auto &[Idx, BP] : enumerate(BPs))
       OS << "  const unsigned " << BP->getName() << " = 1 << " << Idx << ";\n";
-
-    OS << "} // end namespace " << Name << "Bypass\n";
   }
 
   // Begin stages table
@@ -1940,13 +1941,13 @@ void SubtargetEmitter::parseFeaturesFunction(raw_ostream &OS) {
 }
 
 void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
-  OS << "namespace " << Target << "_MC {\n"
-     << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"
+  NamespaceEmitter NS(OS, (Target + Twine("_MC")).str());
+  OS << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,\n"
      << "    const MCInst *MI, const MCInstrInfo *MCII, "
      << "const MCSubtargetInfo &STI, unsigned CPUID) {\n";
   emitSchedModelHelpersImpl(OS, /* OnlyExpandMCPredicates */ true);
   OS << "}\n";
-  OS << "} // end namespace " << Target << "_MC\n\n";
+  NS.close();
 
   OS << "struct " << Target
      << "GenMCSubtargetInfo : public MCSubtargetInfo {\n";
@@ -1982,8 +1983,7 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) {
 }
 
 void SubtargetEmitter::emitMcInstrAnalysisPredicateFunctions(raw_ostream &OS) {
-  OS << "\n#ifdef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n";
-  OS << "#undef GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
+  IfDefEmitter IfDefDecls(OS, "GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS");
 
   STIPredicateExpander PE(Target, /*Indent=*/0);
   PE.setExpandForMC(true);
@@ -1991,37 +1991,29 @@ void SubtargetEmitter::emitMcInstrAnalysisPredicateFunctions(raw_ostream &OS) {
   for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
     PE.expandSTIPredicate(OS, Fn);
 
-  OS << "#endif // GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS\n\n";
-
-  OS << "\n#ifdef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n";
-  OS << "#undef GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
+  IfDefDecls.close();
 
+  IfDefEmitter IfDefDefs(OS, "GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS");
   std::string ClassPrefix = Target + "MCInstrAnalysis";
   PE.setExpandDefinition(true);
   PE.setClassPrefix(ClassPrefix);
   for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
     PE.expandSTIPredicate(OS, Fn);
-
-  OS << "#endif // GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS\n\n";
 }
 
-//
-// SubtargetEmitter::run - Main subtarget enumeration emitter.
-//
-void SubtargetEmitter::run(raw_ostream &OS) {
-  emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
-
-  OS << "\n#ifdef GET_SUBTARGETINFO_ENUM\n";
-  OS << "#undef GET_SUBTARGETINFO_ENUM\n\n";
-
-  OS << "namespace llvm {\n";
-  auto FeatureMap = enumeration(OS);
-  OS << "} // end namespace llvm\n\n";
-  OS << "#endif // GET_SUBTARGETINFO_ENUM\n\n";
+FeatureMapTy SubtargetEmitter::emitEnums(raw_ostream &OS) {
+  IfDefEmitter IfDef(OS, "GET_SUBTARGETINFO_ENUM");
+  NamespaceEmitter NS(OS, "llvm");
+  return enumeration(OS);
+}
 
-  emitSubtargetInfoMacroCalls(OS);
+std::tuple<unsigned, unsigned, unsigned>
+SubtargetEmitter::emitMCDesc(raw_ostream &OS, const FeatureMapTy &FeatureMap) {
+  IfDefEmitter IfDef(OS, "GET_SUBTARGETINFO_MC_DESC");
+  if (Target == "AArch64")
+    OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";
+  NamespaceEmitter LlvmNS(OS, "llvm");
 
-  OS << "namespace llvm {\n";
   unsigned NumFeatures = featureKeyValues(OS, FeatureMap);
   OS << "\n";
   emitSchedModel(OS);
@@ -2067,13 +2059,11 @@ void SubtargetEmitter::run(raw_ostream &OS) {
     OS << "nullptr, nullptr, nullptr";
   }
   OS << ");\n}\n\n";
+  return {NumNames, NumFeatures, NumProcs};
+}
 
-  OS << "} // end namespace llvm\n\n";
-
-  OS << "#endif // GET_SUBTARGETINFO_MC_DESC\n\n";
-
-  OS << "\n#ifdef GET_SUBTARGETINFO_TARGET_DESC\n";
-  OS << "#undef GET_SUBTARGETINFO_TARGET_DESC\n\n";
+void SubtargetEmitter::emitTargetDesc(raw_ostream &OS) {
+  IfDefEmitter IfDef(OS, "GET_SUBTARGETINFO_TARGET_DESC");
 
   OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
   OS << "#include \"llvm/Support/Debug.h\"\n";
@@ -2081,21 +2071,21 @@ void SubtargetEmitter::run(raw_ostream &OS) {
   if (Target == "AArch64")
     OS << "#include \"llvm/TargetParser/AArch64TargetParser.h\"\n\n";
   parseFeaturesFunction(OS);
+}
 
-  OS << "#endif // GET_SUBTARGETINFO_TARGET_DESC\n\n";
-
+void SubtargetEmitter::emitHeader(raw_ostream &OS) {
   // Create a TargetSubtargetInfo subclass to hide the MC layer initialization.
-  OS << "\n#ifdef GET_SUBTARGETINFO_HEADER\n";
-  OS << "#undef GET_SUBTARGETINFO_HEADER\n\n";
+  IfDefEmitter IfDef(OS, "GET_SUBTARGETINFO_HEADER");
+  NamespaceEmitter LLVMNS(OS, "llvm");
 
   std::string ClassName = Target + "GenSubtargetInfo";
-  OS << "namespace llvm {\n";
   OS << "class DFAPacketizer;\n";
-  OS << "namespace " << Target << "_MC {\n"
-     << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
-     << " const MCInst *MI, const MCInstrInfo *MCII, "
-     << "const MCSubtargetInfo &STI, unsigned CPUID);\n"
-     << "} // end namespace " << Target << "_MC\n\n";
+  {
+    NamespaceEmitter MCNS(OS, (Target + Twine("_MC")).str());
+    OS << "unsigned resolveVariantSchedClassImpl(unsigned SchedClass,"
+       << " const MCInst *MI, const MCInstrInfo *MCII, "
+       << "const MCSubtargetInfo &STI, unsigned CPUID);\n";
+  }
   OS << "struct " << ClassName << " : public TargetSubtargetInfo {\n"
      << "  explicit " << ClassName << "(const Triple &TT, StringRef CPU, "
      << "StringRef TuneCPU, StringRef FS);\n"
@@ -2140,17 +2130,15 @@ void SubtargetEmitter::run(raw_ostream &OS) {
   PE.setByRef(false);
   for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates())
     PE.expandSTIPredicate(OS, Fn);
+  OS << "};\n";
+}
 
-  OS << "};\n"
-     << "} // end namespace llvm\n\n";
-
-  OS << "#endif // GET_SUBTARGETINFO_HEADER\n\n";
-
-  OS << "\n#ifdef GET_SUBTARGETINFO_CTOR\n";
-  OS << "#undef GET_SUBTARGETINFO_CTOR\n\n";
-
+void SubtargetEmitter::emitCtor(raw_ostream &OS, unsigned NumNames,
+                                unsigned NumFeatures, unsigned NumProcs) {
+  IfDefEmitter IfDef(OS, "GET_SUBTARGETINFO_CTOR");
   OS << "#include \"llvm/CodeGen/TargetSchedule.h\"\n\n";
-  OS << "namespace llvm {\n";
+
+  NamespaceEmitter LLVMNS(OS, "llvm");
   OS << "extern const llvm::StringRef " << Target << "Names[];\n";
   OS << "extern const llvm::SubtargetFeatureKV " << Target << "FeatureKV[];\n";
   OS << "extern const llvm::SubtargetSubTypeKV " << Target << "SubTypeKV[];\n";
@@ -2167,6 +2155,7 @@ void SubtargetEmitter::run(raw_ostream &OS) {
     OS << "extern const unsigned " << Target << "ForwardingPaths[];\n";
   }
 
+  std::string ClassName = Target + "GenSubtargetInfo";
   OS << ClassName << "::" << ClassName << "(const Triple &TT, StringRef CPU, "
      << "StringRef TuneCPU, StringRef FS)\n";
 
@@ -2204,11 +2193,20 @@ void SubtargetEmitter::run(raw_ostream &OS) {
   emitSchedModelHelpers(ClassName, OS);
   emitHwModeCheck(ClassName, OS, /*IsMC=*/false);
   emitGetMacroFusions(ClassName, OS);
+}
 
-  OS << "} // end namespace llvm\n\n";
-
-  OS << "#endif // GET_SUBTARGETINFO_CTOR\n\n";
+//
+// SubtargetEmitter::run - Main subtarget enumeration emitter.
+//
+void SubtargetEmitter::run(raw_ostream &OS) {
+  emitSourceFileHeader("Subtarget Enumeration Source Fragment", OS);
 
+  auto FeatureMap = emitEnums(OS);
+  emitSubtargetInfoMacroCalls(OS);
+  auto [NumNames, NumFeatures, NumProcs] = emitMCDesc(OS, FeatureMap);
+  emitTargetDesc(OS);
+  emitHeader(OS);
+  emitCtor(OS, NumNames, NumFeatures, NumProcs);
   emitMcInstrAnalysisPredicateFunctions(OS);
 }
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/163820


More information about the llvm-commits mailing list