[llvm] [IROutliner] do not outline non-uniform constants (PR #195450)

Arda Serdar Pektezol via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 11 09:49:03 PDT 2026


https://github.com/pektezol updated https://github.com/llvm/llvm-project/pull/195450

>From 1178b3a7b107b1dffbf7a00cede44c8ceb4ba43e Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Sat, 2 May 2026 16:24:58 +0300
Subject: [PATCH 1/2] [IROutliner] do not outline non-uniform immarg constants

---
 llvm/lib/Transforms/IPO/IROutliner.cpp        | 43 +++++++++++++++++++
 .../IROutliner/illegal-different-immarg.ll    | 28 ++++++++++++
 2 files changed, 71 insertions(+)
 create mode 100644 llvm/test/Transforms/IROutliner/illegal-different-immarg.ll

diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp
index c1640f3d0e2a7..157fc51a9ab2d 100644
--- a/llvm/lib/Transforms/IPO/IROutliner.cpp
+++ b/llvm/lib/Transforms/IPO/IROutliner.cpp
@@ -579,11 +579,54 @@ collectRegionsConstants(OutlinableRegion &Region,
   return ConstantsTheSame;
 }
 
+/// Check whether \p Region contains a non-uniform constant operand that must
+/// remain an immediate argument.
+///
+/// \param Region - The region to check for non-uniform immarg constants.
+/// \param NotSame - The set of global value numbers that do not have the same
+/// constant in each region.
+/// \returns true if \p Region contains a non-uniform immarg constant, and false
+/// otherwise.
+static bool containsNonUniformImmArgConstant(OutlinableRegion &Region,
+                                             DenseSet<unsigned> &NotSame) {
+  IRSimilarityCandidate &C = *Region.Candidate;
+
+  for (IRInstructionData &ID : C) {
+    auto *CB = dyn_cast<CallBase>(ID.Inst);
+    if (!CB)
+      continue;
+
+    for (unsigned ArgIdx = 0, ArgEnd = CB->arg_size(); ArgIdx != ArgEnd;
+         ++ArgIdx) {
+      if (!CB->paramHasAttr(ArgIdx, Attribute::ImmArg))
+        continue;
+
+      Value *Arg = CB->getArgOperand(ArgIdx);
+      if (!isa<Constant>(Arg))
+        continue;
+
+      std::optional<unsigned> GVN = C.getGVN(Arg);
+      assert(GVN && "Expected a GVN for immarg operand?");
+      if (NotSame.contains(*GVN))
+        return true;
+    }
+  }
+
+  return false;
+}
+
 void OutlinableGroup::findSameConstants(DenseSet<unsigned> &NotSame) {
   DenseMap<unsigned, Constant *> GVNToConstant;
 
   for (OutlinableRegion *Region : Regions)
     collectRegionsConstants(*Region, GVNToConstant, NotSame);
+
+  for (OutlinableRegion *Region : Regions) {
+    if (!containsNonUniformImmArgConstant(*Region, NotSame))
+      continue;
+    IgnoreGroup = true;
+    return;
+  }
 }
 
 void OutlinableGroup::collectGVNStoreSets(Module &M) {
diff --git a/llvm/test/Transforms/IROutliner/illegal-different-immarg.ll b/llvm/test/Transforms/IROutliner/illegal-different-immarg.ll
new file mode 100644
index 0000000000000..04f1ef7165869
--- /dev/null
+++ b/llvm/test/Transforms/IROutliner/illegal-different-immarg.ll
@@ -0,0 +1,28 @@
+; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
+
+; Do not outline structurally similar regions when doing so would replace a
+; non-uniform immarg constant with an outlined-function argument.
+
+declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg)
+
+define ptr @PR194733() {
+entry:
+  br i1 false, label %then, label %else
+
+then:
+  %0 = load ptr, ptr null, align 8
+  call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 false)
+  ret ptr null
+
+else:
+  %1 = load ptr, ptr null, align 8
+  call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 true)
+  %2 = load ptr, ptr null, align 8
+  call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 false)
+  ret ptr null
+}
+; CHECK-LABEL: define ptr @PR194733(
+; CHECK-NOT: outlined_ir_func
+; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 false)
+; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 true)
+; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 false)

>From 24fa032ec93238e85452e6e8c31ce00b3ffd5fac Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Thu, 28 May 2026 21:03:47 +0300
Subject: [PATCH 2/2] [IROutliner] update test case

---
 .../IROutliner/illegal-different-immarg.ll    | 35 +++++++++++++------
 1 file changed, 24 insertions(+), 11 deletions(-)

diff --git a/llvm/test/Transforms/IROutliner/illegal-different-immarg.ll b/llvm/test/Transforms/IROutliner/illegal-different-immarg.ll
index 04f1ef7165869..29f2d123534fa 100644
--- a/llvm/test/Transforms/IROutliner/illegal-different-immarg.ll
+++ b/llvm/test/Transforms/IROutliner/illegal-different-immarg.ll
@@ -1,3 +1,4 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
 
 ; Do not outline structurally similar regions when doing so would replace a
@@ -5,24 +6,36 @@
 
 declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg)
 
+ at slot = global ptr null, align 8
+ at buf = global [1 x i8] zeroinitializer, align 1
+
 define ptr @PR194733() {
+; CHECK-LABEL: define ptr @PR194733() {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br i1 false, label %[[THEN:.*]], label %[[ELSE:.*]]
+; CHECK:       [[THEN]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = load ptr, ptr @slot, align 8
+; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr @buf, ptr @buf, i64 0, i1 false)
+; CHECK-NEXT:    ret ptr null
+; CHECK:       [[ELSE]]:
+; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr @slot, align 8
+; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr @buf, ptr @buf, i64 0, i1 true)
+; CHECK-NEXT:    [[TMP2:%.*]] = load ptr, ptr @slot, align 8
+; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr @buf, ptr @buf, i64 0, i1 false)
+; CHECK-NEXT:    ret ptr null
+;
 entry:
   br i1 false, label %then, label %else
 
 then:
-  %0 = load ptr, ptr null, align 8
-  call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 false)
+  %0 = load ptr, ptr @slot, align 8
+  call void @llvm.memcpy.p0.p0.i64(ptr @buf, ptr @buf, i64 0, i1 false)
   ret ptr null
 
 else:
-  %1 = load ptr, ptr null, align 8
-  call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 true)
-  %2 = load ptr, ptr null, align 8
-  call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 false)
+  %1 = load ptr, ptr @slot, align 8
+  call void @llvm.memcpy.p0.p0.i64(ptr @buf, ptr @buf, i64 0, i1 true)
+  %2 = load ptr, ptr @slot, align 8
+  call void @llvm.memcpy.p0.p0.i64(ptr @buf, ptr @buf, i64 0, i1 false)
   ret ptr null
 }
-; CHECK-LABEL: define ptr @PR194733(
-; CHECK-NOT: outlined_ir_func
-; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 false)
-; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 true)
-; CHECK: call void @llvm.memcpy.p0.p0.i64(ptr null, ptr null, i64 0, i1 false)



More information about the llvm-commits mailing list