[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