Skip to content

[CodeGen][NewPM] Port AsmPrinter to new pass manager #99320

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

paperchalice
Copy link
Contributor

@paperchalice paperchalice commented Jul 17, 2024

Just simply wrap it in a pass.

  • The legacy pass part is renamed to AsmPrinterLegacy
  • Unfortunately there is no doInitialization/doFinalization in new pass concept, it is divided into 3 parts in new pass manager version, but we can handle the order of GlobalMerge and AsmPrinter correctly.
  • Provide a way to create AsmPrinter implementation and legacy pass in target registry.
  • Modify CodeGenPassBuilder so it can create AsmPrinter.
  • It seems we can bypass some target registry function if we add some callbacks in PassBuilder without circular dependencies.
  • GC part is in another pull request. [GC] Support bidirectional iterator in GCStrategyMap #99316

@llvmbot
Copy link
Member

llvmbot commented Jul 18, 2024

@llvm/pr-subscribers-backend-powerpc
@llvm/pr-subscribers-backend-nvptx

@llvm/pr-subscribers-backend-x86

Author: None (paperchalice)

Changes

Just simply wrap it in a pass.

  • The legacy pass part is renamed to AsmPrinterLegacy
  • Unfortunately there is no doInitialization/doFinalization in new pass concept, it is divided into 3 parts in new pass manager version, but we can handle the order of GlobalMerge and AsmPrinter correctly.
  • Provide a way to create AsmPrinter implementation and legacy pass in target registry.
  • Modify CodeGenPassBuilder so it can create AsmPrinter.
  • It seems we can bypass some target registry function if we add some callbacks in PassBuilder without circular dependencies.
  • GC part is in another pull request. #99316

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

29 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/AsmPrinter.h (+96-8)
  • (modified) llvm/include/llvm/CodeGen/GCMetadata.h (+32-1)
  • (modified) llvm/include/llvm/CodeGen/GCMetadataPrinter.h (+5)
  • (modified) llvm/include/llvm/MC/TargetRegistry.h (+30-2)
  • (modified) llvm/include/llvm/Passes/CodeGenPassBuilder.h (+39-20)
  • (modified) llvm/include/llvm/Passes/PassBuilder.h (+15)
  • (modified) llvm/include/llvm/Target/TargetMachine.h (+2-2)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+139-43)
  • (modified) llvm/lib/CodeGen/GCMetadata.cpp (+15-7)
  • (modified) llvm/lib/CodeGen/LLVMTargetMachine.cpp (+3-3)
  • (modified) llvm/lib/CodeGen/ShadowStackGCLowering.cpp (+1-1)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+7)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp (+4-11)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCodeGenPassBuilder.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCodeGenPassBuilder.h (+1-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/R600CodeGenPassBuilder.cpp (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/R600CodeGenPassBuilder.h (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/R600TargetMachine.cpp (+8-6)
  • (modified) llvm/lib/Target/AMDGPU/R600TargetMachine.h (+2-2)
  • (modified) llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp (+6-1)
  • (modified) llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (+16)
  • (modified) llvm/lib/Target/X86/CMakeLists.txt (+1)
  • (modified) llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp (+17-8)
  • (modified) llvm/lib/Target/X86/X86MCInstLower.cpp (+6-2)
  • (modified) llvm/lib/Target/X86/X86TargetMachine.h (+2-2)
  • (modified) llvm/tools/llc/NewPMDriver.cpp (+3-2)
  • (modified) llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp (+4-2)
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index dc00bd57d655d..48f96ebff37cb 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -21,6 +21,7 @@
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/CodeGen/DwarfStringPoolEntry.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachinePassManager.h"
 #include "llvm/CodeGen/StackMaps.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/IR/InlineAsm.h"
@@ -83,7 +84,7 @@ class RemarkStreamer;
 }
 
 /// This class is intended to be used as a driving class for all asm writers.
-class AsmPrinter : public MachineFunctionPass {
+class AsmPrinter {
 public:
   /// Target machine description.
   TargetMachine &TM;
@@ -179,8 +180,6 @@ class AsmPrinter : public MachineFunctionPass {
   /// List of symbols to be inserted into PC sections.
   DenseMap<const MDNode *, SmallVector<const MCSymbol *>> PCSectionsSymbols;
 
-  static char ID;
-
 protected:
   MCSymbol *CurrentFnBegin = nullptr;
 
@@ -198,6 +197,10 @@ class AsmPrinter : public MachineFunctionPass {
 
   StackMaps SM;
 
+  MachineFunctionPass *P = nullptr;
+  ModuleAnalysisManager *MAM = nullptr;
+  MachineFunctionAnalysisManager *MFAM = nullptr;
+
 private:
   /// If generated on the fly this own the instance.
   std::unique_ptr<MachineDominatorTree> OwnedMDT;
@@ -229,7 +232,7 @@ class AsmPrinter : public MachineFunctionPass {
   explicit AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
 
 public:
-  ~AsmPrinter() override;
+  virtual ~AsmPrinter();
 
   DwarfDebug *getDwarfDebug() { return DD; }
   DwarfDebug *getDwarfDebug() const { return DD; }
@@ -369,24 +372,36 @@ class AsmPrinter : public MachineFunctionPass {
   // MachineFunctionPass Implementation.
   //===------------------------------------------------------------------===//
 
+  virtual StringRef getPassName() const;
+
   /// Record analysis usage.
-  void getAnalysisUsage(AnalysisUsage &AU) const override;
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
 
   /// Set up the AsmPrinter when we are working on a new module. If your pass
   /// overrides this, it must make sure to explicitly call this implementation.
-  bool doInitialization(Module &M) override;
+  virtual bool doInitialization(Module &M);
 
   /// Shut down the asmprinter. If you override this in your pass, you must make
   /// sure to call it explicitly.
-  bool doFinalization(Module &M) override;
+  virtual bool doFinalization(Module &M);
 
   /// Emit the specified function out to the OutStreamer.
-  bool runOnMachineFunction(MachineFunction &MF) override {
+  virtual bool runOnMachineFunction(MachineFunction &MF) {
     SetupMachineFunction(MF);
     emitFunctionBody();
     return false;
   }
 
+  void setPass(MachineFunctionPass *Pass) { P = Pass; }
+  void setMAM(ModuleAnalysisManager &AM) { MAM = &AM; }
+  void setMFAM(MachineFunctionAnalysisManager &AM) { MFAM = &AM; }
+
+  //===------------------------------------------------------------------===//
+  // New Pass Manager Implementation.
+  //===------------------------------------------------------------------===//
+
+  virtual void getPreservedAnalyses(PreservedAnalyses &PA) const {}
+
   //===------------------------------------------------------------------===//
   // Coarse grained IR lowering routines.
   //===------------------------------------------------------------------===//
@@ -514,6 +529,7 @@ class AsmPrinter : public MachineFunctionPass {
 
   /// Emit the stack maps.
   void emitStackMaps();
+  void emitStackMaps(Module &M); // For new pass manager version.
 
   //===------------------------------------------------------------------===//
   // Overridable Hooks
@@ -905,6 +921,78 @@ class AsmPrinter : public MachineFunctionPass {
   }
 };
 
+class AsmPrinterInitializePass
+    : public PassInfoMixin<AsmPrinterInitializePass> {
+  std::shared_ptr<AsmPrinter> Printer;
+
+public:
+  explicit AsmPrinterInitializePass(std::shared_ptr<AsmPrinter> AP)
+      : Printer(AP) {}
+
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+};
+
+class AsmPrinterPass : public PassInfoMixin<AsmPrinterPass> {
+  std::shared_ptr<AsmPrinter> Printer;
+
+public:
+  explicit AsmPrinterPass(std::shared_ptr<AsmPrinter> AP)
+      : Printer(std::move(AP)) {}
+
+  PreservedAnalyses run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM);
+};
+
+class AsmPrinterFinalizePass : public PassInfoMixin<AsmPrinterFinalizePass> {
+  std::shared_ptr<AsmPrinter> Printer;
+
+public:
+  explicit AsmPrinterFinalizePass(std::shared_ptr<AsmPrinter> AP)
+      : Printer(AP) {}
+
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
+};
+
+class AsmPrinterLegacy : public MachineFunctionPass {
+  std::unique_ptr<AsmPrinter> Printer;
+
+public:
+  static char ID;
+
+  explicit AsmPrinterLegacy(std::unique_ptr<AsmPrinter> AP);
+
+  AsmPrinter &getPrinter() { return *Printer; }
+
+  //===------------------------------------------------------------------===//
+  // MachineFunctionPass Implementation.
+  //===------------------------------------------------------------------===//
+
+  /// Record analysis usage.
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    MachineFunctionPass::getAnalysisUsage(AU);
+    Printer->getAnalysisUsage(AU);
+  }
+
+  /// Set up the AsmPrinter when we are working on a new module. If your pass
+  /// overrides this, it must make sure to explicitly call this implementation.
+  bool doInitialization(Module &M) override {
+    return Printer->doInitialization(M);
+  }
+
+  /// Shut down the asmprinter. If you override this in your pass, you must make
+  /// sure to call it explicitly.
+  bool doFinalization(Module &M) override { return Printer->doFinalization(M); }
+
+  /// Emit the specified function out to the OutStreamer.
+  bool runOnMachineFunction(MachineFunction &MF) override {
+    return Printer->runOnMachineFunction(MF);
+  }
+
+  StringRef getPassName() const override { return Printer->getPassName(); }
+};
+
+AsmPrinterLegacy *createAsmPrinterLegacy(std::unique_ptr<AsmPrinter> AP);
+
 } // end namespace llvm
 
 #endif // LLVM_CODEGEN_ASMPRINTER_H
diff --git a/llvm/include/llvm/CodeGen/GCMetadata.h b/llvm/include/llvm/CodeGen/GCMetadata.h
index ca6a511185c7c..f22aa2c54f401 100644
--- a/llvm/include/llvm/CodeGen/GCMetadata.h
+++ b/llvm/include/llvm/CodeGen/GCMetadata.h
@@ -151,15 +151,46 @@ class GCFunctionInfo {
   size_t live_size(const iterator &p) const { return roots_size(); }
 };
 
-struct GCStrategyMap {
+class GCStrategyMap {
   StringMap<std::unique_ptr<GCStrategy>> StrategyMap;
+  SmallVector<GCStrategy *, 1> StrategyList; // For bidirectional iterator.
+  using StrategyListT = SmallVector<GCStrategy *, 1>;
 
+  FunctionAnalysisManager *FAM = nullptr;
+
+public:
   GCStrategyMap() = default;
   GCStrategyMap(GCStrategyMap &&) = default;
+  GCStrategyMap(FunctionAnalysisManager &FAM) : FAM(&FAM) {}
 
   /// Handle invalidation explicitly.
   bool invalidate(Module &M, const PreservedAnalyses &PA,
                   ModuleAnalysisManager::Invalidator &Inv);
+
+  GCFunctionInfo &getFunctionInfo(Function &F);
+
+  bool empty() const { return StrategyMap.empty(); }
+
+  bool contains(StringRef Name) const { return StrategyMap.contains(Name); }
+
+  /// Insert a new strategy if it is not existed, otherwise do nothing.
+  void insert(StringRef Name, std::unique_ptr<GCStrategy> Strategy) {
+    auto &S = StrategyMap[Name];
+    if (!S) {
+      S = std::move(Strategy);
+      StrategyList.push_back(S.get());
+    }
+  }
+
+  GCStrategy &at(StringRef Name) { return *StrategyMap.at(Name); }
+
+  // This class must support bidirectional iterator which is used by AsmPrinter.
+  using iterator = StrategyListT::iterator;
+  iterator begin() { return StrategyList.begin(); }
+  iterator end() { return StrategyList.end(); }
+  using reverse_iterator = StrategyListT::reverse_iterator;
+  reverse_iterator rbegin() { return StrategyList.rbegin(); }
+  reverse_iterator rend() { return StrategyList.rend(); }
 };
 
 /// An analysis pass which caches information about the entire Module.
diff --git a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
index f9527c9f8752e..a7cf6ec914b9c 100644
--- a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
+++ b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
@@ -27,8 +27,11 @@ class AsmPrinter;
 class GCMetadataPrinter;
 class GCModuleInfo;
 class GCStrategy;
+class GCStrategyMap;
 class Module;
 class StackMaps;
+template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager;
+using ModuleAnalysisManager = AnalysisManager<Module>;
 
 /// GCMetadataPrinterRegistry - The GC assembly printer registry uses all the
 /// defaults from Registry.
@@ -56,10 +59,12 @@ class GCMetadataPrinter {
   /// Called before the assembly for the module is generated by
   /// the AsmPrinter (but after target specific hooks.)
   virtual void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) {}
+  virtual void beginAssembly(Module &M, GCStrategyMap &Map, AsmPrinter &AP) {}
 
   /// Called after the assembly for the module is generated by
   /// the AsmPrinter (but before target specific hooks)
   virtual void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) {}
+  virtual void finishAssembly(Module &M, GCStrategyMap &Map, AsmPrinter &AP) {}
 
   /// Called when the stack maps are generated. Return true if
   /// stack maps with a custom format are generated. Otherwise
diff --git a/llvm/include/llvm/MC/TargetRegistry.h b/llvm/include/llvm/MC/TargetRegistry.h
index 5038b87cd1dc9..1c48dfe2f3fa9 100644
--- a/llvm/include/llvm/MC/TargetRegistry.h
+++ b/llvm/include/llvm/MC/TargetRegistry.h
@@ -36,6 +36,7 @@
 namespace llvm {
 
 class AsmPrinter;
+class AsmPrinterLegacy;
 class MCAsmBackend;
 class MCAsmInfo;
 class MCAsmParser;
@@ -57,6 +58,8 @@ class MCTargetStreamer;
 class raw_ostream;
 class TargetMachine;
 class TargetOptions;
+
+AsmPrinterLegacy *createAsmPrinterLegacy(std::unique_ptr<AsmPrinter> AP);
 namespace mca {
 class CustomBehaviour;
 class InstrPostProcess;
@@ -170,8 +173,12 @@ class Target {
   // If it weren't for layering issues (this header is in llvm/Support, but
   // depends on MC?) this should take the Streamer by value rather than rvalue
   // reference.
-  using AsmPrinterCtorTy = AsmPrinter *(*)(
-      TargetMachine &TM, std::unique_ptr<MCStreamer> &&Streamer);
+  using AsmPrinterLegacyCtorTy =
+      AsmPrinterLegacy *(*)(TargetMachine &TM,
+                            std::unique_ptr<MCStreamer> &&Streamer);
+  using AsmPrinterCtorTy =
+      AsmPrinter *(*)(TargetMachine &TM,
+                      std::unique_ptr<MCStreamer> &&Streamer);
   using MCAsmBackendCtorTy = MCAsmBackend *(*)(const Target &T,
                                                const MCSubtargetInfo &STI,
                                                const MCRegisterInfo &MRI,
@@ -314,6 +321,7 @@ class Target {
 
   /// AsmPrinterCtorFn - Construction function for this target's AsmPrinter,
   /// if registered.
+  AsmPrinterLegacyCtorTy AsmPrinterLegacyCtorFn;
   AsmPrinterCtorTy AsmPrinterCtorFn;
 
   /// MCDisassemblerCtorFn - Construction function for this target's
@@ -517,6 +525,16 @@ class Target {
 
   /// createAsmPrinter - Create a target specific assembly printer pass.  This
   /// takes ownership of the MCStreamer object.
+  AsmPrinterLegacy *
+  createAsmPrinterLegacy(TargetMachine &TM,
+                         std::unique_ptr<MCStreamer> &&Streamer) const {
+    if (!AsmPrinterLegacyCtorFn)
+      return nullptr;
+    return AsmPrinterLegacyCtorFn(TM, std::move(Streamer));
+  }
+
+  /// Same as `createAsmPrinter`, but only create AsmPrinter, for new pass
+  /// manager.
   AsmPrinter *createAsmPrinter(TargetMachine &TM,
                                std::unique_ptr<MCStreamer> &&Streamer) const {
     if (!AsmPrinterCtorFn)
@@ -963,6 +981,9 @@ struct TargetRegistry {
   ///
   /// @param T - The target being registered.
   /// @param Fn - A function to construct an AsmPrinter for the target.
+  static void RegisterAsmPrinter(Target &T, Target::AsmPrinterLegacyCtorTy Fn) {
+    T.AsmPrinterLegacyCtorFn = Fn;
+  }
   static void RegisterAsmPrinter(Target &T, Target::AsmPrinterCtorTy Fn) {
     T.AsmPrinterCtorFn = Fn;
   }
@@ -1428,9 +1449,16 @@ template <class MCAsmParserImpl> struct RegisterMCAsmParser {
 template <class AsmPrinterImpl> struct RegisterAsmPrinter {
   RegisterAsmPrinter(Target &T) {
     TargetRegistry::RegisterAsmPrinter(T, &Allocator);
+    TargetRegistry::RegisterAsmPrinter(T, &AllocatorLegacy);
   }
 
 private:
+  static AsmPrinterLegacy *
+  AllocatorLegacy(TargetMachine &TM, std::unique_ptr<MCStreamer> &&Streamer) {
+    auto *P = new AsmPrinterImpl(TM, std::move(Streamer));
+    return createAsmPrinterLegacy(std::unique_ptr<AsmPrinter>(P));
+  }
+
   static AsmPrinter *Allocator(TargetMachine &TM,
                                std::unique_ptr<MCStreamer> &&Streamer) {
     return new AsmPrinterImpl(TM, std::move(Streamer));
diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index fb7a3c107d88a..f73e1a12e70ac 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -22,6 +22,7 @@
 #include "llvm/Analysis/ScopedNoAliasAA.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/TypeBasedAliasAnalysis.h"
+#include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/AssignmentTrackingAnalysis.h"
 #include "llvm/CodeGen/CallBrPrepare.h"
 #include "llvm/CodeGen/CodeGenPrepare.h"
@@ -62,6 +63,7 @@
 #include "llvm/IRPrinter/IRPrintingPasses.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Passes/PassBuilder.h"
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Error.h"
@@ -119,9 +121,8 @@ namespace llvm {
 template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
 public:
   explicit CodeGenPassBuilder(TargetMachineT &TM,
-                              const CGPassBuilderOption &Opts,
-                              PassInstrumentationCallbacks *PIC)
-      : TM(TM), Opt(Opts), PIC(PIC) {
+                              const CGPassBuilderOption &Opts, PassBuilder &PB)
+      : TM(TM), Opt(Opts), PB(PB), PIC(PB.getPassInstrumentationCallbacks()) {
     // Target could set CGPassBuilderOption::MISchedPostRA to true to achieve
     //     substitutePass(&PostRASchedulerID, &PostMachineSchedulerID)
 
@@ -138,8 +139,8 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
   }
 
   Error buildPipeline(ModulePassManager &MPM, raw_pwrite_stream &Out,
-                      raw_pwrite_stream *DwoOut,
-                      CodeGenFileType FileType) const;
+                      raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
+                      MCContext &Ctx) const;
 
   PassInstrumentationCallbacks *getPassInstrumentationCallbacks() const {
     return PIC;
@@ -256,7 +257,9 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
 
   TargetMachineT &TM;
   CGPassBuilderOption Opt;
+  PassBuilder &PB;
   PassInstrumentationCallbacks *PIC;
+  mutable std::shared_ptr<AsmPrinter> PrinterImpl;
 
   template <typename TMC> TMC &getTM() const { return static_cast<TMC &>(TM); }
   CodeGenOptLevel getOptLevel() const { return TM.getOptLevel(); }
@@ -518,7 +521,7 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
 template <typename Derived, typename TargetMachineT>
 Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
     ModulePassManager &MPM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType) const {
+    CodeGenFileType FileType, MCContext &Ctx) const {
   auto StartStopInfo = TargetPassConfig::getStartStopInfo(*PIC);
   if (!StartStopInfo)
     return StartStopInfo.takeError();
@@ -527,6 +530,14 @@ Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
   bool PrintAsm = TargetPassConfig::willCompleteCodeGenPipeline();
   bool PrintMIR = !PrintAsm && FileType != CodeGenFileType::Null;
 
+  if (PrintAsm) {
+    Expected<std::unique_ptr<MCStreamer>> MCStreamerOrErr =
+        TM.createMCStreamer(Out, DwoOut, FileType, Ctx);
+    if (auto Err = MCStreamerOrErr.takeError())
+      return Err;
+    PrinterImpl = PB.getAsmPrinter(std::move(*MCStreamerOrErr));
+  }
+
   {
     AddIRPass addIRPass(MPM, derived());
     addIRPass(RequireAnalysisPass<MachineModuleAnalysis, Module>());
@@ -535,26 +546,30 @@ Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
     addISelPasses(addIRPass);
   }
 
-  AddMachinePass addPass(MPM, derived());
+  // Ensure we destruct `addPass`.
+  {
+    AddMachinePass addPass(MPM, derived());
 
-  if (PrintMIR)
-    addPass(PrintMIRPreparePass(Out), /*Force=*/true);
+    if (PrintMIR)
+      addPass(PrintMIRPreparePass(Out), /*Force=*/true);
 
-  if (auto Err = addCoreISelPasses(addPass))
-    return std::move(Err);
+    if (auto Err = addCoreISelPasses(addPass))
+      return std::move(Err);
 
-  if (auto Err = derived().addMachinePasses(addPass))
-    return std::move(Err);
+    if (auto Err = derived().addMachinePasses(addPass))
+      return std::move(Err);
 
-  if (PrintAsm) {
-    derived().addAsmPrinter(
-        addPass, [this, &Out, DwoOut, FileType](MCContext &Ctx) {
-          return this->TM.createMCStreamer(Out, DwoOut, FileType, Ctx);
-        });
+    if (PrintAsm)
+      addPass(AsmPrinterPass(PrinterImpl));
+
+    if (PrintMIR)
+      addPass(PrintMIRPass(Out), /*Force=*/true);
   }
 
-  if (PrintMIR)
-    addPass(PrintMIRPass(Out), /*Force=*/true);
+  {
+    AddIRPass addIRPass(MPM, derived());
+    addIRPass(AsmPrinterFinalizePass(PrinterImpl));
+  }
 
   return verifyStartStop(*StartStopInfo);
 }
@@ -665,6 +680,10 @@ void CodeGenPassBuilder<Derived, TargetMachineT>::addIRPasses(
     addPass(ExpandMemCmpPass(&TM));
   }
 
+  // This should be the last IR module pass.
+  if (TargetPassConfig::willCompleteCodeGenPipeline())
+    addPass(AsmPrinterInitializePass(PrinterImpl));
+
   // Run GC lowering passes for builtin collectors
   // TODO: add a pass insertion point here
   addPass(GCLoweringPass());
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 551d297e0c089..46759eabd58af 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -32,6 +32,7 @@
 
 namespace llvm {
 class StringRef;
+class AsmPrinter;
 class AAManager;
 class TargetMachine;
 class ModuleSummaryIndex;
@@ -590,6 +591,12 @@ class PassBuilder {
     RegClassFilterParsingCallbacks.push_back(C);
   }
 
+  void registerAsmPrinterCreationCallback(
+      const std::function<
+          std::shared_ptr<AsmPrinter>(std::unique_ptr<MCStreamer>)> &C) {
+    AsmPrinterCreationCallback = C;
+  }
+
   /// Register a callback for a top-level pipeline entry.
   ///
   /// If the PassManager type is not given at the top level of the pipeline
@@ -693,6 +700,11 @@ class PassBuilder {
                                               StringRef OptionName,
                                               StringRef PassName);
 
+  // Create target asm printer directly, this can bypass
+  // LLVMInitializeXXXAsmPrinter.
+  std::shared_ptr<AsmPrinter>
+  getAsmPrinter(std::unique_ptr<MCStreamer> Streamer);
+
 private:
   // O1 pass pipeline
   FunctionPassManager
@@ -809,6 +821,9 @@ class PassBuilder {
   // Callbacks to parse `filter` parameter in register allocation passes
   SmallVector<std::function<RegClassFilterFunc(StringRef)>, 2>
       RegClassFilterParsingCallbacks;
+  // Callback to create `AsmPrinterPass`.
+  std::function<std::shared_ptr<AsmPrinter>(std::unique_ptr<MCStreamer>)>
+      AsmPrinterCreationCallback;
 };
 
 /// This utility template takes care of adding require<> and invalidate<>
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index b8e56c755fbda..043d88fa47acd 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -471,8 +471,8 @@ class LLVMTargetMachine : public TargetMachine {
 
   virtual Error b...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Jul 18, 2024

@llvm/pr-subscribers-backend-amdgpu

Author: None (paperchalice)

Changes

Just simply wrap it in a pass.

  • The legacy pass part is renamed to AsmPrinterLegacy
  • Unfortunately there is no doInitialization/doFinalization in new pass concept, it is divided into 3 parts in new pass manager version, but we can handle the order of GlobalMerge and AsmPrinter correctly.
  • Provide a way to create AsmPrinter implementation and legacy pass in target registry.
  • Modify CodeGenPassBuilder so it can create AsmPrinter.
  • It seems we can bypass some target registry function if we add some callbacks in PassBuilder without circular dependencies.
  • GC part is in another pull request. #99316

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

29 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/AsmPrinter.h (+96-8)
  • (modified) llvm/include/llvm/CodeGen/GCMetadata.h (+32-1)
  • (modified) llvm/include/llvm/CodeGen/GCMetadataPrinter.h (+5)
  • (modified) llvm/include/llvm/MC/TargetRegistry.h (+30-2)
  • (modified) llvm/include/llvm/Passes/CodeGenPassBuilder.h (+39-20)
  • (modified) llvm/include/llvm/Passes/PassBuilder.h (+15)
  • (modified) llvm/include/llvm/Target/TargetMachine.h (+2-2)
  • (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (+139-43)
  • (modified) llvm/lib/CodeGen/GCMetadata.cpp (+15-7)
  • (modified) llvm/lib/CodeGen/LLVMTargetMachine.cpp (+3-3)
  • (modified) llvm/lib/CodeGen/ShadowStackGCLowering.cpp (+1-1)
  • (modified) llvm/lib/Passes/PassBuilder.cpp (+7)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUAsmPrinter.cpp (+4-11)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCodeGenPassBuilder.cpp (+2-3)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUCodeGenPassBuilder.h (+1-2)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.h (+2-2)
  • (modified) llvm/lib/Target/AMDGPU/R600CodeGenPassBuilder.cpp (+4-4)
  • (modified) llvm/lib/Target/AMDGPU/R600CodeGenPassBuilder.h (+1-1)
  • (modified) llvm/lib/Target/AMDGPU/R600TargetMachine.cpp (+8-6)
  • (modified) llvm/lib/Target/AMDGPU/R600TargetMachine.h (+2-2)
  • (modified) llvm/lib/Target/NVPTX/NVPTXAsmPrinter.cpp (+6-1)
  • (modified) llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (+16)
  • (modified) llvm/lib/Target/X86/CMakeLists.txt (+1)
  • (modified) llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp (+17-8)
  • (modified) llvm/lib/Target/X86/X86MCInstLower.cpp (+6-2)
  • (modified) llvm/lib/Target/X86/X86TargetMachine.h (+2-2)
  • (modified) llvm/tools/llc/NewPMDriver.cpp (+3-2)
  • (modified) llvm/unittests/CodeGen/AsmPrinterDwarfTest.cpp (+4-2)
diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index dc00bd57d655d..48f96ebff37cb 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -21,6 +21,7 @@
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/CodeGen/DwarfStringPoolEntry.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachinePassManager.h"
 #include "llvm/CodeGen/StackMaps.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/IR/InlineAsm.h"
@@ -83,7 +84,7 @@ class RemarkStreamer;
 }
 
 /// This class is intended to be used as a driving class for all asm writers.
-class AsmPrinter : public MachineFunctionPass {
+class AsmPrinter {
 public:
   /// Target machine description.
   TargetMachine &TM;
@@ -179,8 +180,6 @@ class AsmPrinter : public MachineFunctionPass {
   /// List of symbols to be inserted into PC sections.
   DenseMap<const MDNode *, SmallVector<const MCSymbol *>> PCSectionsSymbols;
 
-  static char ID;
-
 protected:
   MCSymbol *CurrentFnBegin = nullptr;
 
@@ -198,6 +197,10 @@ class AsmPrinter : public MachineFunctionPass {
 
   StackMaps SM;
 
+  MachineFunctionPass *P = nullptr;
+  ModuleAnalysisManager *MAM = nullptr;
+  MachineFunctionAnalysisManager *MFAM = nullptr;
+
 private:
   /// If generated on the fly this own the instance.
   std::unique_ptr<MachineDominatorTree> OwnedMDT;
@@ -229,7 +232,7 @@ class AsmPrinter : public MachineFunctionPass {
   explicit AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
 
 public:
-  ~AsmPrinter() override;
+  virtual ~AsmPrinter();
 
   DwarfDebug *getDwarfDebug() { return DD; }
   DwarfDebug *getDwarfDebug() const { return DD; }
@@ -369,24 +372,36 @@ class AsmPrinter : public MachineFunctionPass {
   // MachineFunctionPass Implementation.
   //===------------------------------------------------------------------===//
 
+  virtual StringRef getPassName() const;
+
   /// Record analysis usage.
-  void getAnalysisUsage(AnalysisUsage &AU) const override;
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
 
   /// Set up the AsmPrinter when we are working on a new module. If your pass
   /// overrides this, it must make sure to explicitly call this implementation.
-  bool doInitialization(Module &M) override;
+  virtual bool doInitialization(Module &M);
 
   /// Shut down the asmprinter. If you override this in your pass, you must make
   /// sure to call it explicitly.
-  bool doFinalization(Module &M) override;
+  virtual bool doFinalization(Module &M);
 
   /// Emit the specified function out to the OutStreamer.
-  bool runOnMachineFunction(MachineFunction &MF) override {
+  virtual bool runOnMachineFunction(MachineFunction &MF) {
     SetupMachineFunction(MF);
     emitFunctionBody();
     return false;
   }
 
+  void setPass(MachineFunctionPass *Pass) { P = Pass; }
+  void setMAM(ModuleAnalysisManager &AM) { MAM = &AM; }
+  void setMFAM(MachineFunctionAnalysisManager &AM) { MFAM = &AM; }
+
+  //===------------------------------------------------------------------===//
+  // New Pass Manager Implementation.
+  //===------------------------------------------------------------------===//
+
+  virtual void getPreservedAnalyses(PreservedAnalyses &PA) const {}
+
   //===------------------------------------------------------------------===//
   // Coarse grained IR lowering routines.
   //===------------------------------------------------------------------===//
@@ -514,6 +529,7 @@ class AsmPrinter : public MachineFunctionPass {
 
   /// Emit the stack maps.
   void emitStackMaps();
+  void emitStackMaps(Module &M); // For new pass manager version.
 
   //===------------------------------------------------------------------===//
   // Overridable Hooks
@@ -905,6 +921,78 @@ class AsmPrinter : public MachineFunctionPass {
   }
 };
 
+class AsmPrinterInitializePass
+    : public PassInfoMixin<AsmPrinterInitializePass> {
+  std::shared_ptr<AsmPrinter> Printer;
+
+public:
+  explicit AsmPrinterInitializePass(std::shared_ptr<AsmPrinter> AP)
+      : Printer(AP) {}
+
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+};
+
+class AsmPrinterPass : public PassInfoMixin<AsmPrinterPass> {
+  std::shared_ptr<AsmPrinter> Printer;
+
+public:
+  explicit AsmPrinterPass(std::shared_ptr<AsmPrinter> AP)
+      : Printer(std::move(AP)) {}
+
+  PreservedAnalyses run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM);
+};
+
+class AsmPrinterFinalizePass : public PassInfoMixin<AsmPrinterFinalizePass> {
+  std::shared_ptr<AsmPrinter> Printer;
+
+public:
+  explicit AsmPrinterFinalizePass(std::shared_ptr<AsmPrinter> AP)
+      : Printer(AP) {}
+
+  PreservedAnalyses run(Module &M, ModuleAnalysisManager &);
+};
+
+class AsmPrinterLegacy : public MachineFunctionPass {
+  std::unique_ptr<AsmPrinter> Printer;
+
+public:
+  static char ID;
+
+  explicit AsmPrinterLegacy(std::unique_ptr<AsmPrinter> AP);
+
+  AsmPrinter &getPrinter() { return *Printer; }
+
+  //===------------------------------------------------------------------===//
+  // MachineFunctionPass Implementation.
+  //===------------------------------------------------------------------===//
+
+  /// Record analysis usage.
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    MachineFunctionPass::getAnalysisUsage(AU);
+    Printer->getAnalysisUsage(AU);
+  }
+
+  /// Set up the AsmPrinter when we are working on a new module. If your pass
+  /// overrides this, it must make sure to explicitly call this implementation.
+  bool doInitialization(Module &M) override {
+    return Printer->doInitialization(M);
+  }
+
+  /// Shut down the asmprinter. If you override this in your pass, you must make
+  /// sure to call it explicitly.
+  bool doFinalization(Module &M) override { return Printer->doFinalization(M); }
+
+  /// Emit the specified function out to the OutStreamer.
+  bool runOnMachineFunction(MachineFunction &MF) override {
+    return Printer->runOnMachineFunction(MF);
+  }
+
+  StringRef getPassName() const override { return Printer->getPassName(); }
+};
+
+AsmPrinterLegacy *createAsmPrinterLegacy(std::unique_ptr<AsmPrinter> AP);
+
 } // end namespace llvm
 
 #endif // LLVM_CODEGEN_ASMPRINTER_H
diff --git a/llvm/include/llvm/CodeGen/GCMetadata.h b/llvm/include/llvm/CodeGen/GCMetadata.h
index ca6a511185c7c..f22aa2c54f401 100644
--- a/llvm/include/llvm/CodeGen/GCMetadata.h
+++ b/llvm/include/llvm/CodeGen/GCMetadata.h
@@ -151,15 +151,46 @@ class GCFunctionInfo {
   size_t live_size(const iterator &p) const { return roots_size(); }
 };
 
-struct GCStrategyMap {
+class GCStrategyMap {
   StringMap<std::unique_ptr<GCStrategy>> StrategyMap;
+  SmallVector<GCStrategy *, 1> StrategyList; // For bidirectional iterator.
+  using StrategyListT = SmallVector<GCStrategy *, 1>;
 
+  FunctionAnalysisManager *FAM = nullptr;
+
+public:
   GCStrategyMap() = default;
   GCStrategyMap(GCStrategyMap &&) = default;
+  GCStrategyMap(FunctionAnalysisManager &FAM) : FAM(&FAM) {}
 
   /// Handle invalidation explicitly.
   bool invalidate(Module &M, const PreservedAnalyses &PA,
                   ModuleAnalysisManager::Invalidator &Inv);
+
+  GCFunctionInfo &getFunctionInfo(Function &F);
+
+  bool empty() const { return StrategyMap.empty(); }
+
+  bool contains(StringRef Name) const { return StrategyMap.contains(Name); }
+
+  /// Insert a new strategy if it is not existed, otherwise do nothing.
+  void insert(StringRef Name, std::unique_ptr<GCStrategy> Strategy) {
+    auto &S = StrategyMap[Name];
+    if (!S) {
+      S = std::move(Strategy);
+      StrategyList.push_back(S.get());
+    }
+  }
+
+  GCStrategy &at(StringRef Name) { return *StrategyMap.at(Name); }
+
+  // This class must support bidirectional iterator which is used by AsmPrinter.
+  using iterator = StrategyListT::iterator;
+  iterator begin() { return StrategyList.begin(); }
+  iterator end() { return StrategyList.end(); }
+  using reverse_iterator = StrategyListT::reverse_iterator;
+  reverse_iterator rbegin() { return StrategyList.rbegin(); }
+  reverse_iterator rend() { return StrategyList.rend(); }
 };
 
 /// An analysis pass which caches information about the entire Module.
diff --git a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
index f9527c9f8752e..a7cf6ec914b9c 100644
--- a/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
+++ b/llvm/include/llvm/CodeGen/GCMetadataPrinter.h
@@ -27,8 +27,11 @@ class AsmPrinter;
 class GCMetadataPrinter;
 class GCModuleInfo;
 class GCStrategy;
+class GCStrategyMap;
 class Module;
 class StackMaps;
+template <typename IRUnitT, typename... ExtraArgTs> class AnalysisManager;
+using ModuleAnalysisManager = AnalysisManager<Module>;
 
 /// GCMetadataPrinterRegistry - The GC assembly printer registry uses all the
 /// defaults from Registry.
@@ -56,10 +59,12 @@ class GCMetadataPrinter {
   /// Called before the assembly for the module is generated by
   /// the AsmPrinter (but after target specific hooks.)
   virtual void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) {}
+  virtual void beginAssembly(Module &M, GCStrategyMap &Map, AsmPrinter &AP) {}
 
   /// Called after the assembly for the module is generated by
   /// the AsmPrinter (but before target specific hooks)
   virtual void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) {}
+  virtual void finishAssembly(Module &M, GCStrategyMap &Map, AsmPrinter &AP) {}
 
   /// Called when the stack maps are generated. Return true if
   /// stack maps with a custom format are generated. Otherwise
diff --git a/llvm/include/llvm/MC/TargetRegistry.h b/llvm/include/llvm/MC/TargetRegistry.h
index 5038b87cd1dc9..1c48dfe2f3fa9 100644
--- a/llvm/include/llvm/MC/TargetRegistry.h
+++ b/llvm/include/llvm/MC/TargetRegistry.h
@@ -36,6 +36,7 @@
 namespace llvm {
 
 class AsmPrinter;
+class AsmPrinterLegacy;
 class MCAsmBackend;
 class MCAsmInfo;
 class MCAsmParser;
@@ -57,6 +58,8 @@ class MCTargetStreamer;
 class raw_ostream;
 class TargetMachine;
 class TargetOptions;
+
+AsmPrinterLegacy *createAsmPrinterLegacy(std::unique_ptr<AsmPrinter> AP);
 namespace mca {
 class CustomBehaviour;
 class InstrPostProcess;
@@ -170,8 +173,12 @@ class Target {
   // If it weren't for layering issues (this header is in llvm/Support, but
   // depends on MC?) this should take the Streamer by value rather than rvalue
   // reference.
-  using AsmPrinterCtorTy = AsmPrinter *(*)(
-      TargetMachine &TM, std::unique_ptr<MCStreamer> &&Streamer);
+  using AsmPrinterLegacyCtorTy =
+      AsmPrinterLegacy *(*)(TargetMachine &TM,
+                            std::unique_ptr<MCStreamer> &&Streamer);
+  using AsmPrinterCtorTy =
+      AsmPrinter *(*)(TargetMachine &TM,
+                      std::unique_ptr<MCStreamer> &&Streamer);
   using MCAsmBackendCtorTy = MCAsmBackend *(*)(const Target &T,
                                                const MCSubtargetInfo &STI,
                                                const MCRegisterInfo &MRI,
@@ -314,6 +321,7 @@ class Target {
 
   /// AsmPrinterCtorFn - Construction function for this target's AsmPrinter,
   /// if registered.
+  AsmPrinterLegacyCtorTy AsmPrinterLegacyCtorFn;
   AsmPrinterCtorTy AsmPrinterCtorFn;
 
   /// MCDisassemblerCtorFn - Construction function for this target's
@@ -517,6 +525,16 @@ class Target {
 
   /// createAsmPrinter - Create a target specific assembly printer pass.  This
   /// takes ownership of the MCStreamer object.
+  AsmPrinterLegacy *
+  createAsmPrinterLegacy(TargetMachine &TM,
+                         std::unique_ptr<MCStreamer> &&Streamer) const {
+    if (!AsmPrinterLegacyCtorFn)
+      return nullptr;
+    return AsmPrinterLegacyCtorFn(TM, std::move(Streamer));
+  }
+
+  /// Same as `createAsmPrinter`, but only create AsmPrinter, for new pass
+  /// manager.
   AsmPrinter *createAsmPrinter(TargetMachine &TM,
                                std::unique_ptr<MCStreamer> &&Streamer) const {
     if (!AsmPrinterCtorFn)
@@ -963,6 +981,9 @@ struct TargetRegistry {
   ///
   /// @param T - The target being registered.
   /// @param Fn - A function to construct an AsmPrinter for the target.
+  static void RegisterAsmPrinter(Target &T, Target::AsmPrinterLegacyCtorTy Fn) {
+    T.AsmPrinterLegacyCtorFn = Fn;
+  }
   static void RegisterAsmPrinter(Target &T, Target::AsmPrinterCtorTy Fn) {
     T.AsmPrinterCtorFn = Fn;
   }
@@ -1428,9 +1449,16 @@ template <class MCAsmParserImpl> struct RegisterMCAsmParser {
 template <class AsmPrinterImpl> struct RegisterAsmPrinter {
   RegisterAsmPrinter(Target &T) {
     TargetRegistry::RegisterAsmPrinter(T, &Allocator);
+    TargetRegistry::RegisterAsmPrinter(T, &AllocatorLegacy);
   }
 
 private:
+  static AsmPrinterLegacy *
+  AllocatorLegacy(TargetMachine &TM, std::unique_ptr<MCStreamer> &&Streamer) {
+    auto *P = new AsmPrinterImpl(TM, std::move(Streamer));
+    return createAsmPrinterLegacy(std::unique_ptr<AsmPrinter>(P));
+  }
+
   static AsmPrinter *Allocator(TargetMachine &TM,
                                std::unique_ptr<MCStreamer> &&Streamer) {
     return new AsmPrinterImpl(TM, std::move(Streamer));
diff --git a/llvm/include/llvm/Passes/CodeGenPassBuilder.h b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
index fb7a3c107d88a..f73e1a12e70ac 100644
--- a/llvm/include/llvm/Passes/CodeGenPassBuilder.h
+++ b/llvm/include/llvm/Passes/CodeGenPassBuilder.h
@@ -22,6 +22,7 @@
 #include "llvm/Analysis/ScopedNoAliasAA.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/TypeBasedAliasAnalysis.h"
+#include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/AssignmentTrackingAnalysis.h"
 #include "llvm/CodeGen/CallBrPrepare.h"
 #include "llvm/CodeGen/CodeGenPrepare.h"
@@ -62,6 +63,7 @@
 #include "llvm/IRPrinter/IRPrintingPasses.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Passes/PassBuilder.h"
 #include "llvm/Support/CodeGen.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/Error.h"
@@ -119,9 +121,8 @@ namespace llvm {
 template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
 public:
   explicit CodeGenPassBuilder(TargetMachineT &TM,
-                              const CGPassBuilderOption &Opts,
-                              PassInstrumentationCallbacks *PIC)
-      : TM(TM), Opt(Opts), PIC(PIC) {
+                              const CGPassBuilderOption &Opts, PassBuilder &PB)
+      : TM(TM), Opt(Opts), PB(PB), PIC(PB.getPassInstrumentationCallbacks()) {
     // Target could set CGPassBuilderOption::MISchedPostRA to true to achieve
     //     substitutePass(&PostRASchedulerID, &PostMachineSchedulerID)
 
@@ -138,8 +139,8 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
   }
 
   Error buildPipeline(ModulePassManager &MPM, raw_pwrite_stream &Out,
-                      raw_pwrite_stream *DwoOut,
-                      CodeGenFileType FileType) const;
+                      raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
+                      MCContext &Ctx) const;
 
   PassInstrumentationCallbacks *getPassInstrumentationCallbacks() const {
     return PIC;
@@ -256,7 +257,9 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
 
   TargetMachineT &TM;
   CGPassBuilderOption Opt;
+  PassBuilder &PB;
   PassInstrumentationCallbacks *PIC;
+  mutable std::shared_ptr<AsmPrinter> PrinterImpl;
 
   template <typename TMC> TMC &getTM() const { return static_cast<TMC &>(TM); }
   CodeGenOptLevel getOptLevel() const { return TM.getOptLevel(); }
@@ -518,7 +521,7 @@ template <typename DerivedT, typename TargetMachineT> class CodeGenPassBuilder {
 template <typename Derived, typename TargetMachineT>
 Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
     ModulePassManager &MPM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType) const {
+    CodeGenFileType FileType, MCContext &Ctx) const {
   auto StartStopInfo = TargetPassConfig::getStartStopInfo(*PIC);
   if (!StartStopInfo)
     return StartStopInfo.takeError();
@@ -527,6 +530,14 @@ Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
   bool PrintAsm = TargetPassConfig::willCompleteCodeGenPipeline();
   bool PrintMIR = !PrintAsm && FileType != CodeGenFileType::Null;
 
+  if (PrintAsm) {
+    Expected<std::unique_ptr<MCStreamer>> MCStreamerOrErr =
+        TM.createMCStreamer(Out, DwoOut, FileType, Ctx);
+    if (auto Err = MCStreamerOrErr.takeError())
+      return Err;
+    PrinterImpl = PB.getAsmPrinter(std::move(*MCStreamerOrErr));
+  }
+
   {
     AddIRPass addIRPass(MPM, derived());
     addIRPass(RequireAnalysisPass<MachineModuleAnalysis, Module>());
@@ -535,26 +546,30 @@ Error CodeGenPassBuilder<Derived, TargetMachineT>::buildPipeline(
     addISelPasses(addIRPass);
   }
 
-  AddMachinePass addPass(MPM, derived());
+  // Ensure we destruct `addPass`.
+  {
+    AddMachinePass addPass(MPM, derived());
 
-  if (PrintMIR)
-    addPass(PrintMIRPreparePass(Out), /*Force=*/true);
+    if (PrintMIR)
+      addPass(PrintMIRPreparePass(Out), /*Force=*/true);
 
-  if (auto Err = addCoreISelPasses(addPass))
-    return std::move(Err);
+    if (auto Err = addCoreISelPasses(addPass))
+      return std::move(Err);
 
-  if (auto Err = derived().addMachinePasses(addPass))
-    return std::move(Err);
+    if (auto Err = derived().addMachinePasses(addPass))
+      return std::move(Err);
 
-  if (PrintAsm) {
-    derived().addAsmPrinter(
-        addPass, [this, &Out, DwoOut, FileType](MCContext &Ctx) {
-          return this->TM.createMCStreamer(Out, DwoOut, FileType, Ctx);
-        });
+    if (PrintAsm)
+      addPass(AsmPrinterPass(PrinterImpl));
+
+    if (PrintMIR)
+      addPass(PrintMIRPass(Out), /*Force=*/true);
   }
 
-  if (PrintMIR)
-    addPass(PrintMIRPass(Out), /*Force=*/true);
+  {
+    AddIRPass addIRPass(MPM, derived());
+    addIRPass(AsmPrinterFinalizePass(PrinterImpl));
+  }
 
   return verifyStartStop(*StartStopInfo);
 }
@@ -665,6 +680,10 @@ void CodeGenPassBuilder<Derived, TargetMachineT>::addIRPasses(
     addPass(ExpandMemCmpPass(&TM));
   }
 
+  // This should be the last IR module pass.
+  if (TargetPassConfig::willCompleteCodeGenPipeline())
+    addPass(AsmPrinterInitializePass(PrinterImpl));
+
   // Run GC lowering passes for builtin collectors
   // TODO: add a pass insertion point here
   addPass(GCLoweringPass());
diff --git a/llvm/include/llvm/Passes/PassBuilder.h b/llvm/include/llvm/Passes/PassBuilder.h
index 551d297e0c089..46759eabd58af 100644
--- a/llvm/include/llvm/Passes/PassBuilder.h
+++ b/llvm/include/llvm/Passes/PassBuilder.h
@@ -32,6 +32,7 @@
 
 namespace llvm {
 class StringRef;
+class AsmPrinter;
 class AAManager;
 class TargetMachine;
 class ModuleSummaryIndex;
@@ -590,6 +591,12 @@ class PassBuilder {
     RegClassFilterParsingCallbacks.push_back(C);
   }
 
+  void registerAsmPrinterCreationCallback(
+      const std::function<
+          std::shared_ptr<AsmPrinter>(std::unique_ptr<MCStreamer>)> &C) {
+    AsmPrinterCreationCallback = C;
+  }
+
   /// Register a callback for a top-level pipeline entry.
   ///
   /// If the PassManager type is not given at the top level of the pipeline
@@ -693,6 +700,11 @@ class PassBuilder {
                                               StringRef OptionName,
                                               StringRef PassName);
 
+  // Create target asm printer directly, this can bypass
+  // LLVMInitializeXXXAsmPrinter.
+  std::shared_ptr<AsmPrinter>
+  getAsmPrinter(std::unique_ptr<MCStreamer> Streamer);
+
 private:
   // O1 pass pipeline
   FunctionPassManager
@@ -809,6 +821,9 @@ class PassBuilder {
   // Callbacks to parse `filter` parameter in register allocation passes
   SmallVector<std::function<RegClassFilterFunc(StringRef)>, 2>
       RegClassFilterParsingCallbacks;
+  // Callback to create `AsmPrinterPass`.
+  std::function<std::shared_ptr<AsmPrinter>(std::unique_ptr<MCStreamer>)>
+      AsmPrinterCreationCallback;
 };
 
 /// This utility template takes care of adding require<> and invalidate<>
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index b8e56c755fbda..043d88fa47acd 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -471,8 +471,8 @@ class LLVMTargetMachine : public TargetMachine {
 
   virtual Error b...
[truncated]

@paperchalice paperchalice requested review from arsenm and aeubanks July 18, 2024 09:08
@@ -905,6 +921,78 @@ class AsmPrinter : public MachineFunctionPass {
}
};

class AsmPrinterInitializePass
: public PassInfoMixin<AsmPrinterInitializePass> {
std::shared_ptr<AsmPrinter> Printer;
Copy link
Contributor

Choose a reason for hiding this comment

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

There should be no reason to use shared_ptr instead of unique_ptr

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently these three passes are tightly coupled, AsmPrinterInitializePass may modify some states in AsmPrinter. Also, they must share the same streamer, which is used by all three passes.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would expect the state to move from one pass to the next. It does not need atomic reference counting

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another problem is the ownership of std::unique_ptr<MCStreamer> OutStreamer;, it looks like they must share the same streamer.

Copy link
Contributor

Choose a reason for hiding this comment

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

What if the first pass owned the pointer, the next 2 depend on it, and the second 2 only use a non-smart reference?

};

class AsmPrinterPass : public PassInfoMixin<AsmPrinterPass> {
std::shared_ptr<AsmPrinter> Printer;
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto

@@ -693,6 +700,11 @@ class PassBuilder {
StringRef OptionName,
StringRef PassName);

// Create target asm printer directly, this can bypass
// LLVMInitializeXXXAsmPrinter.
std::shared_ptr<AsmPrinter>
Copy link
Contributor

Choose a reason for hiding this comment

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

No shared_ptrs

@@ -517,6 +525,16 @@ class Target {

/// createAsmPrinter - Create a target specific assembly printer pass. This
/// takes ownership of the MCStreamer object.
AsmPrinterLegacy *
createAsmPrinterLegacy(TargetMachine &TM,
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the point of having the legacy pass overridable by targets? This doesn't seem to be useful (or used), because the legacy pass just wraps the AsmPrinter, which provides virtual functions for everything.

Copy link
Contributor Author

@paperchalice paperchalice Jul 18, 2024

Choose a reason for hiding this comment

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

This is a compromise to ensure there is no circular dependency between CodeGen, MC, Target, etc...

Comment on lines 140 to 143
// Create the AsmPrinter, which takes ownership of AsmStreamer if successful.
FunctionPass *Printer =
getTarget().createAsmPrinter(*this, std::move(*MCStreamerOrErr));
AsmPrinterLegacy *Printer =
getTarget().createAsmPrinterLegacy(*this, std::move(*MCStreamerOrErr));
if (!Printer)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is createAsmPrinterLegacy(getTarget().createAsmPrinter(...)) possible here? (and then remove the AsmPrinterLegacyCtorFn)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some DWARF classes still use it, so it is possible when we can use callback style pass builder and decouple DWARF classes with AsmPrinter.

Comment on lines 167 to 198
PreservedAnalyses AsmPrinterPass::run(MachineFunction &MF,
MachineFunctionAnalysisManager &MFAM) {
auto PA = getMachineFunctionPassPreservedAnalyses();
PA.preserve<MachineOptimizationRemarkEmitterAnalysis>();
PA.preserve<CollectorMetadataAnalysis>();
PA.preserve<MachineBlockFrequencyAnalysis>();
PA.preserve<MachineBranchProbabilityAnalysis>();
Printer->getPreservedAnalyses(PA);
return PA;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This should have Printer->runOnMachineFunction(MF)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I missed it...

Comment on lines 534 to 585
Expected<std::unique_ptr<MCStreamer>> MCStreamerOrErr =
TM.createMCStreamer(Out, DwoOut, FileType, Ctx);
if (auto Err = MCStreamerOrErr.takeError())
return Err;
PrinterImpl = PB.getAsmPrinter(std::move(*MCStreamerOrErr));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

We construct MCStreamer directly from TM here; is there a reason why TM.createAsmPrinter() is not used directly as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently I plan to decoupling pipeline building from TargetMachine, let pass builder handles MCStreamer creation etc. So we can get rid of LLVMTargetMachine finally.

Copy link
Contributor

@optimisan optimisan Jan 29, 2025

Choose a reason for hiding this comment

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

Okay, so I gather that TM would only be used through PB.registerPassBuilderCallbacks().

@paperchalice
Copy link
Contributor Author

paperchalice commented Feb 8, 2025

Use thread unsafe version IntrusiveRefCntPtr in AsmPrinter, should be enough in this scenario. How to embed it into new pass pipeline is pending on high level design feedback.

@paperchalice paperchalice force-pushed the asm-printer branch 6 times, most recently from 9680421 to 64248f8 Compare February 15, 2025 12:22
Comment on lines 4536 to 4540
void AsmPrinter::emitStackMaps(Module &M) {
auto &Map = MAM->getResult<CollectorMetadataAnalysis>(M);
bool NeedsDefault = false;
if (Map.empty())
// No GC strategy, use the default format.
Copy link
Contributor

@optimisan optimisan Mar 24, 2025

Choose a reason for hiding this comment

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

Instead of duplicating multiple things can this class just take the analysis results directly (and not use pass managers)?

Copy link
Contributor Author

@paperchalice paperchalice Mar 24, 2025

Choose a reason for hiding this comment

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

This result is used in some gc lowering passes, and these passes will fill the analysis result.

@@ -151,15 +151,46 @@ class GCFunctionInfo {
size_t live_size(const iterator &p) const { return roots_size(); }
};

struct GCStrategyMap {
class GCStrategyMap {
Copy link
Contributor

Choose a reason for hiding this comment

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

spilled-over patch?

@optimisan
Copy link
Contributor

ping?
Also this is the only pass remaining to fully enable the npm path for AMDGPU

@paperchalice
Copy link
Contributor Author

ping? Also this is the only pass remaining to fully enable the npm path for AMDGPU

Personally I want to revisit it after #137290, because it can handle 3 asm printer passes better.

@paperchalice
Copy link
Contributor Author

Rebased. Convert to pimpl style implementation and currently AsmPrinter still inherit fromMachineFunctionPass.

"asm-printer-initialize");
PIC->addClassToPassName(AsmPrinterPass::name(), "asm-printer");
PIC->addClassToPassName(AsmPrinterFinalizePass::name(),
"asm-printer-finalize");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we provide a unified wrapper, then the name <target>-asm-printer is no longer available.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could let targets add their pass name in the PB callback also?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Found pass builder can construct pass name by getTargetTriple().getArchName()+"-asm-printer"

fix typo

Co-authored-by: Akshat Oke <Akshat.Oke@amd.com>
Copy link
Contributor

@optimisan optimisan left a comment

Choose a reason for hiding this comment

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

Seems good to me, I can get it working for AMDGPU.
Can wait if other people have anything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants