[llvm] [IR] Add `alwaysuniform` function attribute (PR #214644)

Reem Elkhouly via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 17:16:07 PDT 2026


https://github.com/amd-relkhoul updated https://github.com/llvm/llvm-project/pull/214644

>From 93825f0299b0435a4e9970b2964f48d9bb891a13 Mon Sep 17 00:00:00 2001
From: Reem Elkhouly <reem.elkhouly at amd.com>
Date: Fri, 7 Aug 2026 13:40:45 +0900
Subject: [PATCH 1/5] [LLVM] AlwaysUniform function attribute

---
 llvm/docs/LangRef.md                        | 5 +++++
 llvm/include/llvm/Bitcode/LLVMBitCodes.h    | 1 +
 llvm/include/llvm/IR/Attributes.td          | 3 +++
 llvm/lib/Analysis/TargetTransformInfo.cpp   | 2 ++
 llvm/lib/Bitcode/Reader/BitcodeReader.cpp   | 2 ++
 llvm/lib/Bitcode/Writer/BitcodeWriter.cpp   | 2 ++
 llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 +
 7 files changed, 16 insertions(+)

diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 1fc6ea1a7ed9d..1c300aa67426e 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -2377,6 +2377,11 @@ define void @f() "no-sse" { ... }
     would normally be considered a source of divergence; setting this attribute
     on a function means that a call to it is not a source of divergence.
 
+`alwaysuniform`
+:   A call to this function is always uniform. In uniformity analysis, a *uniform*
+    value is a value that is the same across all threads in a warp. Setting this
+    attribute on a function means that a call to it always returns a uniform result.
+
 `noduplicate`
 :   This attribute indicates that calls to the function cannot be
     duplicated. A call to a `noduplicate` function may be moved
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 358f9a65a80af..05a6486d910ad 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -826,6 +826,7 @@ enum AttributeKindCodes {
   ATTR_KIND_NOOUTLINE = 107,
   ATTR_KIND_FLATTEN = 108,
   ATTR_KIND_NOIPA = 109,
+  ATTR_KIND_ALWAYS_UNIFORM = 110,
 };
 
 enum ComdatSelectionKindCodes {
diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td
index 4e45100b54d38..ca3f2e7c8d20a 100644
--- a/llvm/include/llvm/IR/Attributes.td
+++ b/llvm/include/llvm/IR/Attributes.td
@@ -194,6 +194,9 @@ def NoCreateUndefOrPoison
 /// Function is not a source of divergence.
 def NoDivergenceSource : EnumAttr<"nodivergencesource", IntersectAnd, [FnAttr]>;
 
+/// Function is always uniform.
+def AlwaysUniform : EnumAttr<"alwaysuniform", IntersectAnd, [FnAttr]>;
+
 /// Call cannot be duplicated.
 def NoDuplicate : EnumAttr<"noduplicate", IntersectPreserve, [FnAttr]>;
 
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index 595c2d10dd118..aed88f248d5c7 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -295,6 +295,8 @@ ValueUniformity
 llvm::TargetTransformInfo::getValueUniformity(const Value *V) const {
   ValueUniformity VU = TTIImpl->getValueUniformity(V);
   if (const auto *Call = dyn_cast<CallBase>(V)) {
+    if (Call->hasFnAttr(Attribute::AlwaysUniform))
+      return ValueUniformity::AlwaysUniform;
     if (VU == ValueUniformity::NeverUniform &&
         Call->hasFnAttr(Attribute::NoDivergenceSource))
       return ValueUniformity::Default;
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index ac61ede6395af..7f8c07078d6ea 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2172,6 +2172,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) {
     return Attribute::NoCallback;
   case bitc::ATTR_KIND_NO_DIVERGENCE_SOURCE:
     return Attribute::NoDivergenceSource;
+  case bitc::ATTR_KIND_ALWAYS_UNIFORM:
+    return Attribute::AlwaysUniform;
   case bitc::ATTR_KIND_NO_DUPLICATE:
     return Attribute::NoDuplicate;
   case bitc::ATTR_KIND_NOFREE:
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 571336c217797..07cbf8884ef1d 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -862,6 +862,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) {
     return bitc::ATTR_KIND_NO_CALLBACK;
   case Attribute::NoDivergenceSource:
     return bitc::ATTR_KIND_NO_DIVERGENCE_SOURCE;
+  case Attribute::AlwaysUniform:
+    return bitc::ATTR_KIND_ALWAYS_UNIFORM;
   case Attribute::NoDuplicate:
     return bitc::ATTR_KIND_NO_DUPLICATE;
   case Attribute::NoFree:
diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
index db1676838854b..f3e13e77b8381 100644
--- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp
+++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp
@@ -964,6 +964,7 @@ Function *CodeExtractor::constructFunctionDeclaration(
       case Attribute::CoroDestroyOnlyWhenComplete:
       case Attribute::CoroElideSafe:
       case Attribute::NoDivergenceSource:
+      case Attribute::AlwaysUniform:
       case Attribute::NoCreateUndefOrPoison:
         continue;
       // Those attributes should be safe to propagate to the extracted function.

>From 6fb894626fac7f8afb3045403b37332cb9ce467a Mon Sep 17 00:00:00 2001
From: Reem Elkhouly <reem.elkhouly at amd.com>
Date: Fri, 7 Aug 2026 14:41:02 +0900
Subject: [PATCH 2/5] Add test alwaysuniform function attribute

---
 .../AMDGPU/alwaysuniform_function_attribute.ll   | 16 ++++++++++++++++
 llvm/test/Bitcode/attributes.ll                  |  6 ++++++
 2 files changed, 22 insertions(+)
 create mode 100644 llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll

diff --git a/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll b/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll
new file mode 100644
index 0000000000000..663e12e88a15b
--- /dev/null
+++ b/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll
@@ -0,0 +1,16 @@
+; RUN: opt -mtriple amdgcn-- -passes='print<uniformity>' -disable-output %s 2>&1 | FileCheck %s
+
+; CHECK: DIVERGENT: %divergentval
+; CHECK-NOT: DIVERGENT: %uniformval
+; CHECK: %uniformval
+define void @test() {
+  %divergentval = call i32 @normalfunc()
+  %uniformval = call i32 @alwaysuniformfunc()
+  ret void
+}
+
+declare i32 @normalfunc() #0
+declare i32 @alwaysuniformfunc() #1
+
+attributes #0 = { nounwind }
+attributes #1 = { alwaysuniform nounwind }
\ No newline at end of file
diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll
index f696f2dd12323..8b28b6bd0225b 100644
--- a/llvm/test/Bitcode/attributes.ll
+++ b/llvm/test/Bitcode/attributes.ll
@@ -557,6 +557,11 @@ define void @f94() nodivergencesource {
   ret void;
 }
 
+; CHECK: define void @f95() [[ALWAYSUNIFORM:#[0-9]+]]
+define void @f95() alwaysuniform {
+  ret void;
+}
+
 ; CHECK: define range(i32 -1, 42) i32 @range_attribute(<4 x i32> range(i32 -1, 42) %a)
 define range(i32 -1, 42) i32 @range_attribute(<4 x i32> range(i32 -1, 42) %a) {
   ret i32 0
@@ -659,5 +664,6 @@ define void @noipa() noipa {
 ; CHECK: attributes [[SKIPPROFILE]] = { skipprofile }
 ; CHECK: attributes [[OPTDEBUG]] = { optdebug }
 ; CHECK: attributes [[NODIVERGENCESOURCE]] = { nodivergencesource }
+; CHECK: attributes [[ALWAYSUNIFORM]] = { alwaysuniform }
 ; CHECK: attributes [[NOIPA]] = { noipa }
 ; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin }

>From 8172e6f38776dd2d64e30cb598788174debf08f6 Mon Sep 17 00:00:00 2001
From: Reem Elkhouly <reem.elkhouly at amd.com>
Date: Wed, 12 Aug 2026 10:20:36 +0900
Subject: [PATCH 3/5] Use general term and fix EOF

---
 llvm/docs/LangRef.md                                            | 2 +-
 .../AMDGPU/alwaysuniform_function_attribute.ll                  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 1c300aa67426e..0b0af571e1562 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -2379,7 +2379,7 @@ define void @f() "no-sse" { ... }
 
 `alwaysuniform`
 :   A call to this function is always uniform. In uniformity analysis, a *uniform*
-    value is a value that is the same across all threads in a warp. Setting this
+    value is a value that is the same across all threads in a subgroup. Setting this
     attribute on a function means that a call to it always returns a uniform result.
 
 `noduplicate`
diff --git a/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll b/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll
index 663e12e88a15b..5b6b1d8f948ae 100644
--- a/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll
+++ b/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll
@@ -13,4 +13,4 @@ declare i32 @normalfunc() #0
 declare i32 @alwaysuniformfunc() #1
 
 attributes #0 = { nounwind }
-attributes #1 = { alwaysuniform nounwind }
\ No newline at end of file
+attributes #1 = { alwaysuniform nounwind }

>From 5c2be4c37eceed0cd1ed80a00d4aa20c73a28a70 Mon Sep 17 00:00:00 2001
From: Reem Elkhouly <reem.elkhouly at amd.com>
Date: Fri, 14 Aug 2026 17:07:40 +0900
Subject: [PATCH 4/5] Refine the description of alwaysuniform in LangRef

---
 llvm/docs/LangRef.md | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/docs/LangRef.md b/llvm/docs/LangRef.md
index 0b0af571e1562..bef006e9cbf12 100644
--- a/llvm/docs/LangRef.md
+++ b/llvm/docs/LangRef.md
@@ -2378,9 +2378,9 @@ define void @f() "no-sse" { ... }
     on a function means that a call to it is not a source of divergence.
 
 `alwaysuniform`
-:   A call to this function is always uniform. In uniformity analysis, a *uniform*
-    value is a value that is the same across all threads in a subgroup. Setting this
-    attribute on a function means that a call to it always returns a uniform result.
+:   Setting this attribute on a function means that a call to it always returns
+    a uniform result regardless of the uniformity of the inputs. Even when given
+    inputs that are divergent, the call is guaranteed to return a uniform result.
 
 `noduplicate`
 :   This attribute indicates that calls to the function cannot be

>From 62577ad49365a2ef62790665ee808b8bacde0f00 Mon Sep 17 00:00:00 2001
From: Reem Elkhouly <relkhoul at amd.com>
Date: Wed, 19 Aug 2026 09:15:56 +0900
Subject: [PATCH 5/5] Fix RUN line and inline attributes

Co-authored-by: Jay Foad <jay.foad at gmail.com>
Co-authored-by: Matt Arsenault <arsenm2 at gmail.com>
---
 .../AMDGPU/alwaysuniform_function_attribute.ll           | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll b/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll
index 5b6b1d8f948ae..ede6960684a89 100644
--- a/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll
+++ b/llvm/test/Analysis/UniformityAnalysis/AMDGPU/alwaysuniform_function_attribute.ll
@@ -1,4 +1,4 @@
-; RUN: opt -mtriple amdgcn-- -passes='print<uniformity>' -disable-output %s 2>&1 | FileCheck %s
+; RUN: opt -mtriple=amdgpu-- -passes='print<uniformity>' -disable-output %s 2>&1 | FileCheck %s
 
 ; CHECK: DIVERGENT: %divergentval
 ; CHECK-NOT: DIVERGENT: %uniformval
@@ -9,8 +9,5 @@ define void @test() {
   ret void
 }
 
-declare i32 @normalfunc() #0
-declare i32 @alwaysuniformfunc() #1
-
-attributes #0 = { nounwind }
-attributes #1 = { alwaysuniform nounwind }
+declare i32 @normalfunc() nounwind
+declare i32 @alwaysuniformfunc() alwaysuniform nounwind



More information about the llvm-commits mailing list