Skip to content

Conversation

@jurahul
Copy link
Contributor

@jurahul jurahul commented Oct 16, 2025

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

@jurahul jurahul force-pushed the nfc_adropt_ifdef_ns_emitter_subtarget_emitter branch 2 times, most recently from 3d63762 to f6ae047 Compare October 16, 2025 18:12
@jurahul jurahul force-pushed the nfc_adropt_ifdef_ns_emitter_subtarget_emitter branch from b2d599b to 23fd850 Compare October 29, 2025 17:23
@jurahul jurahul marked this pull request as ready for review October 29, 2025 19:43
@llvmbot
Copy link
Member

llvmbot commented Oct 29, 2025

@llvm/pr-subscribers-tablegen

Author: Rahul Joshi (jurahul)

Changes
  • 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 --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);
 }
 

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.

3 participants