[llvm] Implement Move-assignment for llvm::Module (NFC) (PR #117270)
Mehdi Amini via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 21 17:05:00 PST 2024
https://github.com/joker-eph updated https://github.com/llvm/llvm-project/pull/117270
>From 1c5be453f4ebbe275b659283bbee7648f4e08a36 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Thu, 21 Nov 2024 16:53:26 -0800
Subject: [PATCH] Implement Move-assignment for llvm::Module (NFC)
Move-assignment is quite convenient in various situation, and work-around
having it available is very convoluted.
---
llvm/include/llvm/IR/Module.h | 9 ++--
llvm/lib/IR/Module.cpp | 35 +++++++++++++++
llvm/unittests/IR/ModuleTest.cpp | 77 ++++++++++++++++++++++++++++++++
3 files changed, 118 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h
index 528e19af5518df..12b50fc506516e 100644
--- a/llvm/include/llvm/IR/Module.h
+++ b/llvm/include/llvm/IR/Module.h
@@ -256,9 +256,12 @@ class LLVM_ABI Module {
/// The module destructor. This will dropAllReferences.
~Module();
-/// @}
-/// @name Module Level Accessors
-/// @{
+ /// Move assignment.
+ Module &operator=(Module &&Other);
+
+ /// @}
+ /// @name Module Level Accessors
+ /// @{
/// Get the module identifier which is, essentially, the name of the module.
/// @returns the module identifier as a string
diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp
index ab48d3e4101b72..ff95f123d48781 100644
--- a/llvm/lib/IR/Module.cpp
+++ b/llvm/lib/IR/Module.cpp
@@ -78,6 +78,41 @@ Module::Module(StringRef MID, LLVMContext &C)
Context.addModule(this);
}
+Module &Module::operator=(Module &&Other) {
+ assert(&Context == &Other.Context && "Module must be in the same Context");
+
+ dropAllReferences();
+
+ ModuleID = std::move(Other.ModuleID);
+ SourceFileName = std::move(Other.SourceFileName);
+ IsNewDbgInfoFormat = std::move(Other.IsNewDbgInfoFormat);
+
+ GlobalList.clear();
+ GlobalList.splice(GlobalList.begin(), Other.GlobalList);
+
+ FunctionList.clear();
+ FunctionList.splice(FunctionList.begin(), Other.FunctionList);
+
+ AliasList.clear();
+ AliasList.splice(AliasList.begin(), Other.AliasList);
+
+ IFuncList.clear();
+ IFuncList.splice(IFuncList.begin(), Other.IFuncList);
+
+ NamedMDList.clear();
+ NamedMDList.splice(NamedMDList.begin(), Other.NamedMDList);
+ GlobalScopeAsm = std::move(Other.GlobalScopeAsm);
+ OwnedMemoryBuffer = std::move(Other.OwnedMemoryBuffer);
+ Materializer = std::move(Other.Materializer);
+ TargetTriple = std::move(Other.TargetTriple);
+ DL = std::move(Other.DL);
+ CurrentIntrinsicIds = std::move(Other.CurrentIntrinsicIds);
+ UniquedIntrinsicNames = std::move(Other.UniquedIntrinsicNames);
+ ModuleFlags = std::move(Other.ModuleFlags);
+ Context.addModule(this);
+ return *this;
+}
+
Module::~Module() {
Context.removeModule(this);
dropAllReferences();
diff --git a/llvm/unittests/IR/ModuleTest.cpp b/llvm/unittests/IR/ModuleTest.cpp
index c18301d5e6d758..36c356730d27a7 100644
--- a/llvm/unittests/IR/ModuleTest.cpp
+++ b/llvm/unittests/IR/ModuleTest.cpp
@@ -14,6 +14,7 @@
#include "llvm/Pass.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <random>
@@ -326,4 +327,80 @@ TEST(ModuleTest, GlobalList) {
EXPECT_EQ(M->global_size(), 1u);
}
+TEST(ModuleTest, MoveAssign) {
+ // This tests that we can move-assign modules, we parse two modules and
+ // move assign the second one to the first one, and check that the print
+ // is equal to what we loaded.
+ LLVMContext C;
+ SMDiagnostic Err;
+ LLVMContext Context;
+ std::unique_ptr<Module> M1 = parseAssemblyString(R"(
+; ModuleID = '<string>'
+source_filename = "<string1>"
+
+ at GV1 = external global i32
+
+ at GA1 = alias void (), ptr @Foo1
+
+define void @Foo1() {
+ ret void
+}
+
+!llvm.module.flags = !{!0}
+!llvm.dbg.cu = !{!1}
+!foo1 = !{!3}
+!bar1 = !{!4}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang1", isOptimized: true, flags: "-O2", runtimeVersion: 0, splitDebugFilename: "abc.debug", emissionKind: LineTablesOnly)
+!2 = !DIFile(filename: "path/to/file1", directory: "/path/to/dir1")
+!3 = !DILocation(line: 12, column: 34, scope: !4)
+!4 = distinct !DISubprogram(name: "foo1", scope: null, spFlags: DISPFlagDefinition, unit: !1)
+)",
+ Err, Context);
+ ASSERT_TRUE(M1.get());
+
+ StringLiteral M2Str = R"(
+; ModuleID = '<string>'
+source_filename = "<string2>"
+
+ at GV2 = external global i32
+
+ at GA2 = alias void (), ptr @Foo2
+
+define void @Foo2() {
+ ret void
+}
+
+!llvm.module.flags = !{!0}
+!llvm.dbg.cu = !{!1}
+!foo2 = !{!3}
+!bar2 = !{!4}
+
+!0 = !{i32 2, !"Debug Info Version", i32 3}
+!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang2", isOptimized: true, flags: "-O2", runtimeVersion: 0, splitDebugFilename: "abc.debug", emissionKind: LineTablesOnly)
+!2 = !DIFile(filename: "path/to/file2", directory: "/path/to/dir2")
+!3 = !DILocation(line: 1234, column: 56, scope: !4)
+!4 = distinct !DISubprogram(name: "foo2", scope: null, spFlags: DISPFlagDefinition, unit: !1)
+)";
+ {
+ std::unique_ptr<Module> M2 = parseAssemblyString(M2Str, Err, Context);
+ ASSERT_TRUE(M2.get());
+ auto *GV1 = M1->getNamedValue("GV1");
+ ASSERT_TRUE(GV1);
+ auto *GV2 = M2->getNamedValue("GV2");
+ ASSERT_TRUE(GV2);
+ ASSERT_EQ(GV2->getParent(), &*M2);
+ *M1 = std::move(*M2);
+ ASSERT_EQ(GV2->getParent(), &*M1);
+ }
+
+ std::string M1Print;
+ {
+ llvm::raw_string_ostream Os(M1Print);
+ Os << "\n" << *M1;
+ }
+ ASSERT_EQ(M2Str, M1Print);
+}
+
} // end namespace
More information about the llvm-commits
mailing list