[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