From b27943537460dabf0d2a9477c6e7f9d06b23e0f3 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Thu, 16 Oct 2025 09:32:04 -0700 Subject: [PATCH 1/4] [NFC][TableGen] Adopt CodeGenHelpers in SubtargetEmitter --- llvm/include/llvm/TableGen/CodeGenHelpers.h | 44 ++++++- llvm/utils/TableGen/SubtargetEmitter.cpp | 138 ++++++++++---------- 2 files changed, 105 insertions(+), 77 deletions(-) diff --git a/llvm/include/llvm/TableGen/CodeGenHelpers.h b/llvm/include/llvm/TableGen/CodeGenHelpers.h index 95866e306b5ff..e357b2670be15 100644 --- a/llvm/include/llvm/TableGen/CodeGenHelpers.h +++ b/llvm/include/llvm/TableGen/CodeGenHelpers.h @@ -21,18 +21,37 @@ 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). @@ -43,11 +62,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 @@ -65,7 +93,9 @@ class NamespaceEmitter { // Explicit function to close the namespace scopes. void close() { - if (!Closed && !Name.empty()) + if (Closed) + return; + if (!Name.empty()) OS << "\n} // namespace " << Name << "\n"; Closed = true; } diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 2f15cc8c76548..99fee03d36da9 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 + 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 and the end of the scope since its + // used within the scope. + IfDefEmitter IfDefMacro(OS, "GET_SUBTARGETINFO_MACRO", /*LateUndef=*/true); std::vector 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 +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); } From 6f29332e90a465dd848e64537d374c5ba9d121f0 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Thu, 23 Oct 2025 15:10:44 -0700 Subject: [PATCH 2/4] Fix typo in comment --- llvm/utils/TableGen/SubtargetEmitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 99fee03d36da9..c3fb089d3f608 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -150,7 +150,7 @@ 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) { - // Undef the GET_SUBTARGETINFO_MACRO macro and the end of the scope since its + // 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); From c36d6831575c0b34e0eb4e5d6ce00a217fc3ab24 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Tue, 4 Nov 2025 16:38:31 -0800 Subject: [PATCH 3/4] Review feedback --- llvm/utils/TableGen/SubtargetEmitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index c3fb089d3f608..1274589755ba6 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -150,7 +150,7 @@ 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) { - // Undef the GET_SUBTARGETINFO_MACRO macro at the end of the scope since its + // Undef the GET_SUBTARGETINFO_MACRO macro at the end of the scope since it's // used within the scope. IfDefEmitter IfDefMacro(OS, "GET_SUBTARGETINFO_MACRO", /*LateUndef=*/true); From 344ed20670aa7f9f73eb1f9b747e150786a8a7d6 Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Wed, 5 Nov 2025 07:53:51 -0800 Subject: [PATCH 4/4] Review feedback: use scopes instead of close --- llvm/utils/TableGen/SubtargetEmitter.cpp | 43 ++++++++++++------------ 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index 1274589755ba6..ae0431e79e1bc 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -443,14 +443,14 @@ void SubtargetEmitter::emitStageAndOperandCycleData( continue; StringRef Name = ProcModel.ItinsDef->getName(); - OS << "\n// Functional units for \"" << Name << "\"\n"; - NamespaceEmitter FUNamespace(OS, (Name + Twine("FU")).str()); + { + 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"; - - FUNamespace.close(); + for (const auto &[Idx, FU] : enumerate(FUs)) + OS << " const InstrStage::FuncUnits " << FU->getName() << " = 1ULL << " + << Idx << ";\n"; + } ConstRecVec BPs = ProcModel.ItinsDef->getValueAsListOfDefs("BP"); if (BPs.empty()) @@ -1941,13 +1941,14 @@ void SubtargetEmitter::parseFeaturesFunction(raw_ostream &OS) { } void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) { - 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"; - NS.close(); + { + 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 << "struct " << Target << "GenMCSubtargetInfo : public MCSubtargetInfo {\n"; @@ -1983,15 +1984,15 @@ void SubtargetEmitter::emitGenMCSubtargetInfo(raw_ostream &OS) { } void SubtargetEmitter::emitMcInstrAnalysisPredicateFunctions(raw_ostream &OS) { - IfDefEmitter IfDefDecls(OS, "GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS"); - STIPredicateExpander PE(Target, /*Indent=*/0); - PE.setExpandForMC(true); - PE.setByRef(true); - for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) - PE.expandSTIPredicate(OS, Fn); - IfDefDecls.close(); + { + IfDefEmitter IfDefDecls(OS, "GET_STIPREDICATE_DECLS_FOR_MC_ANALYSIS"); + PE.setExpandForMC(true); + PE.setByRef(true); + for (const STIPredicateFunction &Fn : SchedModels.getSTIPredicates()) + PE.expandSTIPredicate(OS, Fn); + } IfDefEmitter IfDefDefs(OS, "GET_STIPREDICATE_DEFS_FOR_MC_ANALYSIS"); std::string ClassPrefix = Target + "MCInstrAnalysis";