Skip to content

Add A Version Of MachineModuleInfoWrapperPass That Does Not Own Its Underlying MachineModuleInfo #134554

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 8 commits into
base: main
Choose a base branch
from

Conversation

matinraayai
Copy link
Contributor

This PR makes the following changes to the MachineModuleInfoWrapperPass:

  1. MachineModuleInfoWrapperPass is now an interface pass with its own typeid.
  2. Two kinds of MachineModuleInfoWrapperPass are introduced, one is OwningMachineModuleInfoWrapperPass, which behaves the same way as the original MachineModuleInfoWrapperPass, and one is NonOwningMachineModuleInfoWrapperPass, which instead takes a reference to an already created MachineModuleInfo.
    Also, this PR removes the move constructor for MachineModuleInfo since it was not correct to begin with.

Originally, I planned on only having the non-owning version available, but then I realized that many users of TargetMachine::addPassesToEmitFile don't link against CodeGen, which means they cannot create a MachineModuleInfo and manage its lifetime. I also think its not ideal to explicitly link against CodeGen.

Feedback is greatly appreciated.
cc: @aeubanks @arsenm

@llvmbot
Copy link
Member

llvmbot commented Apr 6, 2025

@llvm/pr-subscribers-backend-spir-v
@llvm/pr-subscribers-backend-nvptx

@llvm/pr-subscribers-tools-llvm-exegesis

Author: Matin Raayai (matinraayai)

Changes

This PR makes the following changes to the MachineModuleInfoWrapperPass:

  1. MachineModuleInfoWrapperPass is now an interface pass with its own typeid.
  2. Two kinds of MachineModuleInfoWrapperPass are introduced, one is OwningMachineModuleInfoWrapperPass, which behaves the same way as the original MachineModuleInfoWrapperPass, and one is NonOwningMachineModuleInfoWrapperPass, which instead takes a reference to an already created MachineModuleInfo.
    Also, this PR removes the move constructor for MachineModuleInfo since it was not correct to begin with.

Originally, I planned on only having the non-owning version available, but then I realized that many users of TargetMachine::addPassesToEmitFile don't link against CodeGen, which means they cannot create a MachineModuleInfo and manage its lifetime. I also think its not ideal to explicitly link against CodeGen.

Feedback is greatly appreciated.
cc: @aeubanks @arsenm


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

15 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h (+15-14)
  • (modified) llvm/include/llvm/CodeGen/MachineModuleInfo.h (+36-11)
  • (modified) llvm/include/llvm/Target/TargetMachine.h (+18-16)
  • (modified) llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp (+32-18)
  • (modified) llvm/lib/CodeGen/MachineModuleInfo.cpp (+4-21)
  • (modified) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp (+3-4)
  • (modified) llvm/lib/ExecutionEngine/MCJIT/MCJIT.h (-1)
  • (modified) llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp (+1-2)
  • (modified) llvm/lib/Target/DirectX/DirectXTargetMachine.cpp (+14-6)
  • (modified) llvm/lib/Target/DirectX/DirectXTargetMachine.h (+3-3)
  • (modified) llvm/lib/Target/NVPTX/NVPTXTargetMachine.h (+2-2)
  • (modified) llvm/lib/Target/SPIRV/SPIRVAPI.cpp (+4-5)
  • (modified) llvm/tools/llc/llc.cpp (+5-9)
  • (modified) llvm/tools/llvm-exegesis/lib/Assembler.cpp (+4-4)
  • (modified) offload/plugins-nextgen/common/src/JIT.cpp (+3-2)
diff --git a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
index 7bb4420e555fb..1491eb3d42964 100644
--- a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
+++ b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
@@ -44,22 +44,23 @@ class CodeGenTargetMachineImpl : public TargetMachine {
   virtual TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
 
   /// Add passes to the specified pass manager to get the specified file
-  /// emitted.  Typically this will involve several steps of code generation.
-  /// \p MMIWP is an optional parameter that, if set to non-nullptr,
-  /// will be used to set the MachineModuloInfo for this PM.
-  bool
-  addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out,
-                      raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
-                      bool DisableVerify = true,
-                      MachineModuleInfoWrapperPass *MMIWP = nullptr) override;
+  /// emitted. Typically, this will involve several steps of code generation.
+  /// This method should return true if emission of this file type is not
+  /// supported, or false on success.
+  /// \p MMI an optional, externally-managed \c MachineModuleInfo to
+  /// hold the generated machine code even after the \p PM is destroyed
+  bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out,
+                           raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
+                           bool DisableVerify = true,
+                           MachineModuleInfo *MMI = nullptr) override;
 
   /// Add passes to the specified pass manager to get machine code emitted with
-  /// the MCJIT. This method returns true if machine code is not supported. It
-  /// fills the MCContext Ctx pointer which can be used to build custom
-  /// MCStreamer.
-  bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
-                         raw_pwrite_stream &Out,
-                         bool DisableVerify = true) override;
+  /// the MCJIT. This method returns true if machine code is not supported.
+  /// \p MMI an optional, externally-managed \c MachineModuleInfo to
+  /// hold the generated machine code even after the \p PM is destroyed
+  bool addPassesToEmitMC(PassManagerBase &PM, raw_pwrite_stream &Out,
+                         bool DisableVerify = true,
+                         MachineModuleInfo *MMI = nullptr) override;
 
   /// Adds an AsmPrinter pass to the pipeline that prints assembly or
   /// machine code from the MI representation.
diff --git a/llvm/include/llvm/CodeGen/MachineModuleInfo.h b/llvm/include/llvm/CodeGen/MachineModuleInfo.h
index bec500dc609f3..4e4582fa0021a 100644
--- a/llvm/include/llvm/CodeGen/MachineModuleInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineModuleInfo.h
@@ -106,15 +106,11 @@ class MachineModuleInfo {
   const Function *LastRequest = nullptr; ///< Used for shortcut/cache.
   MachineFunction *LastResult = nullptr; ///< Used for shortcut/cache.
 
-  MachineModuleInfo &operator=(MachineModuleInfo &&MMII) = delete;
-
 public:
   explicit MachineModuleInfo(const TargetMachine *TM = nullptr);
 
   explicit MachineModuleInfo(const TargetMachine *TM, MCContext *ExtContext);
 
-  MachineModuleInfo(MachineModuleInfo &&MMII);
-
   ~MachineModuleInfo();
 
   void initialize();
@@ -167,22 +163,51 @@ class MachineModuleInfo {
   /// \}
 }; // End class MachineModuleInfo
 
+/// \brief Interface for pass that provide access to \c MachineModuleInfo
+/// being worked on
 class MachineModuleInfoWrapperPass : public ImmutablePass {
-  MachineModuleInfo MMI;
 
 public:
   static char ID; // Pass identification, replacement for typeid
-  explicit MachineModuleInfoWrapperPass(const TargetMachine *TM = nullptr);
-
-  explicit MachineModuleInfoWrapperPass(const TargetMachine *TM,
-                                        MCContext *ExtContext);
+  MachineModuleInfoWrapperPass();
 
   // Initialization and Finalization
   bool doInitialization(Module &) override;
   bool doFinalization(Module &) override;
 
-  MachineModuleInfo &getMMI() { return MMI; }
-  const MachineModuleInfo &getMMI() const { return MMI; }
+  virtual MachineModuleInfo &getMMI() = 0;
+  virtual const MachineModuleInfo &getMMI() const = 0;
+};
+
+/// \brief a version of \c MachineModuleInfoWrapperPass that manages the
+/// lifetime of its \c MachineModuleInfo
+class OwningMachineModuleInfoWrapperPass : public MachineModuleInfoWrapperPass {
+  MachineModuleInfo MMI;
+
+public:
+  explicit OwningMachineModuleInfoWrapperPass(const TargetMachine &TM)
+      : MMI(&TM) {};
+
+  OwningMachineModuleInfoWrapperPass(const TargetMachine &TM,
+                                     MCContext &ExtContext)
+      : MMI(&TM, &ExtContext) {};
+
+  MachineModuleInfo &getMMI() override { return MMI; }
+  const MachineModuleInfo &getMMI() const override { return MMI; }
+};
+
+/// \brief a version of \c MachineModuleInfoWrapperPass that does not manage the
+/// lifetime of its \c MachineModuleInfo
+class NonOwningMachineModuleInfoWrapperPass
+    : public MachineModuleInfoWrapperPass {
+  MachineModuleInfo &MMI;
+
+public:
+  explicit NonOwningMachineModuleInfoWrapperPass(MachineModuleInfo &MMI)
+      : MMI(MMI) {};
+
+  MachineModuleInfo &getMMI() override { return MMI; }
+  const MachineModuleInfo &getMMI() const override { return MMI; }
 };
 
 /// An analysis that produces \c MachineModuleInfo for a module.
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index 27eeb415ed644..3d8c6694297c9 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -38,7 +38,7 @@ using ModulePassManager = PassManager<Module>;
 
 class Function;
 class GlobalValue;
-class MachineModuleInfoWrapperPass;
+class MachineModuleInfo;
 struct MachineSchedContext;
 class Mangler;
 class MCAsmInfo;
@@ -401,27 +401,29 @@ class TargetMachine {
   virtual void registerDefaultAliasAnalyses(AAManager &) {}
 
   /// Add passes to the specified pass manager to get the specified file
-  /// emitted.  Typically this will involve several steps of code generation.
+  /// emitted. Typically, this will involve several steps of code generation.
   /// This method should return true if emission of this file type is not
   /// supported, or false on success.
-  /// \p MMIWP is an optional parameter that, if set to non-nullptr,
-  /// will be used to set the MachineModuloInfo for this PM.
-  virtual bool
-  addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &,
-                      raw_pwrite_stream *, CodeGenFileType,
-                      bool /*DisableVerify*/ = true,
-                      MachineModuleInfoWrapperPass *MMIWP = nullptr) {
+  /// For targets that utilize the target-independent code generator
+  /// (CodeGen), an externally-managed \c MachineModuleInfo can be provided
+  /// to ensure persistence of the generated machine code even after the pass
+  /// manager is destroyed
+  virtual bool addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &,
+                                   raw_pwrite_stream *, CodeGenFileType,
+                                   bool /*DisableVerify*/ = true,
+                                   MachineModuleInfo * = nullptr) {
     return true;
   }
 
   /// Add passes to the specified pass manager to get machine code emitted with
-  /// the MCJIT. This method returns true if machine code is not supported. It
-  /// fills the MCContext Ctx pointer which can be used to build custom
-  /// MCStreamer.
-  ///
-  virtual bool addPassesToEmitMC(PassManagerBase &, MCContext *&,
-                                 raw_pwrite_stream &,
-                                 bool /*DisableVerify*/ = true) {
+  /// the MCJIT. This method returns true if machine code is not supported.
+  /// For targets that utilize the target-independent code generator
+  /// (CodeGen), an externally-managed \c MachineModuleInfo can be provided
+  /// to ensure persistence of the generated machine code even after the pass
+  /// manager is destroyed
+  virtual bool addPassesToEmitMC(PassManagerBase &, raw_pwrite_stream &,
+                                 bool /*DisableVerify*/ = true,
+                                 MachineModuleInfo * = nullptr) {
     return true;
   }
 
diff --git a/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp b/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp
index 5757ca1b3adf8..3495a45859054 100644
--- a/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp
+++ b/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp
@@ -210,18 +210,27 @@ CodeGenTargetMachineImpl::createMCStreamer(raw_pwrite_stream &Out,
 
 bool CodeGenTargetMachineImpl::addPassesToEmitFile(
     PassManagerBase &PM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType, bool DisableVerify,
-    MachineModuleInfoWrapperPass *MMIWP) {
-  // Add common CodeGen passes.
-  if (!MMIWP)
-    MMIWP = new MachineModuleInfoWrapperPass(this);
+    CodeGenFileType FileType, bool DisableVerify, MachineModuleInfo *MMI) {
+  // Add the wrapper pass for MMI
+  MachineModuleInfoWrapperPass *MMIWP;
+  if (MMI) {
+    MMIWP = new NonOwningMachineModuleInfoWrapperPass(*MMI);
+  } else {
+    MMIWP = new OwningMachineModuleInfoWrapperPass(*this);
+    MMI = &MMIWP->getMMI();
+  }
+  // Check (for the case of externally-managed MMI) if the TM of MMI is
+  // the same as this target machine
+  if (&MMI->getTarget() != this)
+    return true;
+
   TargetPassConfig *PassConfig =
       addPassesToGenerateCode(*this, PM, DisableVerify, *MMIWP);
   if (!PassConfig)
     return true;
 
   if (TargetPassConfig::willCompleteCodeGenPipeline()) {
-    if (addAsmPrinter(PM, Out, DwoOut, FileType, MMIWP->getMMI().getContext()))
+    if (addAsmPrinter(PM, Out, DwoOut, FileType, MMI->getContext()))
       return true;
   } else {
     // MIR printing is redundant with -filetype=null.
@@ -233,17 +242,22 @@ bool CodeGenTargetMachineImpl::addPassesToEmitFile(
   return false;
 }
 
-/// addPassesToEmitMC - Add passes to the specified pass manager to get
-/// machine code emitted with the MCJIT. This method returns true if machine
-/// code is not supported. It fills the MCContext Ctx pointer which can be
-/// used to build custom MCStreamer.
-///
 bool CodeGenTargetMachineImpl::addPassesToEmitMC(PassManagerBase &PM,
-                                                 MCContext *&Ctx,
                                                  raw_pwrite_stream &Out,
-                                                 bool DisableVerify) {
-  // Add common CodeGen passes.
-  MachineModuleInfoWrapperPass *MMIWP = new MachineModuleInfoWrapperPass(this);
+                                                 bool DisableVerify,
+                                                 MachineModuleInfo *MMI) {
+  // Add the wrapper pass for MMI
+  MachineModuleInfoWrapperPass *MMIWP;
+  if (MMI) {
+    MMIWP = new NonOwningMachineModuleInfoWrapperPass(*MMI);
+  } else {
+    MMIWP = new OwningMachineModuleInfoWrapperPass(*this);
+    MMI = &MMIWP->getMMI();
+  }
+  // Check (for the case of externally-managed MMI) if the TM of MMI is
+  // the same as this target machine
+  if (&MMI->getTarget() != this)
+    return true;
   TargetPassConfig *PassConfig =
       addPassesToGenerateCode(*this, PM, DisableVerify, *MMIWP);
   if (!PassConfig)
@@ -251,7 +265,7 @@ bool CodeGenTargetMachineImpl::addPassesToEmitMC(PassManagerBase &PM,
   assert(TargetPassConfig::willCompleteCodeGenPipeline() &&
          "Cannot emit MC with limited codegen pipeline");
 
-  Ctx = &MMIWP->getMMI().getContext();
+  MCContext &Ctx = MMI->getContext();
   // libunwind is unable to load compact unwind dynamically, so we must generate
   // DWARF unwind info for the JIT.
   Options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::Always;
@@ -261,7 +275,7 @@ bool CodeGenTargetMachineImpl::addPassesToEmitMC(PassManagerBase &PM,
   const MCSubtargetInfo &STI = *getMCSubtargetInfo();
   const MCRegisterInfo &MRI = *getMCRegisterInfo();
   std::unique_ptr<MCCodeEmitter> MCE(
-      getTarget().createMCCodeEmitter(*getMCInstrInfo(), *Ctx));
+      getTarget().createMCCodeEmitter(*getMCInstrInfo(), Ctx));
   if (!MCE)
     return true;
   MCAsmBackend *MAB =
@@ -271,7 +285,7 @@ bool CodeGenTargetMachineImpl::addPassesToEmitMC(PassManagerBase &PM,
 
   const Triple &T = getTargetTriple();
   std::unique_ptr<MCStreamer> AsmStreamer(getTarget().createMCObjectStreamer(
-      T, *Ctx, std::unique_ptr<MCAsmBackend>(MAB), MAB->createObjectWriter(Out),
+      T, Ctx, std::unique_ptr<MCAsmBackend>(MAB), MAB->createObjectWriter(Out),
       std::move(MCE), STI));
 
   // Create the AsmPrinter, which takes ownership of AsmStreamer if successful.
diff --git a/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp
index 6167e99aecf03..76841d4116ef4 100644
--- a/llvm/lib/CodeGen/MachineModuleInfo.cpp
+++ b/llvm/lib/CodeGen/MachineModuleInfo.cpp
@@ -37,17 +37,6 @@ void MachineModuleInfo::finalize() {
   ObjFileMMI = nullptr;
 }
 
-MachineModuleInfo::MachineModuleInfo(MachineModuleInfo &&MMI)
-    : TM(std::move(MMI.TM)),
-      Context(TM.getTargetTriple(), TM.getMCAsmInfo(), TM.getMCRegisterInfo(),
-              TM.getMCSubtargetInfo(), nullptr, &TM.Options.MCOptions, false),
-      MachineFunctions(std::move(MMI.MachineFunctions)) {
-  Context.setObjectFileInfo(TM.getObjFileLowering());
-  ObjFileMMI = MMI.ObjFileMMI;
-  ExternalContext = MMI.ExternalContext;
-  TheModule = MMI.TheModule;
-}
-
 MachineModuleInfo::MachineModuleInfo(const TargetMachine *TM)
     : TM(*TM), Context(TM->getTargetTriple(), TM->getMCAsmInfo(),
                        TM->getMCRegisterInfo(), TM->getMCSubtargetInfo(),
@@ -150,15 +139,8 @@ FunctionPass *llvm::createFreeMachineFunctionPass() {
   return new FreeMachineFunction();
 }
 
-MachineModuleInfoWrapperPass::MachineModuleInfoWrapperPass(
-    const TargetMachine *TM)
-    : ImmutablePass(ID), MMI(TM) {
-  initializeMachineModuleInfoWrapperPassPass(*PassRegistry::getPassRegistry());
-}
-
-MachineModuleInfoWrapperPass::MachineModuleInfoWrapperPass(
-    const TargetMachine *TM, MCContext *ExtContext)
-    : ImmutablePass(ID), MMI(TM, ExtContext) {
+MachineModuleInfoWrapperPass::MachineModuleInfoWrapperPass()
+    : ImmutablePass(ID) {
   initializeMachineModuleInfoWrapperPassPass(*PassRegistry::getPassRegistry());
 }
 
@@ -193,6 +175,7 @@ static uint64_t getLocCookie(const SMDiagnostic &SMD, const SourceMgr &SrcMgr,
 }
 
 bool MachineModuleInfoWrapperPass::doInitialization(Module &M) {
+  MachineModuleInfo &MMI = getMMI();
   MMI.initialize();
   MMI.TheModule = &M;
   LLVMContext &Ctx = M.getContext();
@@ -210,7 +193,7 @@ bool MachineModuleInfoWrapperPass::doInitialization(Module &M) {
 }
 
 bool MachineModuleInfoWrapperPass::doFinalization(Module &M) {
-  MMI.finalize();
+  getMMI().finalize();
   return false;
 }
 
diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
index 5f3067b2a97ea..e73db347e4c01 100644
--- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
+++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
@@ -66,9 +66,8 @@ MCJIT::MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> TM,
              std::shared_ptr<MCJITMemoryManager> MemMgr,
              std::shared_ptr<LegacyJITSymbolResolver> Resolver)
     : ExecutionEngine(TM->createDataLayout(), std::move(M)), TM(std::move(TM)),
-      Ctx(nullptr), MemMgr(std::move(MemMgr)),
-      Resolver(*this, std::move(Resolver)), Dyld(*this->MemMgr, this->Resolver),
-      ObjCache(nullptr) {
+      MemMgr(std::move(MemMgr)), Resolver(*this, std::move(Resolver)),
+      Dyld(*this->MemMgr, this->Resolver), ObjCache(nullptr) {
   // FIXME: We are managing our modules, so we do not want the base class
   // ExecutionEngine to manage them as well. To avoid double destruction
   // of the first (and only) module added in ExecutionEngine constructor
@@ -163,7 +162,7 @@ std::unique_ptr<MemoryBuffer> MCJIT::emitObject(Module *M) {
 
   // Turn the machine code intermediate representation into bytes in memory
   // that may be executed.
-  if (TM->addPassesToEmitMC(PM, Ctx, ObjStream, !getVerifyModules()))
+  if (TM->addPassesToEmitMC(PM, ObjStream, !getVerifyModules()))
     report_fatal_error("Target does not support MC emission!");
 
   // Initialize passes.
diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h
index fbe64fabd3240..596b83dbb8a05 100644
--- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h
+++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h
@@ -168,7 +168,6 @@ class MCJIT : public ExecutionEngine {
   };
 
   std::unique_ptr<TargetMachine> TM;
-  MCContext *Ctx;
   std::shared_ptr<MCJITMemoryManager> MemMgr;
   LinkingSymbolResolver Resolver;
   RuntimeDyld Dyld;
diff --git a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
index c4d65af1b57f8..b09cc738996a5 100644
--- a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
@@ -46,8 +46,7 @@ Expected<SimpleCompiler::CompileResult> SimpleCompiler::operator()(Module &M) {
     raw_svector_ostream ObjStream(ObjBufferSV);
 
     legacy::PassManager PM;
-    MCContext *Ctx;
-    if (TM.addPassesToEmitMC(PM, Ctx, ObjStream))
+    if (TM.addPassesToEmitMC(PM, ObjStream))
       return make_error<StringError>("Target does not support MC emission",
                                      inconvertibleErrorCode());
     PM.run(M);
diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
index ce408b4034f83..d7a05ebf1f738 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
+++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
@@ -133,8 +133,7 @@ void DirectXTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
 
 bool DirectXTargetMachine::addPassesToEmitFile(
     PassManagerBase &PM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType, bool DisableVerify,
-    MachineModuleInfoWrapperPass *MMIWP) {
+    CodeGenFileType FileType, bool DisableVerify, MachineModuleInfo *MMI) {
   TargetPassConfig *PassConfig = createPassConfig(PM);
   PassConfig->addCodeGenPrepare();
 
@@ -150,8 +149,17 @@ bool DirectXTargetMachine::addPassesToEmitFile(
       // globals don't pollute the DXIL.
       PM.add(createDXContainerGlobalsPass());
 
-      if (!MMIWP)
-        MMIWP = new MachineModuleInfoWrapperPass(this);
+      MachineModuleInfoWrapperPass *MMIWP;
+      if (MMI) {
+        MMIWP = new NonOwningMachineModuleInfoWrapperPass(*MMI);
+      } else {
+        MMIWP = new OwningMachineModuleInfoWrapperPass(*this);
+        MMI = &MMIWP->getMMI();
+      }
+      // Check (for the case of externally-managed MMI) if the TM of MMI is
+      // the same as this target machine
+      if (&MMI->getTarget() != this)
+        return true;
       PM.add(MMIWP);
       if (addAsmPrinter(PM, Out, DwoOut, FileType,
                         MMIWP->getMMI().getContext()))
@@ -166,9 +174,9 @@ bool DirectXTargetMachine::addPassesToEmitFile(
 }
 
 bool DirectXTargetMachine::addPassesToEmitMC(PassManagerBase &PM,
-                                             MCContext *&Ctx,
                                              raw_pwrite_stream &Out,
-                                             bool DisableVerify) {
+                                             bool DisableVerify,
+                                             MachineModuleInfo *MMI) {
   return true;
 }
 
diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.h b/llvm/lib/Target/DirectX/DirectXTargetMachine.h
index 7ba80d2ba5de1..21c50d4c996a9 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetMachine.h
+++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.h
@@ -33,10 +33,10 @@ class DirectXTargetMachine : public CodeGenTargetMachineImpl {
   bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out,
                            raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
                            bool DisableVerify,
-                           MachineModuleInfoWrapperPass *MMIWP) override;
+                           MachineModuleInfo *MMIWP) override;
 
-  bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
-                         raw_pwrite_stream &Out, bool DisableVerify) override;
+  bool add...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Apr 6, 2025

@llvm/pr-subscribers-offload

Author: Matin Raayai (matinraayai)

Changes

This PR makes the following changes to the MachineModuleInfoWrapperPass:

  1. MachineModuleInfoWrapperPass is now an interface pass with its own typeid.
  2. Two kinds of MachineModuleInfoWrapperPass are introduced, one is OwningMachineModuleInfoWrapperPass, which behaves the same way as the original MachineModuleInfoWrapperPass, and one is NonOwningMachineModuleInfoWrapperPass, which instead takes a reference to an already created MachineModuleInfo.
    Also, this PR removes the move constructor for MachineModuleInfo since it was not correct to begin with.

Originally, I planned on only having the non-owning version available, but then I realized that many users of TargetMachine::addPassesToEmitFile don't link against CodeGen, which means they cannot create a MachineModuleInfo and manage its lifetime. I also think its not ideal to explicitly link against CodeGen.

Feedback is greatly appreciated.
cc: @aeubanks @arsenm


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

15 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h (+15-14)
  • (modified) llvm/include/llvm/CodeGen/MachineModuleInfo.h (+36-11)
  • (modified) llvm/include/llvm/Target/TargetMachine.h (+18-16)
  • (modified) llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp (+32-18)
  • (modified) llvm/lib/CodeGen/MachineModuleInfo.cpp (+4-21)
  • (modified) llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp (+3-4)
  • (modified) llvm/lib/ExecutionEngine/MCJIT/MCJIT.h (-1)
  • (modified) llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp (+1-2)
  • (modified) llvm/lib/Target/DirectX/DirectXTargetMachine.cpp (+14-6)
  • (modified) llvm/lib/Target/DirectX/DirectXTargetMachine.h (+3-3)
  • (modified) llvm/lib/Target/NVPTX/NVPTXTargetMachine.h (+2-2)
  • (modified) llvm/lib/Target/SPIRV/SPIRVAPI.cpp (+4-5)
  • (modified) llvm/tools/llc/llc.cpp (+5-9)
  • (modified) llvm/tools/llvm-exegesis/lib/Assembler.cpp (+4-4)
  • (modified) offload/plugins-nextgen/common/src/JIT.cpp (+3-2)
diff --git a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
index 7bb4420e555fb..1491eb3d42964 100644
--- a/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
+++ b/llvm/include/llvm/CodeGen/CodeGenTargetMachineImpl.h
@@ -44,22 +44,23 @@ class CodeGenTargetMachineImpl : public TargetMachine {
   virtual TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
 
   /// Add passes to the specified pass manager to get the specified file
-  /// emitted.  Typically this will involve several steps of code generation.
-  /// \p MMIWP is an optional parameter that, if set to non-nullptr,
-  /// will be used to set the MachineModuloInfo for this PM.
-  bool
-  addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out,
-                      raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
-                      bool DisableVerify = true,
-                      MachineModuleInfoWrapperPass *MMIWP = nullptr) override;
+  /// emitted. Typically, this will involve several steps of code generation.
+  /// This method should return true if emission of this file type is not
+  /// supported, or false on success.
+  /// \p MMI an optional, externally-managed \c MachineModuleInfo to
+  /// hold the generated machine code even after the \p PM is destroyed
+  bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out,
+                           raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
+                           bool DisableVerify = true,
+                           MachineModuleInfo *MMI = nullptr) override;
 
   /// Add passes to the specified pass manager to get machine code emitted with
-  /// the MCJIT. This method returns true if machine code is not supported. It
-  /// fills the MCContext Ctx pointer which can be used to build custom
-  /// MCStreamer.
-  bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
-                         raw_pwrite_stream &Out,
-                         bool DisableVerify = true) override;
+  /// the MCJIT. This method returns true if machine code is not supported.
+  /// \p MMI an optional, externally-managed \c MachineModuleInfo to
+  /// hold the generated machine code even after the \p PM is destroyed
+  bool addPassesToEmitMC(PassManagerBase &PM, raw_pwrite_stream &Out,
+                         bool DisableVerify = true,
+                         MachineModuleInfo *MMI = nullptr) override;
 
   /// Adds an AsmPrinter pass to the pipeline that prints assembly or
   /// machine code from the MI representation.
diff --git a/llvm/include/llvm/CodeGen/MachineModuleInfo.h b/llvm/include/llvm/CodeGen/MachineModuleInfo.h
index bec500dc609f3..4e4582fa0021a 100644
--- a/llvm/include/llvm/CodeGen/MachineModuleInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineModuleInfo.h
@@ -106,15 +106,11 @@ class MachineModuleInfo {
   const Function *LastRequest = nullptr; ///< Used for shortcut/cache.
   MachineFunction *LastResult = nullptr; ///< Used for shortcut/cache.
 
-  MachineModuleInfo &operator=(MachineModuleInfo &&MMII) = delete;
-
 public:
   explicit MachineModuleInfo(const TargetMachine *TM = nullptr);
 
   explicit MachineModuleInfo(const TargetMachine *TM, MCContext *ExtContext);
 
-  MachineModuleInfo(MachineModuleInfo &&MMII);
-
   ~MachineModuleInfo();
 
   void initialize();
@@ -167,22 +163,51 @@ class MachineModuleInfo {
   /// \}
 }; // End class MachineModuleInfo
 
+/// \brief Interface for pass that provide access to \c MachineModuleInfo
+/// being worked on
 class MachineModuleInfoWrapperPass : public ImmutablePass {
-  MachineModuleInfo MMI;
 
 public:
   static char ID; // Pass identification, replacement for typeid
-  explicit MachineModuleInfoWrapperPass(const TargetMachine *TM = nullptr);
-
-  explicit MachineModuleInfoWrapperPass(const TargetMachine *TM,
-                                        MCContext *ExtContext);
+  MachineModuleInfoWrapperPass();
 
   // Initialization and Finalization
   bool doInitialization(Module &) override;
   bool doFinalization(Module &) override;
 
-  MachineModuleInfo &getMMI() { return MMI; }
-  const MachineModuleInfo &getMMI() const { return MMI; }
+  virtual MachineModuleInfo &getMMI() = 0;
+  virtual const MachineModuleInfo &getMMI() const = 0;
+};
+
+/// \brief a version of \c MachineModuleInfoWrapperPass that manages the
+/// lifetime of its \c MachineModuleInfo
+class OwningMachineModuleInfoWrapperPass : public MachineModuleInfoWrapperPass {
+  MachineModuleInfo MMI;
+
+public:
+  explicit OwningMachineModuleInfoWrapperPass(const TargetMachine &TM)
+      : MMI(&TM) {};
+
+  OwningMachineModuleInfoWrapperPass(const TargetMachine &TM,
+                                     MCContext &ExtContext)
+      : MMI(&TM, &ExtContext) {};
+
+  MachineModuleInfo &getMMI() override { return MMI; }
+  const MachineModuleInfo &getMMI() const override { return MMI; }
+};
+
+/// \brief a version of \c MachineModuleInfoWrapperPass that does not manage the
+/// lifetime of its \c MachineModuleInfo
+class NonOwningMachineModuleInfoWrapperPass
+    : public MachineModuleInfoWrapperPass {
+  MachineModuleInfo &MMI;
+
+public:
+  explicit NonOwningMachineModuleInfoWrapperPass(MachineModuleInfo &MMI)
+      : MMI(MMI) {};
+
+  MachineModuleInfo &getMMI() override { return MMI; }
+  const MachineModuleInfo &getMMI() const override { return MMI; }
 };
 
 /// An analysis that produces \c MachineModuleInfo for a module.
diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h
index 27eeb415ed644..3d8c6694297c9 100644
--- a/llvm/include/llvm/Target/TargetMachine.h
+++ b/llvm/include/llvm/Target/TargetMachine.h
@@ -38,7 +38,7 @@ using ModulePassManager = PassManager<Module>;
 
 class Function;
 class GlobalValue;
-class MachineModuleInfoWrapperPass;
+class MachineModuleInfo;
 struct MachineSchedContext;
 class Mangler;
 class MCAsmInfo;
@@ -401,27 +401,29 @@ class TargetMachine {
   virtual void registerDefaultAliasAnalyses(AAManager &) {}
 
   /// Add passes to the specified pass manager to get the specified file
-  /// emitted.  Typically this will involve several steps of code generation.
+  /// emitted. Typically, this will involve several steps of code generation.
   /// This method should return true if emission of this file type is not
   /// supported, or false on success.
-  /// \p MMIWP is an optional parameter that, if set to non-nullptr,
-  /// will be used to set the MachineModuloInfo for this PM.
-  virtual bool
-  addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &,
-                      raw_pwrite_stream *, CodeGenFileType,
-                      bool /*DisableVerify*/ = true,
-                      MachineModuleInfoWrapperPass *MMIWP = nullptr) {
+  /// For targets that utilize the target-independent code generator
+  /// (CodeGen), an externally-managed \c MachineModuleInfo can be provided
+  /// to ensure persistence of the generated machine code even after the pass
+  /// manager is destroyed
+  virtual bool addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &,
+                                   raw_pwrite_stream *, CodeGenFileType,
+                                   bool /*DisableVerify*/ = true,
+                                   MachineModuleInfo * = nullptr) {
     return true;
   }
 
   /// Add passes to the specified pass manager to get machine code emitted with
-  /// the MCJIT. This method returns true if machine code is not supported. It
-  /// fills the MCContext Ctx pointer which can be used to build custom
-  /// MCStreamer.
-  ///
-  virtual bool addPassesToEmitMC(PassManagerBase &, MCContext *&,
-                                 raw_pwrite_stream &,
-                                 bool /*DisableVerify*/ = true) {
+  /// the MCJIT. This method returns true if machine code is not supported.
+  /// For targets that utilize the target-independent code generator
+  /// (CodeGen), an externally-managed \c MachineModuleInfo can be provided
+  /// to ensure persistence of the generated machine code even after the pass
+  /// manager is destroyed
+  virtual bool addPassesToEmitMC(PassManagerBase &, raw_pwrite_stream &,
+                                 bool /*DisableVerify*/ = true,
+                                 MachineModuleInfo * = nullptr) {
     return true;
   }
 
diff --git a/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp b/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp
index 5757ca1b3adf8..3495a45859054 100644
--- a/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp
+++ b/llvm/lib/CodeGen/CodeGenTargetMachineImpl.cpp
@@ -210,18 +210,27 @@ CodeGenTargetMachineImpl::createMCStreamer(raw_pwrite_stream &Out,
 
 bool CodeGenTargetMachineImpl::addPassesToEmitFile(
     PassManagerBase &PM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType, bool DisableVerify,
-    MachineModuleInfoWrapperPass *MMIWP) {
-  // Add common CodeGen passes.
-  if (!MMIWP)
-    MMIWP = new MachineModuleInfoWrapperPass(this);
+    CodeGenFileType FileType, bool DisableVerify, MachineModuleInfo *MMI) {
+  // Add the wrapper pass for MMI
+  MachineModuleInfoWrapperPass *MMIWP;
+  if (MMI) {
+    MMIWP = new NonOwningMachineModuleInfoWrapperPass(*MMI);
+  } else {
+    MMIWP = new OwningMachineModuleInfoWrapperPass(*this);
+    MMI = &MMIWP->getMMI();
+  }
+  // Check (for the case of externally-managed MMI) if the TM of MMI is
+  // the same as this target machine
+  if (&MMI->getTarget() != this)
+    return true;
+
   TargetPassConfig *PassConfig =
       addPassesToGenerateCode(*this, PM, DisableVerify, *MMIWP);
   if (!PassConfig)
     return true;
 
   if (TargetPassConfig::willCompleteCodeGenPipeline()) {
-    if (addAsmPrinter(PM, Out, DwoOut, FileType, MMIWP->getMMI().getContext()))
+    if (addAsmPrinter(PM, Out, DwoOut, FileType, MMI->getContext()))
       return true;
   } else {
     // MIR printing is redundant with -filetype=null.
@@ -233,17 +242,22 @@ bool CodeGenTargetMachineImpl::addPassesToEmitFile(
   return false;
 }
 
-/// addPassesToEmitMC - Add passes to the specified pass manager to get
-/// machine code emitted with the MCJIT. This method returns true if machine
-/// code is not supported. It fills the MCContext Ctx pointer which can be
-/// used to build custom MCStreamer.
-///
 bool CodeGenTargetMachineImpl::addPassesToEmitMC(PassManagerBase &PM,
-                                                 MCContext *&Ctx,
                                                  raw_pwrite_stream &Out,
-                                                 bool DisableVerify) {
-  // Add common CodeGen passes.
-  MachineModuleInfoWrapperPass *MMIWP = new MachineModuleInfoWrapperPass(this);
+                                                 bool DisableVerify,
+                                                 MachineModuleInfo *MMI) {
+  // Add the wrapper pass for MMI
+  MachineModuleInfoWrapperPass *MMIWP;
+  if (MMI) {
+    MMIWP = new NonOwningMachineModuleInfoWrapperPass(*MMI);
+  } else {
+    MMIWP = new OwningMachineModuleInfoWrapperPass(*this);
+    MMI = &MMIWP->getMMI();
+  }
+  // Check (for the case of externally-managed MMI) if the TM of MMI is
+  // the same as this target machine
+  if (&MMI->getTarget() != this)
+    return true;
   TargetPassConfig *PassConfig =
       addPassesToGenerateCode(*this, PM, DisableVerify, *MMIWP);
   if (!PassConfig)
@@ -251,7 +265,7 @@ bool CodeGenTargetMachineImpl::addPassesToEmitMC(PassManagerBase &PM,
   assert(TargetPassConfig::willCompleteCodeGenPipeline() &&
          "Cannot emit MC with limited codegen pipeline");
 
-  Ctx = &MMIWP->getMMI().getContext();
+  MCContext &Ctx = MMI->getContext();
   // libunwind is unable to load compact unwind dynamically, so we must generate
   // DWARF unwind info for the JIT.
   Options.MCOptions.EmitDwarfUnwind = EmitDwarfUnwindType::Always;
@@ -261,7 +275,7 @@ bool CodeGenTargetMachineImpl::addPassesToEmitMC(PassManagerBase &PM,
   const MCSubtargetInfo &STI = *getMCSubtargetInfo();
   const MCRegisterInfo &MRI = *getMCRegisterInfo();
   std::unique_ptr<MCCodeEmitter> MCE(
-      getTarget().createMCCodeEmitter(*getMCInstrInfo(), *Ctx));
+      getTarget().createMCCodeEmitter(*getMCInstrInfo(), Ctx));
   if (!MCE)
     return true;
   MCAsmBackend *MAB =
@@ -271,7 +285,7 @@ bool CodeGenTargetMachineImpl::addPassesToEmitMC(PassManagerBase &PM,
 
   const Triple &T = getTargetTriple();
   std::unique_ptr<MCStreamer> AsmStreamer(getTarget().createMCObjectStreamer(
-      T, *Ctx, std::unique_ptr<MCAsmBackend>(MAB), MAB->createObjectWriter(Out),
+      T, Ctx, std::unique_ptr<MCAsmBackend>(MAB), MAB->createObjectWriter(Out),
       std::move(MCE), STI));
 
   // Create the AsmPrinter, which takes ownership of AsmStreamer if successful.
diff --git a/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp
index 6167e99aecf03..76841d4116ef4 100644
--- a/llvm/lib/CodeGen/MachineModuleInfo.cpp
+++ b/llvm/lib/CodeGen/MachineModuleInfo.cpp
@@ -37,17 +37,6 @@ void MachineModuleInfo::finalize() {
   ObjFileMMI = nullptr;
 }
 
-MachineModuleInfo::MachineModuleInfo(MachineModuleInfo &&MMI)
-    : TM(std::move(MMI.TM)),
-      Context(TM.getTargetTriple(), TM.getMCAsmInfo(), TM.getMCRegisterInfo(),
-              TM.getMCSubtargetInfo(), nullptr, &TM.Options.MCOptions, false),
-      MachineFunctions(std::move(MMI.MachineFunctions)) {
-  Context.setObjectFileInfo(TM.getObjFileLowering());
-  ObjFileMMI = MMI.ObjFileMMI;
-  ExternalContext = MMI.ExternalContext;
-  TheModule = MMI.TheModule;
-}
-
 MachineModuleInfo::MachineModuleInfo(const TargetMachine *TM)
     : TM(*TM), Context(TM->getTargetTriple(), TM->getMCAsmInfo(),
                        TM->getMCRegisterInfo(), TM->getMCSubtargetInfo(),
@@ -150,15 +139,8 @@ FunctionPass *llvm::createFreeMachineFunctionPass() {
   return new FreeMachineFunction();
 }
 
-MachineModuleInfoWrapperPass::MachineModuleInfoWrapperPass(
-    const TargetMachine *TM)
-    : ImmutablePass(ID), MMI(TM) {
-  initializeMachineModuleInfoWrapperPassPass(*PassRegistry::getPassRegistry());
-}
-
-MachineModuleInfoWrapperPass::MachineModuleInfoWrapperPass(
-    const TargetMachine *TM, MCContext *ExtContext)
-    : ImmutablePass(ID), MMI(TM, ExtContext) {
+MachineModuleInfoWrapperPass::MachineModuleInfoWrapperPass()
+    : ImmutablePass(ID) {
   initializeMachineModuleInfoWrapperPassPass(*PassRegistry::getPassRegistry());
 }
 
@@ -193,6 +175,7 @@ static uint64_t getLocCookie(const SMDiagnostic &SMD, const SourceMgr &SrcMgr,
 }
 
 bool MachineModuleInfoWrapperPass::doInitialization(Module &M) {
+  MachineModuleInfo &MMI = getMMI();
   MMI.initialize();
   MMI.TheModule = &M;
   LLVMContext &Ctx = M.getContext();
@@ -210,7 +193,7 @@ bool MachineModuleInfoWrapperPass::doInitialization(Module &M) {
 }
 
 bool MachineModuleInfoWrapperPass::doFinalization(Module &M) {
-  MMI.finalize();
+  getMMI().finalize();
   return false;
 }
 
diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
index 5f3067b2a97ea..e73db347e4c01 100644
--- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
+++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.cpp
@@ -66,9 +66,8 @@ MCJIT::MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> TM,
              std::shared_ptr<MCJITMemoryManager> MemMgr,
              std::shared_ptr<LegacyJITSymbolResolver> Resolver)
     : ExecutionEngine(TM->createDataLayout(), std::move(M)), TM(std::move(TM)),
-      Ctx(nullptr), MemMgr(std::move(MemMgr)),
-      Resolver(*this, std::move(Resolver)), Dyld(*this->MemMgr, this->Resolver),
-      ObjCache(nullptr) {
+      MemMgr(std::move(MemMgr)), Resolver(*this, std::move(Resolver)),
+      Dyld(*this->MemMgr, this->Resolver), ObjCache(nullptr) {
   // FIXME: We are managing our modules, so we do not want the base class
   // ExecutionEngine to manage them as well. To avoid double destruction
   // of the first (and only) module added in ExecutionEngine constructor
@@ -163,7 +162,7 @@ std::unique_ptr<MemoryBuffer> MCJIT::emitObject(Module *M) {
 
   // Turn the machine code intermediate representation into bytes in memory
   // that may be executed.
-  if (TM->addPassesToEmitMC(PM, Ctx, ObjStream, !getVerifyModules()))
+  if (TM->addPassesToEmitMC(PM, ObjStream, !getVerifyModules()))
     report_fatal_error("Target does not support MC emission!");
 
   // Initialize passes.
diff --git a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h
index fbe64fabd3240..596b83dbb8a05 100644
--- a/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h
+++ b/llvm/lib/ExecutionEngine/MCJIT/MCJIT.h
@@ -168,7 +168,6 @@ class MCJIT : public ExecutionEngine {
   };
 
   std::unique_ptr<TargetMachine> TM;
-  MCContext *Ctx;
   std::shared_ptr<MCJITMemoryManager> MemMgr;
   LinkingSymbolResolver Resolver;
   RuntimeDyld Dyld;
diff --git a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
index c4d65af1b57f8..b09cc738996a5 100644
--- a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp
@@ -46,8 +46,7 @@ Expected<SimpleCompiler::CompileResult> SimpleCompiler::operator()(Module &M) {
     raw_svector_ostream ObjStream(ObjBufferSV);
 
     legacy::PassManager PM;
-    MCContext *Ctx;
-    if (TM.addPassesToEmitMC(PM, Ctx, ObjStream))
+    if (TM.addPassesToEmitMC(PM, ObjStream))
       return make_error<StringError>("Target does not support MC emission",
                                      inconvertibleErrorCode());
     PM.run(M);
diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
index ce408b4034f83..d7a05ebf1f738 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
+++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.cpp
@@ -133,8 +133,7 @@ void DirectXTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
 
 bool DirectXTargetMachine::addPassesToEmitFile(
     PassManagerBase &PM, raw_pwrite_stream &Out, raw_pwrite_stream *DwoOut,
-    CodeGenFileType FileType, bool DisableVerify,
-    MachineModuleInfoWrapperPass *MMIWP) {
+    CodeGenFileType FileType, bool DisableVerify, MachineModuleInfo *MMI) {
   TargetPassConfig *PassConfig = createPassConfig(PM);
   PassConfig->addCodeGenPrepare();
 
@@ -150,8 +149,17 @@ bool DirectXTargetMachine::addPassesToEmitFile(
       // globals don't pollute the DXIL.
       PM.add(createDXContainerGlobalsPass());
 
-      if (!MMIWP)
-        MMIWP = new MachineModuleInfoWrapperPass(this);
+      MachineModuleInfoWrapperPass *MMIWP;
+      if (MMI) {
+        MMIWP = new NonOwningMachineModuleInfoWrapperPass(*MMI);
+      } else {
+        MMIWP = new OwningMachineModuleInfoWrapperPass(*this);
+        MMI = &MMIWP->getMMI();
+      }
+      // Check (for the case of externally-managed MMI) if the TM of MMI is
+      // the same as this target machine
+      if (&MMI->getTarget() != this)
+        return true;
       PM.add(MMIWP);
       if (addAsmPrinter(PM, Out, DwoOut, FileType,
                         MMIWP->getMMI().getContext()))
@@ -166,9 +174,9 @@ bool DirectXTargetMachine::addPassesToEmitFile(
 }
 
 bool DirectXTargetMachine::addPassesToEmitMC(PassManagerBase &PM,
-                                             MCContext *&Ctx,
                                              raw_pwrite_stream &Out,
-                                             bool DisableVerify) {
+                                             bool DisableVerify,
+                                             MachineModuleInfo *MMI) {
   return true;
 }
 
diff --git a/llvm/lib/Target/DirectX/DirectXTargetMachine.h b/llvm/lib/Target/DirectX/DirectXTargetMachine.h
index 7ba80d2ba5de1..21c50d4c996a9 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetMachine.h
+++ b/llvm/lib/Target/DirectX/DirectXTargetMachine.h
@@ -33,10 +33,10 @@ class DirectXTargetMachine : public CodeGenTargetMachineImpl {
   bool addPassesToEmitFile(PassManagerBase &PM, raw_pwrite_stream &Out,
                            raw_pwrite_stream *DwoOut, CodeGenFileType FileType,
                            bool DisableVerify,
-                           MachineModuleInfoWrapperPass *MMIWP) override;
+                           MachineModuleInfo *MMIWP) override;
 
-  bool addPassesToEmitMC(PassManagerBase &PM, MCContext *&Ctx,
-                         raw_pwrite_stream &Out, bool DisableVerify) override;
+  bool add...
[truncated]

Copy link

github-actions bot commented Apr 6, 2025

⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
Please turn off Keep my email addresses private setting in your account.
See LLVM Discourse for more information.

Copy link

github-actions bot commented Apr 6, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
Comment on lines +182 to +185
/// \brief a version of \c MachineModuleInfoWrapperPass that manages the
/// lifetime of its \c MachineModuleInfo
class OwningMachineModuleInfoWrapperPass : public MachineModuleInfoWrapperPass {
MachineModuleInfo MMI;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should not have different versions of the pass. We should change wholly change the ownership mode for the pass to not own it.

(Also I've been thinking we should rename MachineModuleInfo. It's really more of a "MachineFunctionMap" or something)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Originally I intended to only have a single version, but the main issue I found was that creating a MachineModuleInfo requires any client of TargetMachine::addPassesToEmitFile and TargetMachine::addPassesToEmitMC to be linked against CodeGen, which it might not be something they want to do. This only applies to targets that implement codegen, however. All other out-of-tree non-codegen targets are not affected.

I will change to my originally intended design if you think it's acceptable to force all TargetMachine clients to link against CodeGen.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess I don't understand what the use case is for this specific pass if you aren't using codegen. MachineModuleInfo, and by extension MachineModuleInfoWrapperPass are a fundamental part of codegen (it is after all just a map of MachineFunction). I would expect for only the owning version to exist, and it to not change the linking requirements of addPassesToEmitFile users

Copy link
Contributor

Choose a reason for hiding this comment

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

One without MachineModuleInfo is for something else; Owning probably isn't the right name (but neither is MachineModuleInfo)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can combine the two passes together into a single MachineModuleInfoWrapperPass that looks like the following:

class MachineModuleInfoWrapperPass : public ImmutablePass {
  MachineModuleInfo *MMI{nullptr};
  bool OwnsMMI{true};
  
  public:
  explicit MachineModuleInfoWrapperPass(const TargetMachine &TM)
      : MMI(new MachineModuleInfo(&TM)), OwnsMMI(true) {};

  MachineModuleInfoWrapperPass(const TargetMachine &TM,
                                     MCContext &ExtContext)
      : MMI(new MachineModuleInfo(&TM, &ExtContext)), OwnsMMI(true) {};
  
  explicit MachineModuleInfoWrapperPass(MachineModuleInfo &MMI) : MMI(&MMI), OwnsMMI(false) {};
  
  MachineModuleInfo &getMMI() override { return MMI; }
  const MachineModuleInfo &getMMI() const override { return MMI; }
};


bool MachineModuleInfoWrapperPass::doFinalization(Module &M) {
  getMMI().finalize();
  if (OwnsMMI)
    delete MMI;
  return false;
};

This way, there is only a single version of the pass, and it will continue to behave the same way as it did before, while supporting the new functionality.
I'm curious, how does addPassestoEmitFiles for the new PM handles the issue of not owning the MMI reference? Does it force its users to link against CodeGen?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: No status
Development

Successfully merging this pull request may close these issues.

None yet

3 participants