From ad206289f15b263b9942f60b2324de21b1b0273d Mon Sep 17 00:00:00 2001 From: Ivan Kosarev Date: Mon, 28 Jul 2025 16:42:03 +0100 Subject: [PATCH] [TableGen] Split *GenRegisterInfo.inc. Reduces memory usage compiling backend sources, most notably for AMDGPU by ~98 MB per source on average. AMDGPUGenRegisterInfo.inc is tens of megabytes in size now, and is even larger downstream. At the same time, it is included in nearly all backend sources, typically just for a small portion of its content, resulting in compilation being unnecessarily memory-hungry, which in turn stresses buildbots and wastes their resources. Splitting .inc files also helps avoiding extra ccache misses where changes in .td files don't cause changes in all parts of what previously was a single .inc file. It is thought that rather than building on top of the current single-output-file design of TableGen, e.g., using `split-file`, it would be more preferable to recognise the need for multi-file outputs and give it a proper first-class support directly in TableGen. --- llvm/docs/TableGen/index.rst | 5 ++ llvm/include/llvm/TableGen/Main.h | 17 +++- llvm/include/llvm/TableGen/TableGenBackend.h | 43 +++++++++- llvm/lib/TableGen/Main.cpp | 76 ++++++++++------ llvm/lib/TableGen/TableGenBackend.cpp | 19 ++-- llvm/lib/Target/AMDGPU/SIFoldOperands.cpp | 2 +- llvm/test/TableGen/ArtificialSubregs.td | 2 +- llvm/test/TableGen/ConcatenatedSubregs.td | 2 +- llvm/test/TableGen/HwModeBitSet.td | 2 +- llvm/test/TableGen/HwModeSubRegs.td | 2 +- llvm/test/TableGen/SubRegsAndAliases.td | 2 +- llvm/utils/TableGen/Basic/TableGen.cpp | 7 +- llvm/utils/TableGen/RegisterInfoEmitter.cpp | 86 ++++++++++++------- mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp | 9 +- 14 files changed, 201 insertions(+), 73 deletions(-) diff --git a/llvm/docs/TableGen/index.rst b/llvm/docs/TableGen/index.rst index e334b2e4b23ac..0f1190c54627a 100644 --- a/llvm/docs/TableGen/index.rst +++ b/llvm/docs/TableGen/index.rst @@ -55,6 +55,11 @@ TableGen runs just like any other LLVM tool. The first (optional) argument specifies the file to read. If a filename is not specified, ``llvm-tblgen`` reads from standard input. +The ``-o`` option specifies the output file or ``-`` to output to +stdout. Where TableGen produces multiple output files, the option +specifies the name of the main output file, which also works as the +name prefix for other output files. + To be useful, one of the `backends`_ must be used. These backends are selectable on the command line (type '``llvm-tblgen -help``' for a list). For example, to get a list of all of the definitions that subclass a particular type diff --git a/llvm/include/llvm/TableGen/Main.h b/llvm/include/llvm/TableGen/Main.h index 5f68be188de78..bafce3a463acc 100644 --- a/llvm/include/llvm/TableGen/Main.h +++ b/llvm/include/llvm/TableGen/Main.h @@ -15,19 +15,34 @@ #include "llvm/Support/CommandLine.h" #include +#include namespace llvm { class raw_ostream; class RecordKeeper; -/// Perform the action using Records, and write output to OS. +struct TableGenOutputFiles { + std::string MainFile; + + // Translates additional output file names to their contents. + std::map AdditionalFiles; +}; + /// Returns true on error, false otherwise. using TableGenMainFn = bool(raw_ostream &OS, const RecordKeeper &Records); +/// Perform the action using Records, and store output in OutFiles. +/// Returns true on error, false otherwise. +using MultiFileTableGenMainFn = bool(TableGenOutputFiles &OutFiles, + const RecordKeeper &Records); + int TableGenMain(const char *argv0, std::function MainFn = nullptr); +int TableGenMain(const char *argv0, + std::function MainFn = nullptr); + /// Controls emitting large character arrays as strings or character arrays. /// Typically set to false when building with MSVC. extern cl::opt EmitLongStrLiterals; diff --git a/llvm/include/llvm/TableGen/TableGenBackend.h b/llvm/include/llvm/TableGen/TableGenBackend.h index 7cb540f66ec70..8450a02eb19e7 100644 --- a/llvm/include/llvm/TableGen/TableGenBackend.h +++ b/llvm/include/llvm/TableGen/TableGenBackend.h @@ -15,6 +15,7 @@ #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/TableGen/Main.h" #include "llvm/TableGen/Record.h" namespace llvm { @@ -23,7 +24,27 @@ class RecordKeeper; class raw_ostream; namespace TableGen::Emitter { -using FnT = function_ref; + +/// Represents the emitting function. Can produce a single or multple output +/// files. +struct FnT { + using SingleFileGeneratorType = void(const RecordKeeper &Records, + raw_ostream &OS); + using MultiFileGeneratorType = TableGenOutputFiles( + StringRef FilenamePrefix, const RecordKeeper &Records); + + SingleFileGeneratorType *SingleFileGenerator = nullptr; + MultiFileGeneratorType *MultiFileGenerator = nullptr; + + FnT() = default; + FnT(SingleFileGeneratorType *Gen) : SingleFileGenerator(Gen) {} + FnT(MultiFileGeneratorType *Gen) : MultiFileGenerator(Gen) {} + + bool operator==(const FnT &Other) const { + return SingleFileGenerator == Other.SingleFileGenerator && + MultiFileGenerator == Other.MultiFileGenerator; + } +}; /// Creating an `Opt` object registers the command line option \p Name with /// TableGen backend and associates the callback \p CB with that option. If @@ -36,17 +57,33 @@ struct Opt { /// Convienence wrapper around `Opt` that registers `EmitterClass::run` as the /// callback. template class OptClass : Opt { - static void run(const RecordKeeper &RK, raw_ostream &OS) { + static TableGenOutputFiles run(StringRef /*FilenamePrefix*/, + const RecordKeeper &RK) { + std::string S; + raw_string_ostream OS(S); EmitterC(RK).run(OS); + return {S, {}}; } public: OptClass(StringRef Name, StringRef Desc) : Opt(Name, run, Desc) {} }; +/// A version of the wrapper for backends emitting multiple files. +template class MultiFileOptClass : Opt { + static TableGenOutputFiles run(StringRef FilenamePrefix, + const RecordKeeper &RK) { + return EmitterC(RK).run(FilenamePrefix); + } + +public: + MultiFileOptClass(StringRef Name, StringRef Desc) : Opt(Name, run, Desc) {} +}; + /// Apply callback for any command line option registered above. Returns false /// is no callback was applied. -bool ApplyCallback(const RecordKeeper &Records, raw_ostream &OS); +bool ApplyCallback(const RecordKeeper &Records, TableGenOutputFiles &OutFiles, + StringRef FilenamePrefix); } // namespace TableGen::Emitter diff --git a/llvm/lib/TableGen/Main.cpp b/llvm/lib/TableGen/Main.cpp index b1024a8d39e00..c3869c3fb9a5a 100644 --- a/llvm/lib/TableGen/Main.cpp +++ b/llvm/lib/TableGen/Main.cpp @@ -23,6 +23,7 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/SMLoc.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/ToolOutputFile.h" @@ -104,8 +105,30 @@ static int createDependencyFile(const TGParser &Parser, const char *argv0) { return 0; } +static int WriteOutput(const TGParser &Parser, const char *argv0, + StringRef Filename, StringRef Content) { + if (WriteIfChanged) { + // Only updates the real output file if there are any differences. + // This prevents recompilation of all the files depending on it if there + // aren't any. + if (auto ExistingOrErr = MemoryBuffer::getFile(Filename, /*IsText=*/true)) + if (std::move(ExistingOrErr.get())->getBuffer() == Content) + return 0; + } + std::error_code EC; + ToolOutputFile OutFile(Filename, EC, sys::fs::OF_Text); + if (EC) + return reportError(argv0, "error opening " + Filename + ": " + + EC.message() + "\n"); + OutFile.os() << Content; + if (ErrorsPrinted == 0) + OutFile.keep(); + + return 0; +} + int llvm::TableGenMain(const char *argv0, - std::function MainFn) { + std::function MainFn) { RecordKeeper Records; TGTimer &Timer = Records.getTimer(); @@ -144,13 +167,14 @@ int llvm::TableGenMain(const char *argv0, // Write output to memory. Timer.startBackendTimer("Backend overall"); - std::string OutString; - raw_string_ostream Out(OutString); + SmallString<128> FilenamePrefix(OutputFilename); + sys::path::replace_extension(FilenamePrefix, ""); + TableGenOutputFiles OutFiles; unsigned status = 0; // ApplyCallback will return true if it did not apply any callback. In that // case, attempt to apply the MainFn. - if (TableGen::Emitter::ApplyCallback(Records, Out)) - status = MainFn ? MainFn(Out, Records) : 1; + if (TableGen::Emitter::ApplyCallback(Records, OutFiles, FilenamePrefix)) + status = MainFn ? MainFn(OutFiles, Records) : 1; Timer.stopBackendTimer(); if (status) return 1; @@ -165,25 +189,17 @@ int llvm::TableGenMain(const char *argv0, } Timer.startTimer("Write output"); - bool WriteFile = true; - if (WriteIfChanged) { - // Only updates the real output file if there are any differences. - // This prevents recompilation of all the files depending on it if there - // aren't any. - if (auto ExistingOrErr = - MemoryBuffer::getFile(OutputFilename, /*IsText=*/true)) - if (std::move(ExistingOrErr.get())->getBuffer() == OutString) - WriteFile = false; - } - if (WriteFile) { - std::error_code EC; - ToolOutputFile OutFile(OutputFilename, EC, sys::fs::OF_Text); - if (EC) - return reportError(argv0, "error opening " + OutputFilename + ": " + - EC.message() + "\n"); - OutFile.os() << OutString; - if (ErrorsPrinted == 0) - OutFile.keep(); + if (int Ret = WriteOutput(Parser, argv0, OutputFilename, OutFiles.MainFile)) + return Ret; + for (auto [Suffix, Content] : OutFiles.AdditionalFiles) { + SmallString<128> Filename(OutputFilename); + // TODO: Format using the split-file convention when writing to stdout? + if (Filename != "-") { + Filename = FilenamePrefix; + Filename.append(Suffix); + } + if (int Ret = WriteOutput(Parser, argv0, Filename, Content)) + return Ret; } Timer.stopTimer(); @@ -193,3 +209,15 @@ int llvm::TableGenMain(const char *argv0, return reportError(argv0, Twine(ErrorsPrinted) + " errors.\n"); return 0; } + +int llvm::TableGenMain(const char *argv0, + std::function MainFn) { + return TableGenMain(argv0, [&MainFn](TableGenOutputFiles &OutFiles, + const RecordKeeper &Records) { + std::string S; + raw_string_ostream OS(S); + int Res = MainFn(OS, Records); + OutFiles = {S, {}}; + return Res; + }); +} diff --git a/llvm/lib/TableGen/TableGenBackend.cpp b/llvm/lib/TableGen/TableGenBackend.cpp index 153ca39cfba08..116c3fcca8bd8 100644 --- a/llvm/lib/TableGen/TableGenBackend.cpp +++ b/llvm/lib/TableGen/TableGenBackend.cpp @@ -61,12 +61,21 @@ Opt::Opt(StringRef Name, FnT CB, StringRef Desc, bool ByDefault) { /// Apply callback specified on the command line. Returns true if no callback /// was applied. bool llvm::TableGen::Emitter::ApplyCallback(const RecordKeeper &Records, - raw_ostream &OS) { + TableGenOutputFiles &OutFiles, + StringRef FilenamePrefix) { FnT Fn = CallbackFunction->getValue(); - if (!Fn) - return true; - Fn(Records, OS); - return false; + if (Fn.SingleFileGenerator) { + std::string S; + raw_string_ostream OS(S); + Fn.SingleFileGenerator(Records, OS); + OutFiles = {S, {}}; + return false; + } + if (Fn.MultiFileGenerator) { + OutFiles = Fn.MultiFileGenerator(FilenamePrefix, Records); + return false; + } + return true; } static void printLine(raw_ostream &OS, const Twine &Prefix, char Fill, diff --git a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp index 2c00e23d113cb..a4faf9ae7376e 100644 --- a/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp +++ b/llvm/lib/Target/AMDGPU/SIFoldOperands.cpp @@ -1358,7 +1358,7 @@ void SIFoldOperandsImpl::foldOperand( // Remove this if 16-bit SGPRs (i.e. SGPR_LO16) are added to the // VS_16RegClass // - // Excerpt from AMDGPUGenRegisterInfo.inc + // Excerpt from AMDGPUGenRegisterInfoEnums.inc // NoSubRegister, //0 // hi16, // 1 // lo16, // 2 diff --git a/llvm/test/TableGen/ArtificialSubregs.td b/llvm/test/TableGen/ArtificialSubregs.td index b8d5686dee51b..e1e83e504137e 100644 --- a/llvm/test/TableGen/ArtificialSubregs.td +++ b/llvm/test/TableGen/ArtificialSubregs.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s --check-prefix=CHECK include "llvm/Target/Target.td" // This file tests that when using `isArtificial` for subregisters in diff --git a/llvm/test/TableGen/ConcatenatedSubregs.td b/llvm/test/TableGen/ConcatenatedSubregs.td index ea4e7f01a2e2d..8b0bd2a691cc8 100644 --- a/llvm/test/TableGen/ConcatenatedSubregs.td +++ b/llvm/test/TableGen/ConcatenatedSubregs.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s +// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s // Checks that tablegen correctly and completely infers subregister relations. include "llvm/Target/Target.td" diff --git a/llvm/test/TableGen/HwModeBitSet.td b/llvm/test/TableGen/HwModeBitSet.td index 869b09b3c6316..70cf789e4a9c7 100644 --- a/llvm/test/TableGen/HwModeBitSet.td +++ b/llvm/test/TableGen/HwModeBitSet.td @@ -1,5 +1,5 @@ // This is to test the scenario where different HwMode attributes coexist. -// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s --check-prefix=CHECK-REG +// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s --check-prefix=CHECK-REG // RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SUBTARGET diff --git a/llvm/test/TableGen/HwModeSubRegs.td b/llvm/test/TableGen/HwModeSubRegs.td index 31a569fcdaad1..c71e963fca13b 100644 --- a/llvm/test/TableGen/HwModeSubRegs.td +++ b/llvm/test/TableGen/HwModeSubRegs.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s +// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s include "llvm/Target/Target.td" def HasFeat : Predicate<"Subtarget->hasFeat()">; diff --git a/llvm/test/TableGen/SubRegsAndAliases.td b/llvm/test/TableGen/SubRegsAndAliases.td index ec450f8945b49..bd062a7ab6f53 100644 --- a/llvm/test/TableGen/SubRegsAndAliases.td +++ b/llvm/test/TableGen/SubRegsAndAliases.td @@ -1,4 +1,4 @@ -// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o /dev/null 2>&1 | FileCheck %s +// RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s include "llvm/Target/Target.td" def TestTarget : Target; diff --git a/llvm/utils/TableGen/Basic/TableGen.cpp b/llvm/utils/TableGen/Basic/TableGen.cpp index edb7791500699..b79ae93dab4f7 100644 --- a/llvm/utils/TableGen/Basic/TableGen.cpp +++ b/llvm/utils/TableGen/Basic/TableGen.cpp @@ -60,7 +60,9 @@ static TableGen::Emitter::Opt X[] = { true}, {"print-detailed-records", EmitDetailedRecords, "Print full details of all records to stdout"}, - {"null-backend", [](const RecordKeeper &Records, raw_ostream &OS) {}, + {"null-backend", + TableGen::Emitter::FnT( + [](const RecordKeeper &Records, raw_ostream &OS) {}), "Do nothing after parsing (useful for timing)"}, {"dump-json", EmitJSON, "Dump all records as machine-readable JSON"}, {"print-enums", printEnums, "Print enum values for a class"}, @@ -71,7 +73,8 @@ int tblgen_main(int argc, char **argv) { InitLLVM X(argc, argv); cl::ParseCommandLineOptions(argc, argv); - return TableGenMain(argv[0]); + std::function MainFn = nullptr; + return TableGenMain(argv[0], MainFn); } #ifndef __has_feature diff --git a/llvm/utils/TableGen/RegisterInfoEmitter.cpp b/llvm/utils/TableGen/RegisterInfoEmitter.cpp index eac908d9bc2bd..ef7b13e8940f8 100644 --- a/llvm/utils/TableGen/RegisterInfoEmitter.cpp +++ b/llvm/utils/TableGen/RegisterInfoEmitter.cpp @@ -68,19 +68,22 @@ class RegisterInfoEmitter { } // runEnums - Print out enum values for all of the registers. - void runEnums(raw_ostream &OS); + void runEnums(raw_ostream &OS, raw_ostream &MainOS, StringRef FilenamePrefix); // runMCDesc - Print out MC register descriptions. - void runMCDesc(raw_ostream &OS); + void runMCDesc(raw_ostream &OS, raw_ostream &MainOS, + StringRef FilenamePrefix); // runTargetHeader - Emit a header fragment for the register info emitter. - void runTargetHeader(raw_ostream &OS); + void runTargetHeader(raw_ostream &OS, raw_ostream &MainOS, + StringRef FilenamePrefix); // runTargetDesc - Output the target register and register file descriptions. - void runTargetDesc(raw_ostream &OS); + void runTargetDesc(raw_ostream &OS, raw_ostream &MainOS, + StringRef FilenamePrefix); // run - Output the register file description. - void run(raw_ostream &OS); + TableGenOutputFiles run(StringRef FilenamePrefix); void debugDump(raw_ostream &OS); @@ -97,8 +100,19 @@ class RegisterInfoEmitter { } // end anonymous namespace +static void emitInclude(StringRef FilenamePrefix, StringRef IncludeFile, + StringRef GuardMacro, raw_ostream &OS) { + OS << "#ifdef " << GuardMacro << '\n'; + OS << "#undef " << GuardMacro << '\n'; + OS << "#include \"" << FilenamePrefix << IncludeFile << "\"\n"; + OS << "#endif\n\n"; +} + // runEnums - Print out enum values for all of the registers. -void RegisterInfoEmitter::runEnums(raw_ostream &OS) { +void RegisterInfoEmitter::runEnums(raw_ostream &OS, raw_ostream &MainOS, + StringRef FilenamePrefix) { + emitInclude(FilenamePrefix, "Enums.inc", "GET_REGINFO_ENUM", MainOS); + const auto &Registers = RegBank.getRegisters(); // Register enums are stored as uint16_t in the tables. Make sure we'll fit. @@ -108,9 +122,6 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS) { emitSourceFileHeader("Target Register Enum Values", OS); - OS << "\n#ifdef GET_REGINFO_ENUM\n"; - OS << "#undef GET_REGINFO_ENUM\n\n"; - OS << "namespace llvm {\n\n"; OS << "class MCRegisterClass;\n" @@ -194,7 +205,6 @@ void RegisterInfoEmitter::runEnums(raw_ostream &OS) { OS << '\n'; OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_ENUM\n\n"; } static void printInt(raw_ostream &OS, int Val) { OS << Val; } @@ -902,11 +912,11 @@ void RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, // // runMCDesc - Print out MC register descriptions. // -void RegisterInfoEmitter::runMCDesc(raw_ostream &OS) { - emitSourceFileHeader("MC Register Information", OS); +void RegisterInfoEmitter::runMCDesc(raw_ostream &OS, raw_ostream &MainOS, + StringRef FilenamePrefix) { + emitInclude(FilenamePrefix, "MCDesc.inc", "GET_REGINFO_MC_DESC", MainOS); - OS << "\n#ifdef GET_REGINFO_MC_DESC\n"; - OS << "#undef GET_REGINFO_MC_DESC\n\n"; + emitSourceFileHeader("MC Register Information", OS); const auto &Regs = RegBank.getRegisters(); @@ -1131,14 +1141,13 @@ void RegisterInfoEmitter::runMCDesc(raw_ostream &OS) { OS << "}\n\n"; OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_MC_DESC\n\n"; } -void RegisterInfoEmitter::runTargetHeader(raw_ostream &OS) { - emitSourceFileHeader("Register Information Header Fragment", OS); +void RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, raw_ostream &MainOS, + StringRef FilenamePrefix) { + emitInclude(FilenamePrefix, "Header.inc", "GET_REGINFO_HEADER", MainOS); - OS << "\n#ifdef GET_REGINFO_HEADER\n"; - OS << "#undef GET_REGINFO_HEADER\n\n"; + emitSourceFileHeader("Register Information Header Fragment", OS); const std::string &TargetName = Target.getName().str(); std::string ClassName = TargetName + "GenRegisterInfo"; @@ -1215,17 +1224,17 @@ void RegisterInfoEmitter::runTargetHeader(raw_ostream &OS) { OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n\n"; } OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_HEADER\n\n"; } // // runTargetDesc - Output the target register and register file descriptions. // -void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS) { - emitSourceFileHeader("Target Register and Register Classes Information", OS); +void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, raw_ostream &MainOS, + StringRef FilenamePrefix) { + emitInclude(FilenamePrefix, "TargetDesc.inc", "GET_REGINFO_TARGET_DESC", + MainOS); - OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n"; - OS << "#undef GET_REGINFO_TARGET_DESC\n\n"; + emitSourceFileHeader("Target Register and Register Classes Information", OS); OS << "namespace llvm {\n\n"; @@ -1840,25 +1849,40 @@ void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS) { << "}\n\n"; OS << "} // end namespace llvm\n\n"; - OS << "#endif // GET_REGINFO_TARGET_DESC\n\n"; } -void RegisterInfoEmitter::run(raw_ostream &OS) { +TableGenOutputFiles RegisterInfoEmitter::run(StringRef FilenamePrefix) { TGTimer &Timer = Records.getTimer(); Timer.startTimer("Print enums"); - runEnums(OS); + std::string Main; + raw_string_ostream MainOS(Main); + std::string Enums; + raw_string_ostream EnumsOS(Enums); + runEnums(EnumsOS, MainOS, FilenamePrefix); Timer.startTimer("Print MC registers"); - runMCDesc(OS); + std::string MCDesc; + raw_string_ostream MCDescOS(MCDesc); + runMCDesc(MCDescOS, MainOS, FilenamePrefix); Timer.startTimer("Print header fragment"); - runTargetHeader(OS); + std::string Header; + raw_string_ostream HeaderOS(Header); + runTargetHeader(HeaderOS, MainOS, FilenamePrefix); Timer.startTimer("Print target registers"); - runTargetDesc(OS); + std::string TargetDesc; + raw_string_ostream TargetDescOS(TargetDesc); + runTargetDesc(TargetDescOS, MainOS, FilenamePrefix); if (RegisterInfoDebug) debugDump(errs()); + + return {Main, + {{"Enums.inc", Enums}, + {"MCDesc.inc", MCDesc}, + {"Header.inc", Header}, + {"TargetDesc.inc", TargetDesc}}}; } void RegisterInfoEmitter::debugDump(raw_ostream &OS) { @@ -1935,5 +1959,5 @@ void RegisterInfoEmitter::debugDump(raw_ostream &OS) { } } -static TableGen::Emitter::OptClass +static TableGen::Emitter::MultiFileOptClass X("gen-register-info", "Generate registers and register classes info"); diff --git a/mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp b/mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp index 685e79484e175..64e86f2a62073 100644 --- a/mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp +++ b/mlir/lib/Tools/mlir-tblgen/MlirTblgenMain.cpp @@ -153,5 +153,12 @@ int mlir::MlirTblgenMain(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); - return TableGenMain(argv[0], &mlirTableGenMain); + return TableGenMain( + argv[0], [](TableGenOutputFiles &OutFiles, const RecordKeeper &RK) { + std::string S; + raw_string_ostream OS(S); + bool Res = mlirTableGenMain(OS, RK); + OutFiles = {S, {}}; + return Res; + }); }