[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