diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 5262f0b99a68dab..b956e7ca209aec5 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -2082,6 +2082,12 @@ 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. ``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 ba2efee9414218f..41d1dc4c2244778 100644 --- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -767,6 +767,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 d05a6ca92aaba01..b6d36a5f7ae4fb3 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/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp index 8ab8a53b7531129..a6c9b6111cab119 100644 --- a/llvm/lib/Analysis/TargetTransformInfo.cpp +++ b/llvm/lib/Analysis/TargetTransformInfo.cpp @@ -292,6 +292,10 @@ bool TargetTransformInfo::hasBranchDivergence(const Function *F) const { } bool TargetTransformInfo::isSourceOfDivergence(const Value *V) const { + if (const auto *Call = dyn_cast(V)) { + if (Call->hasFnAttr(Attribute::NoDivergenceSource)) + return false; + } return TTIImpl->isSourceOfDivergence(V); } diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 8ee93253bc24471..a8b5f96d850b558 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2066,6 +2066,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 bec0caef58afa80..c3bd107954c64a8 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -763,6 +763,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 a090c5ed7492056..15b26a38cc28ef2 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 000000000000000..9c893ac3ba76a0c --- /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 a66eda19ff57357..737f49aa86a7ba2 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 }