From 3bb577263d38831e579d8b114ed599ab799ae2ab Mon Sep 17 00:00:00 2001 From: Tim Renouf Date: Wed, 9 Oct 2024 18:48:50 +0100 Subject: [PATCH 1/6] [LLVM] New NoDivergenceSource function attribute A call to a function that has this attribute is not a source of divergence, as used by UniformityAnalysis. That allows a front-end to use known-name calls as an instruction extension mechanism (e.g. https://github.com/GPUOpen-Drivers/llvm-dialects ) without such a call being a source of divergence. --- llvm/docs/LangRef.rst | 10 ++++++++++ llvm/include/llvm/Bitcode/LLVMBitCodes.h | 1 + llvm/include/llvm/IR/Attributes.td | 3 +++ llvm/lib/Analysis/UniformityAnalysis.cpp | 9 ++++++++- llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 2 ++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 2 ++ llvm/lib/Transforms/Utils/CodeExtractor.cpp | 1 + .../AMDGPU/nodivergencesource.ll | 16 ++++++++++++++++ llvm/test/Bitcode/attributes.ll | 6 ++++++ 9 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Analysis/UniformityAnalysis/AMDGPU/nodivergencesource.ll diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 0c7279de06cd6..4c94ffbc1d737 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2082,6 +2082,16 @@ example: function call, use of ``longjmp``, or other means. It is a compiler hint that is used at module level to improve dataflow analysis, dropped during linking, and has no effect on functions defined in the current module. +``nodivergencesource`` + A call to this function is not a source of divergence. In uniformity + analysis, a *source of divergence* is an instruction that generates + divergence even if its inputs are uniform. A call with no further information + 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. + + This is useful where known-name calls are being used as an extension + mechanism for instructions, as for example in `llvm-dialects + `. ``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 cbd92fd52fc75..a6959d9b62742 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -764,6 +764,7 @@ enum AttributeKindCodes { ATTR_KIND_SANITIZE_REALTIME_UNSAFE = 97, ATTR_KIND_CORO_ELIDE_SAFE = 98, ATTR_KIND_NO_EXT = 99, + ATTR_KIND_NO_DIVERGENCE_SOURCE = 100, }; enum ComdatSelectionKindCodes { diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index d05a6ca92aaba..b6d36a5f7ae4f 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -183,6 +183,9 @@ def NoCallback : EnumAttr<"nocallback", IntersectAnd, [FnAttr]>; /// Function creates no aliases of pointer. def NoCapture : EnumAttr<"nocapture", IntersectAnd, [ParamAttr]>; +/// Function is not a source of divergence. +def NoDivergenceSource : EnumAttr<"nodivergencesource", IntersectAnd, [FnAttr]>; + /// Call cannot be duplicated. def NoDuplicate : EnumAttr<"noduplicate", IntersectPreserve, [FnAttr]>; diff --git a/llvm/lib/Analysis/UniformityAnalysis.cpp b/llvm/lib/Analysis/UniformityAnalysis.cpp index 2d617db431c58..b0be6379a1512 100644 --- a/llvm/lib/Analysis/UniformityAnalysis.cpp +++ b/llvm/lib/Analysis/UniformityAnalysis.cpp @@ -32,7 +32,14 @@ bool llvm::GenericUniformityAnalysisImpl::markDefsDivergent( template <> void llvm::GenericUniformityAnalysisImpl::initialize() { for (auto &I : instructions(F)) { - if (TTI->isSourceOfDivergence(&I)) + bool NoDivergenceSource = false; + if (auto Call = dyn_cast(&I)) { + if (Function *Callee = Call->getCalledFunction()) { + if (Callee->hasFnAttribute(Attribute::NoDivergenceSource)) + NoDivergenceSource = true; + } + } + if (!NoDivergenceSource && TTI->isSourceOfDivergence(&I)) markDivergent(I); else if (TTI->isAlwaysUniform(&I)) addUniformOverride(I); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 6f997510b0360..b8dc5ecbf7abd 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2048,6 +2048,8 @@ static Attribute::AttrKind getAttrFromCode(uint64_t Code) { return Attribute::NoCallback; case bitc::ATTR_KIND_NO_CAPTURE: return Attribute::NoCapture; + case bitc::ATTR_KIND_NO_DIVERGENCE_SOURCE: + return Attribute::NoDivergenceSource; 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 d9086bfebbd2a..a44b6a8614357 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -761,6 +761,8 @@ static uint64_t getAttrKindEncoding(Attribute::AttrKind Kind) { return bitc::ATTR_KIND_NO_CALLBACK; case Attribute::NoCapture: return bitc::ATTR_KIND_NO_CAPTURE; + case Attribute::NoDivergenceSource: + return bitc::ATTR_KIND_NO_DIVERGENCE_SOURCE; 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 f58448dd9562d..5b42099398f8f 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -917,6 +917,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::NoFPClass: case Attribute::CoroDestroyOnlyWhenComplete: case Attribute::CoroElideSafe: + case Attribute::NoDivergenceSource: continue; // Those attributes should be safe to propagate to the extracted function. case Attribute::AlwaysInline: diff --git a/llvm/test/Analysis/UniformityAnalysis/AMDGPU/nodivergencesource.ll b/llvm/test/Analysis/UniformityAnalysis/AMDGPU/nodivergencesource.ll new file mode 100644 index 0000000000000..9c893ac3ba76a --- /dev/null +++ b/llvm/test/Analysis/UniformityAnalysis/AMDGPU/nodivergencesource.ll @@ -0,0 +1,16 @@ +; RUN: opt -mtriple amdgcn-- -passes='print' -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 @nodivergencesourcefunc() + ret void +} + +declare i32 @normalfunc() #0 +declare i32 @nodivergencesourcefunc() #1 + +attributes #0 = { nounwind } +attributes #1 = { nounwind nodivergencesource } diff --git a/llvm/test/Bitcode/attributes.ll b/llvm/test/Bitcode/attributes.ll index a66eda19ff573..737f49aa86a7b 100644 --- a/llvm/test/Bitcode/attributes.ll +++ b/llvm/test/Bitcode/attributes.ll @@ -537,6 +537,11 @@ define void @f91(ptr dead_on_unwind %p) { ret void } +; CHECK: define void @f94() [[NODIVERGENCESOURCE:#[0-9]+]] +define void @f94() nodivergencesource { + 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 @@ -615,4 +620,5 @@ define void @initializes(ptr initializes((-4, 0), (4, 8)) %a) { ; CHECK: attributes [[FNRETTHUNKEXTERN]] = { fn_ret_thunk_extern } ; CHECK: attributes [[SKIPPROFILE]] = { skipprofile } ; CHECK: attributes [[OPTDEBUG]] = { optdebug } +; CHECK: attributes [[NODIVERGENCESOURCE]] = { nodivergencesource } ; CHECK: attributes #[[NOBUILTIN]] = { nobuiltin } From e1905675f2e6b4c7723936b93ce85433b69f260d Mon Sep 17 00:00:00 2001 From: Tim Renouf Date: Thu, 10 Oct 2024 16:02:40 +0100 Subject: [PATCH 2/6] Use CallBase::hasFnAttr --- llvm/lib/Analysis/UniformityAnalysis.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Analysis/UniformityAnalysis.cpp b/llvm/lib/Analysis/UniformityAnalysis.cpp index b0be6379a1512..3675b22057fa8 100644 --- a/llvm/lib/Analysis/UniformityAnalysis.cpp +++ b/llvm/lib/Analysis/UniformityAnalysis.cpp @@ -33,12 +33,8 @@ bool llvm::GenericUniformityAnalysisImpl::markDefsDivergent( template <> void llvm::GenericUniformityAnalysisImpl::initialize() { for (auto &I : instructions(F)) { bool NoDivergenceSource = false; - if (auto Call = dyn_cast(&I)) { - if (Function *Callee = Call->getCalledFunction()) { - if (Callee->hasFnAttribute(Attribute::NoDivergenceSource)) - NoDivergenceSource = true; - } - } + if (auto Call = dyn_cast(&I)) + NoDivergenceSource = Call->hasFnAttr(Attribute::NoDivergenceSource); if (!NoDivergenceSource && TTI->isSourceOfDivergence(&I)) markDivergent(I); else if (TTI->isAlwaysUniform(&I)) From 795bbbaf25315437ad5ea2f775bbcc2d6db56cf6 Mon Sep 17 00:00:00 2001 From: Tim Renouf Date: Fri, 11 Oct 2024 14:56:58 +0100 Subject: [PATCH 3/6] Move check to TargetTransformInfo --- llvm/lib/Analysis/TargetTransformInfo.cpp | 4 ++++ llvm/lib/Analysis/UniformityAnalysis.cpp | 5 +---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp index 3dc29fc7cd77b..fd6627577d7f2 100644 --- a/llvm/lib/Analysis/TargetTransformInfo.cpp +++ b/llvm/lib/Analysis/TargetTransformInfo.cpp @@ -288,6 +288,10 @@ bool TargetTransformInfo::hasBranchDivergence(const Function *F) const { } bool TargetTransformInfo::isSourceOfDivergence(const Value *V) const { + if (auto Call = dyn_cast(V)) { + if (Call->hasFnAttr(Attribute::NoDivergenceSource)) + return false; + } return TTIImpl->isSourceOfDivergence(V); } diff --git a/llvm/lib/Analysis/UniformityAnalysis.cpp b/llvm/lib/Analysis/UniformityAnalysis.cpp index 3675b22057fa8..2d617db431c58 100644 --- a/llvm/lib/Analysis/UniformityAnalysis.cpp +++ b/llvm/lib/Analysis/UniformityAnalysis.cpp @@ -32,10 +32,7 @@ bool llvm::GenericUniformityAnalysisImpl::markDefsDivergent( template <> void llvm::GenericUniformityAnalysisImpl::initialize() { for (auto &I : instructions(F)) { - bool NoDivergenceSource = false; - if (auto Call = dyn_cast(&I)) - NoDivergenceSource = Call->hasFnAttr(Attribute::NoDivergenceSource); - if (!NoDivergenceSource && TTI->isSourceOfDivergence(&I)) + if (TTI->isSourceOfDivergence(&I)) markDivergent(I); else if (TTI->isAlwaysUniform(&I)) addUniformOverride(I); From c578054ab5f2a6bbdf619c76a79f5386c347235a Mon Sep 17 00:00:00 2001 From: Tim Renouf Date: Fri, 11 Oct 2024 17:09:49 +0100 Subject: [PATCH 4/6] Remove last para. Un-auto a variable. --- llvm/docs/LangRef.rst | 4 ---- llvm/lib/Analysis/TargetTransformInfo.cpp | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 4c94ffbc1d737..506115aa9370b 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2088,10 +2088,6 @@ example: divergence even if its inputs are uniform. A call with no further information 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. - - This is useful where known-name calls are being used as an extension - mechanism for instructions, as for example in `llvm-dialects - `. ``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/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp index fd6627577d7f2..2b597e77703f7 100644 --- a/llvm/lib/Analysis/TargetTransformInfo.cpp +++ b/llvm/lib/Analysis/TargetTransformInfo.cpp @@ -288,7 +288,7 @@ bool TargetTransformInfo::hasBranchDivergence(const Function *F) const { } bool TargetTransformInfo::isSourceOfDivergence(const Value *V) const { - if (auto Call = dyn_cast(V)) { + if (const CallBase *Call = dyn_cast(V)) { if (Call->hasFnAttr(Attribute::NoDivergenceSource)) return false; } From 7cd27b81b39e93ed45c6788113f5912e34bb68a2 Mon Sep 17 00:00:00 2001 From: Tim Renouf Date: Fri, 11 Oct 2024 18:44:59 +0100 Subject: [PATCH 5/6] Reinstate auto but with *, as recommended in review --- llvm/lib/Analysis/TargetTransformInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp index 65fc639feadd0..2b7bb626f6c07 100644 --- a/llvm/lib/Analysis/TargetTransformInfo.cpp +++ b/llvm/lib/Analysis/TargetTransformInfo.cpp @@ -292,7 +292,7 @@ bool TargetTransformInfo::hasBranchDivergence(const Function *F) const { } bool TargetTransformInfo::isSourceOfDivergence(const Value *V) const { - if (const CallBase *Call = dyn_cast(V)) { + if (auto *Call = dyn_cast(V)) { if (Call->hasFnAttr(Attribute::NoDivergenceSource)) return false; } From a27951a2127a9eca84c2e9920b343034813074f3 Mon Sep 17 00:00:00 2001 From: Tim Renouf Date: Fri, 11 Oct 2024 18:55:08 +0100 Subject: [PATCH 6/6] const --- llvm/lib/Analysis/TargetTransformInfo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp index 2b7bb626f6c07..a6c9b6111cab1 100644 --- a/llvm/lib/Analysis/TargetTransformInfo.cpp +++ b/llvm/lib/Analysis/TargetTransformInfo.cpp @@ -292,7 +292,7 @@ bool TargetTransformInfo::hasBranchDivergence(const Function *F) const { } bool TargetTransformInfo::isSourceOfDivergence(const Value *V) const { - if (auto *Call = dyn_cast(V)) { + if (const auto *Call = dyn_cast(V)) { if (Call->hasFnAttr(Attribute::NoDivergenceSource)) return false; }