[llvm] [CloneModule] Clone ifunc by ShouldCloneDefinition (PR #197183)

via llvm-commits llvm-commits at lists.llvm.org
Tue May 12 06:03:46 PDT 2026


https://github.com/weg0818 created https://github.com/llvm/llvm-project/pull/197183

None

>From 2b9c865bcef8405fc5a0c405ba28206e83603d5d Mon Sep 17 00:00:00 2001
From: maojiaping <maojiaping1 at huawei.com>
Date: Tue, 12 May 2026 20:58:04 +0800
Subject: [PATCH] [CloneModule] Clone ifunc by ShouldCloneDefinition

---
 llvm/lib/Transforms/Utils/CloneModule.cpp | 19 +++++++++++++
 llvm/test/tools/llvm-split/ifunc.ll       | 34 +++++++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 llvm/test/tools/llvm-split/ifunc.ll

diff --git a/llvm/lib/Transforms/Utils/CloneModule.cpp b/llvm/lib/Transforms/Utils/CloneModule.cpp
index bb638f180bfbf..e1966aa39eb17 100644
--- a/llvm/lib/Transforms/Utils/CloneModule.cpp
+++ b/llvm/lib/Transforms/Utils/CloneModule.cpp
@@ -117,6 +117,22 @@ std::unique_ptr<Module> llvm::CloneModule(
 
   for (const GlobalIFunc &I : M.ifuncs()) {
     // Defer setting the resolver function until after functions are cloned.
+    if (!ShouldCloneDefinition(&I)) {
+      // An ifunc also cannot act as an external reference, so we need to create
+      // either a function or a global variable depending on the value type.
+      GlobalValue *GV;
+      if (I.getValueType()->isFunctionTy())
+        GV = Function::Create(cast<FunctionType>(I.getValueType()),
+                              GlobalValue::ExternalLinkage, I.getAddressSpace(),
+                              I.getName(), New.get());
+      else
+        GV = new GlobalVariable(*New, I.getValueType(), false,
+                                GlobalValue::ExternalLinkage, nullptr,
+                                I.getName(), nullptr, I.getThreadLocalMode(),
+                                I.getType()->getAddressSpace());
+      VMap[&I] = GV;
+      continue;
+    }
     auto *GI =
         GlobalIFunc::create(I.getValueType(), I.getAddressSpace(),
                             I.getLinkage(), I.getName(), nullptr, New.get());
@@ -174,6 +190,9 @@ std::unique_ptr<Module> llvm::CloneModule(
   }
 
   for (const GlobalIFunc &I : M.ifuncs()) {
+    // We already dealt with undefined ifuncs above.
+    if (!ShouldCloneDefinition(&I))
+      continue;
     GlobalIFunc *GI = cast<GlobalIFunc>(VMap[&I]);
     if (const Constant *Resolver = I.getResolver())
       GI->setResolver(MapValue(Resolver, VMap));
diff --git a/llvm/test/tools/llvm-split/ifunc.ll b/llvm/test/tools/llvm-split/ifunc.ll
new file mode 100644
index 0000000000000..fc6414d81499b
--- /dev/null
+++ b/llvm/test/tools/llvm-split/ifunc.ll
@@ -0,0 +1,34 @@
+; RUN: llvm-split -j2 -o %t %s
+; RUN: llvm-dis -o - %t0 | FileCheck --check-prefix=CHECK0 %s
+; RUN: llvm-dis -o - %t1 | FileCheck --check-prefix=CHECK1 %s
+
+
+; CHECK0-DAG: declare void @foo_a.ifunc()
+; CHECK1-DAG: @foo_a.ifunc = ifunc void (), ptr @foo_a.resolver
+
+ at foo_a.ifunc = ifunc void (), ptr @foo_a.resolver
+
+; CHECK0-DAG: define hidden void @foo.impl()
+; CHECK1-DAG: declare hidden void @foo.impl()
+
+define internal void @foo.impl() {
+entry:
+  ret void
+}
+
+; CHECK0-DAG: declare hidden ptr @foo_a.resolver()
+; CHECK1-DAG: define hidden ptr @foo_a.resolver()
+
+define internal ptr @foo_a.resolver() {
+entry:
+  ret ptr @foo.impl
+}
+
+; CHECK0-DAG: declare void @bar_a()
+; CHECK1-DAG: define void @bar_a()
+
+define void @bar_a() {
+entry:
+  call void @foo_a.ifunc()
+  ret void
+}
\ No newline at end of file



More information about the llvm-commits mailing list