[llvm] ff494c6 - [MachineModuleInfo] add a grouping mechanism to defer deletion MF (#214525)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 12 18:02:12 PDT 2026


Author: Gang Chen
Date: 2026-08-12T18:02:07-07:00
New Revision: ff494c648aeca35d15c982de35528d413312d128

URL: https://github.com/llvm/llvm-project/commit/ff494c648aeca35d15c982de35528d413312d128
DIFF: https://github.com/llvm/llvm-project/commit/ff494c648aeca35d15c982de35528d413312d128.diff

LOG: [MachineModuleInfo] add a grouping mechanism to defer deletion MF (#214525)

Add a mechanism so that We can defer deleting the MF after a function is
finalized because there are cases in which we want to late-inline those
MF into some caller.

commit-id:d24afd34

Added: 
    llvm/unittests/CodeGen/MachineModuleInfoTest.cpp

Modified: 
    llvm/include/llvm/CodeGen/MachineModuleInfo.h
    llvm/lib/CodeGen/MachineModuleInfo.cpp
    llvm/unittests/CodeGen/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/CodeGen/MachineModuleInfo.h b/llvm/include/llvm/CodeGen/MachineModuleInfo.h
index 6c5ed5622a321..06384fbfc14dc 100644
--- a/llvm/include/llvm/CodeGen/MachineModuleInfo.h
+++ b/llvm/include/llvm/CodeGen/MachineModuleInfo.h
@@ -31,6 +31,8 @@
 #define LLVM_CODEGEN_MACHINEMODULEINFO_H
 
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/EquivalenceClasses.h"
 #include "llvm/ADT/PointerIntPair.h"
 #include "llvm/IR/PassManager.h"
 #include "llvm/MC/MCContext.h"
@@ -107,6 +109,12 @@ class MachineModuleInfo {
   const Function *LastRequest = nullptr; ///< Used for shortcut/cache.
   MachineFunction *LastResult = nullptr; ///< Used for shortcut/cache.
 
+  // MachineFunctions are freed only when all the functions in the same
+  // deletion grouping have been finalized.
+  EquivalenceClasses<const Function *> MFDeletionGrouping;
+  // Add to this set once a function has been fully processed.
+  DenseSet<const Function *> FinalizedMFs;
+
   MachineModuleInfo &operator=(MachineModuleInfo &&MMII) = delete;
 
 public:
@@ -145,8 +153,20 @@ class MachineModuleInfo {
   /// the `MachineFunction`, use `MachineFunctionAnalysis` instead.
   LLVM_ABI MachineFunction *getMachineFunction(const Function &F) const;
 
+  /// Group two IR functions so their MachineFunctions are deleted together once
+  /// both functions have been finalized.
+  void groupMachineFunctionsForDeletion(const Function &F1,
+                                        const Function &F2) {
+    if (FinalizedMFs.count(&F1) || FinalizedMFs.count(&F2))
+      return;
+    MFDeletionGrouping.unionSets(&F1, &F2);
+  }
+
   /// Delete the MachineFunction \p MF and reset the link in the IR Function to
-  /// Machine Function map.
+  /// Machine Function map. When a function is not grouped with any other
+  /// function, its MF gets deleted right away. When a function is grouped with
+  /// other functions, its MF gets deleted when all functions in the same group
+  /// have been finalized.
   LLVM_ABI void deleteMachineFunctionFor(Function &F);
 
   /// Add an externally created MachineFunction \p MF for \p F.

diff  --git a/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp
index 6b7a8cdfd2951..e421378bd5b17 100644
--- a/llvm/lib/CodeGen/MachineModuleInfo.cpp
+++ b/llvm/lib/CodeGen/MachineModuleInfo.cpp
@@ -104,9 +104,25 @@ MachineFunction &MachineModuleInfo::getOrCreateMachineFunction(Function &F) {
 }
 
 void MachineModuleInfo::deleteMachineFunctionFor(Function &F) {
-  MachineFunctions.erase(&F);
+  FinalizedMFs.insert(&F);
   LastRequest = nullptr;
   LastResult = nullptr;
+  auto Leader = MFDeletionGrouping.findLeader(&F);
+  if (Leader == MFDeletionGrouping.member_end()) {
+    MachineFunctions.erase(&F);
+    return;
+  }
+
+  if (llvm::all_of(MFDeletionGrouping.members(*Leader),
+                   [this](const Function *Member) {
+                     return FinalizedMFs.count(Member);
+                   })) {
+    // All functions in the same deletion grouping have been finalized,
+    // so delete all of them.
+    for (const Function *Member : MFDeletionGrouping.members(*Leader)) {
+      MachineFunctions.erase(Member);
+    }
+  }
 }
 
 void MachineModuleInfo::insertFunction(const Function &F,

diff  --git a/llvm/unittests/CodeGen/CMakeLists.txt b/llvm/unittests/CodeGen/CMakeLists.txt
index 709017380fa4e..6302dc2771775 100644
--- a/llvm/unittests/CodeGen/CMakeLists.txt
+++ b/llvm/unittests/CodeGen/CMakeLists.txt
@@ -36,6 +36,7 @@ add_llvm_unittest(CodeGenTests
   MachineDomTreeUpdaterTest.cpp
   MachineInstrBundleIteratorTest.cpp
   MachineInstrTest.cpp
+  MachineModuleInfoTest.cpp
   MachineOperandTest.cpp
   MIR2VecTest.cpp
   RegAllocBasicTest.cpp

diff  --git a/llvm/unittests/CodeGen/MachineModuleInfoTest.cpp b/llvm/unittests/CodeGen/MachineModuleInfoTest.cpp
new file mode 100644
index 0000000000000..81d36feca3ba4
--- /dev/null
+++ b/llvm/unittests/CodeGen/MachineModuleInfoTest.cpp
@@ -0,0 +1,132 @@
+//===- MachineModuleInfoTest.cpp ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "gtest/gtest.h"
+
+#include <memory>
+
+using namespace llvm;
+
+namespace {
+
+class MachineModuleInfoTest : public testing::Test {
+protected:
+  LLVMContext Ctx;
+  std::unique_ptr<Module> M;
+  std::unique_ptr<TargetMachine> TM;
+
+  void SetUp() override {
+    InitializeAllTargets();
+    InitializeAllTargetMCs();
+
+    M = std::make_unique<Module>("test", Ctx);
+
+    Triple TargetTriple("x86_64--");
+    std::string Error;
+    const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
+    if (!T)
+      GTEST_SKIP();
+
+    TargetOptions Options;
+    TM.reset(T->createTargetMachine(TargetTriple, "", "", Options, std::nullopt,
+                                    std::nullopt, CodeGenOptLevel::None));
+    M->setDataLayout(TM->createDataLayout());
+  }
+
+  Function *createEmptyFunction(StringRef Name) {
+    auto *Ty = FunctionType::get(Type::getVoidTy(Ctx), false);
+    return Function::Create(Ty, GlobalValue::ExternalLinkage, Name, M.get());
+  }
+};
+
+// Deleting an ungrouped function erases its MachineFunction immediately.
+TEST_F(MachineModuleInfoTest, DeleteUngroupedMachineFunction) {
+  MachineModuleInfo MMI(TM.get());
+
+  Function *F = createEmptyFunction("f");
+  MMI.getOrCreateMachineFunction(*F);
+  ASSERT_NE(MMI.getMachineFunction(*F), nullptr);
+
+  MMI.deleteMachineFunctionFor(*F);
+  EXPECT_EQ(MMI.getMachineFunction(*F), nullptr);
+}
+
+// When two functions are grouped for deletion, their MachineFunctions must not
+// be erased until every function in the group has been finalized.
+TEST_F(MachineModuleInfoTest, DeleteGroupedMachineFunctions) {
+  MachineModuleInfo MMI(TM.get());
+
+  Function *F1 = createEmptyFunction("f1");
+  Function *F2 = createEmptyFunction("f2");
+  MMI.getOrCreateMachineFunction(*F1);
+  MMI.getOrCreateMachineFunction(*F2);
+  ASSERT_NE(MMI.getMachineFunction(*F1), nullptr);
+  ASSERT_NE(MMI.getMachineFunction(*F2), nullptr);
+
+  MMI.groupMachineFunctionsForDeletion(*F1, *F2);
+
+  // Finalizing only the first grouped function must defer erasure of both
+  // MachineFunctions.
+  MMI.deleteMachineFunctionFor(*F1);
+  EXPECT_NE(MMI.getMachineFunction(*F1), nullptr);
+  EXPECT_NE(MMI.getMachineFunction(*F2), nullptr);
+
+  // Once the last grouped function is finalized, all grouped MachineFunctions
+  // are erased together.
+  MMI.deleteMachineFunctionFor(*F2);
+  EXPECT_EQ(MMI.getMachineFunction(*F1), nullptr);
+  EXPECT_EQ(MMI.getMachineFunction(*F2), nullptr);
+}
+
+// A group of three functions is only erased once all three are finalized,
+// regardless of the order in which they are deleted.
+TEST_F(MachineModuleInfoTest, DeleteGroupedMachineFunctionsThreeMembers) {
+  MachineModuleInfo MMI(TM.get());
+
+  Function *F1 = createEmptyFunction("f1");
+  Function *F2 = createEmptyFunction("f2");
+  Function *F3 = createEmptyFunction("f3");
+  Function *F4 = createEmptyFunction("f4");
+  MMI.getOrCreateMachineFunction(*F1);
+  MMI.getOrCreateMachineFunction(*F2);
+  MMI.getOrCreateMachineFunction(*F3);
+  MMI.getOrCreateMachineFunction(*F4);
+
+  // Build a single group {F1, F2, F3} out of two pairwise groupings.
+  MMI.groupMachineFunctionsForDeletion(*F1, *F2);
+  MMI.groupMachineFunctionsForDeletion(*F2, *F3);
+
+  MMI.deleteMachineFunctionFor(*F3);
+  EXPECT_NE(MMI.getMachineFunction(*F1), nullptr);
+  EXPECT_NE(MMI.getMachineFunction(*F2), nullptr);
+  EXPECT_NE(MMI.getMachineFunction(*F3), nullptr);
+
+  MMI.deleteMachineFunctionFor(*F4);
+  EXPECT_EQ(MMI.getMachineFunction(*F4), nullptr);
+
+  MMI.deleteMachineFunctionFor(*F1);
+  EXPECT_NE(MMI.getMachineFunction(*F1), nullptr);
+  EXPECT_NE(MMI.getMachineFunction(*F2), nullptr);
+  EXPECT_NE(MMI.getMachineFunction(*F3), nullptr);
+
+  MMI.deleteMachineFunctionFor(*F2);
+  EXPECT_EQ(MMI.getMachineFunction(*F1), nullptr);
+  EXPECT_EQ(MMI.getMachineFunction(*F2), nullptr);
+  EXPECT_EQ(MMI.getMachineFunction(*F3), nullptr);
+}
+
+} // namespace


        


More information about the llvm-commits mailing list