Skip to content

Commit 0ed8b27

Browse files
authored
llvm-reduce: Avoid removing convergent with convergence tokens (#132946)
Check if the intrinsics are declared in the module as an overly conservative fix. Fixes #132695
1 parent bed2bdf commit 0ed8b27

File tree

3 files changed

+114
-2
lines changed

3 files changed

+114
-2
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=attributes --test FileCheck --test-arg --check-prefix=INTERESTING --test-arg %s --test-arg --input-file %s -o %t
2+
; RUN: FileCheck --check-prefixes=RESULT %s < %t
3+
4+
; Test that convergent attributes are reduced if convergencectrl
5+
; bundles are not used
6+
7+
; INTERESTING-LABEL: define float @convergent_intrinsic(
8+
; RESULT-LABEL: define float @convergent_intrinsic(float %x, float %y) {
9+
define float @convergent_intrinsic(float %x, float %y) #0 {
10+
%val = call float @llvm.amdgcn.readfirstlane.f32(float %x)
11+
ret float %val
12+
}
13+
14+
; INTERESTING-LABEL: define float @convergent_func_no_convergent_intrinsics(
15+
; RESULT-LABEL: define float @convergent_func_no_convergent_intrinsics(float %x, float %y) {
16+
define float @convergent_func_no_convergent_intrinsics(float %x, float %y) #0 {
17+
%val = call float @extern.func(float %x, float %y)
18+
ret float %val
19+
}
20+
21+
22+
; RESULT-LABEL: declare float @convergent.extern.func(float, float){{$}}
23+
declare float @convergent.extern.func(float, float) #0
24+
declare float @extern.func(float, float)
25+
declare float @llvm.amdgcn.readfirstlane.f32(float) #1
26+
27+
; RESULT: attributes #0 = { convergent nocallback nofree nounwind willreturn memory(none) }
28+
; RESULT-NOT: attributes
29+
30+
attributes #0 = { convergent nounwind }
31+
attributes #1 = { convergent nocallback nofree nounwind willreturn memory(none) }
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=attributes --test FileCheck --test-arg %s --test-arg --input-file %s -o %t
2+
; RUN: FileCheck --check-prefixes=CHECK,RESULT %s < %t
3+
4+
; Test that invalid reductions aren't produced on convergent functions
5+
; which use convergencectrl bundles
6+
7+
; CHECK-LABEL: define float @convergent_intrinsic(float %x, float %y)
8+
; RESULT-SAME: [[CONVERGENT_ONLY:#[0-9]+]] {
9+
define float @convergent_intrinsic(float %x, float %y) #0 {
10+
%entry.token = call token @llvm.experimental.convergence.entry()
11+
%val = call float @llvm.amdgcn.readfirstlane.f32(float %x) [ "convergencectrl"(token %entry.token) ]
12+
ret float %val
13+
}
14+
15+
; CHECK-LABEL: define float @convergent_callsite(float %x, float %y)
16+
; RESULT-SAME: [[CONVERGENT_ONLY]] {
17+
; RESULT: call float @extern.func(float %x, float %y) [[CONVERGENT_ONLY]]
18+
define float @convergent_callsite(float %x, float %y) #0 {
19+
%entry.token = call token @llvm.experimental.convergence.entry()
20+
%val = call float @extern.func(float %x, float %y) #0 [ "convergencectrl"(token %entry.token) ]
21+
ret float %val
22+
}
23+
24+
; CHECK-LABEL: define float @convergent_declaration(float %x, float %y)
25+
; RESULT-SAME: [[CONVERGENT_ONLY]] {
26+
define float @convergent_declaration(float %x, float %y) #0 {
27+
%entry.token = call token @llvm.experimental.convergence.entry()
28+
%val = call float @convergent.extern.func(float %x, float %y) [ "convergencectrl"(token %entry.token) ]
29+
ret float %val
30+
}
31+
32+
; CHECK-LABEL: define float @convergent_func_no_convergent_intrinsics(float %x, float %y)
33+
; RESULT-SAME: [[CONVERGENT_ONLY]] {
34+
define float @convergent_func_no_convergent_intrinsics(float %x, float %y) #0 {
35+
%val = call float @extern.func(float %x, float %y)
36+
ret float %val
37+
}
38+
39+
; CHECK-LABEL: define float @convergent_func_no_convergent_bundles(float %x, float %y)
40+
; RESULT-SAME: [[CONVERGENT_ONLY]] {
41+
define float @convergent_func_no_convergent_bundles(float %x, float %y) #0 {
42+
%entry.token = call token @llvm.experimental.convergence.entry()
43+
%val = call float @extern.func(float %x, float %y)
44+
ret float %val
45+
}
46+
47+
; CHECK-LABEL: declare float @convergent.extern.func(float, float)
48+
; RESULT-SAME: [[CONVERGENT_ONLY]]{{$}}
49+
declare float @convergent.extern.func(float, float) #0
50+
declare float @extern.func(float, float)
51+
declare float @llvm.amdgcn.readfirstlane.f32(float) #1
52+
declare token @llvm.experimental.convergence.entry() #2
53+
54+
; RESULT: attributes [[CONVERGENT_ONLY]] = { convergent }
55+
56+
attributes #0 = { convergent nounwind }
57+
attributes #1 = { convergent nocallback nofree nounwind willreturn memory(none) }
58+
attributes #2 = { convergent nocallback nofree nosync nounwind willreturn memory(none) }

llvm/tools/llvm-reduce/deltas/ReduceAttributes.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,25 @@ namespace {
4444
class AttributeRemapper : public InstVisitor<AttributeRemapper> {
4545
Oracle &O;
4646
LLVMContext &Context;
47+
bool HasControlledConvergence = true;
4748

4849
public:
49-
AttributeRemapper(Oracle &O, LLVMContext &C) : O(O), Context(C) {}
50+
AttributeRemapper(Oracle &O, Module &M) : O(O), Context(M.getContext()) {
51+
52+
// Check if there are any convergence intrinsics used. We cannot remove the
53+
// convergent attribute if a function uses convergencectrl bundles. As a
54+
// simple filter, check if any of the intrinsics are used in the module.
55+
//
56+
// TODO: This could be done per-function. We should be eliminating
57+
// convergent if there are no convergent token uses in a function.
58+
HasControlledConvergence = any_of(
59+
ArrayRef<Intrinsic::ID>{Intrinsic::experimental_convergence_anchor,
60+
Intrinsic::experimental_convergence_entry,
61+
Intrinsic::experimental_convergence_loop},
62+
[&M](Intrinsic::ID ID) {
63+
return Intrinsic::getDeclarationIfExists(&M, ID);
64+
});
65+
}
5066

5167
void visitModule(Module &M) {
5268
for (GlobalVariable &GV : M.globals())
@@ -132,6 +148,13 @@ class AttributeRemapper : public InstVisitor<AttributeRemapper> {
132148
AttrsToPreserve.addAttribute(A);
133149
continue;
134150
}
151+
152+
// TODO: Could only remove this if there are no convergence tokens in
153+
// the function.
154+
if (Kind == Attribute::Convergent && HasControlledConvergence) {
155+
AttrsToPreserve.addAttribute(A);
156+
continue;
157+
}
135158
}
136159

137160
if (O.shouldKeep())
@@ -144,7 +167,7 @@ class AttributeRemapper : public InstVisitor<AttributeRemapper> {
144167

145168
/// Removes out-of-chunk attributes from module.
146169
static void extractAttributesFromModule(Oracle &O, ReducerWorkItem &WorkItem) {
147-
AttributeRemapper R(O, WorkItem.getContext());
170+
AttributeRemapper R(O, WorkItem.getModule());
148171
R.visit(WorkItem.getModule());
149172
}
150173

0 commit comments

Comments
 (0)