1- ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature -- check-attributes --check-globals
2- ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
3- ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
1+ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals all --version 5
2+ ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S %s | FileCheck %s --check-prefixes=CHECK,TUNIT
3+ ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S %s | FileCheck %s --check-prefixes=CHECK,CGSCC
44
55define i32 @defined () convergent {
66; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
7- ; CHECK-LABEL: define {{[^@]+}}@ defined
8- ; CHECK-SAME: ( ) #[[ATTR0:[0-9]+]] {
7+ ; CHECK-LABEL: define noundef i32 @ defined(
8+ ; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
99; CHECK-NEXT: ret i32 1
1010;
1111 ret i32 1
1212}
1313
1414define i32 @calls_defined () convergent {
1515; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
16- ; TUNIT-LABEL: define {{[^@]+}}@ calls_defined
17- ; TUNIT-SAME: ( ) #[[ATTR0]] {
16+ ; TUNIT-LABEL: define noundef i32 @ calls_defined(
17+ ; TUNIT-SAME: ) #[[ATTR0]] {
1818; TUNIT-NEXT: ret i32 1
1919;
2020; CGSCC: Function Attrs: convergent mustprogress nofree nosync nounwind willreturn memory(none)
21- ; CGSCC-LABEL: define {{[^@]+}}@ calls_defined
22- ; CGSCC-SAME: ( ) #[[ATTR1:[0-9]+]] {
23- ; CGSCC-NEXT: [[A:%.*]] = call noundef i32 @defined() #[[ATTR6 :[0-9]+]]
21+ ; CGSCC-LABEL: define noundef i32 @ calls_defined(
22+ ; CGSCC-SAME: ) #[[ATTR1:[0-9]+]] {
23+ ; CGSCC-NEXT: [[A:%.*]] = call noundef i32 @defined() #[[ATTR7 :[0-9]+]]
2424; CGSCC-NEXT: ret i32 [[A]]
2525;
2626 %a = call i32 @defined ()
@@ -30,7 +30,7 @@ define i32 @calls_defined() convergent {
3030declare void @declared_non_convergent ()
3131
3232define void @calls_declared_non_convergent () convergent {
33- ; CHECK-LABEL: define {{[^@]+}} @calls_declared_non_convergent() {
33+ ; CHECK-LABEL: define void @calls_declared_non_convergent() {
3434; CHECK-NEXT: call void @declared_non_convergent()
3535; CHECK-NEXT: ret void
3636;
@@ -43,24 +43,135 @@ declare i32 @declared_convergent() convergent
4343
4444define i32 @calls_declared_convergent () convergent {
4545; TUNIT: Function Attrs: convergent
46- ; TUNIT-LABEL: define {{[^@]+}}@ calls_declared_convergent
47- ; TUNIT-SAME: ( ) #[[ATTR1:[0-9]+]] {
46+ ; TUNIT-LABEL: define i32 @ calls_declared_convergent(
47+ ; TUNIT-SAME: ) #[[ATTR1:[0-9]+]] {
4848; TUNIT-NEXT: [[A:%.*]] = call i32 @declared_convergent()
4949; TUNIT-NEXT: ret i32 [[A]]
5050;
5151; CGSCC: Function Attrs: convergent
52- ; CGSCC-LABEL: define {{[^@]+}}@ calls_declared_convergent
53- ; CGSCC-SAME: ( ) #[[ATTR2:[0-9]+]] {
52+ ; CGSCC-LABEL: define i32 @ calls_declared_convergent(
53+ ; CGSCC-SAME: ) #[[ATTR2:[0-9]+]] {
5454; CGSCC-NEXT: [[A:%.*]] = call i32 @declared_convergent()
5555; CGSCC-NEXT: ret i32 [[A]]
5656;
5757 %a = call i32 @declared_convergent ()
5858 ret i32 %a
5959}
6060
61+ ; Function declared convergent. Body not provided to prevent inlining
62+ ; of the functions below.
63+ declare i32 @direct_call_convergent_attribute_with_token_declared (i32 %a )
64+
65+ ; This function could be declared non-convergent as it only calls
66+ ; non-convergent functions, but it is being called with a convergence token,
67+ ; hence it is not allowed to drop the convergence attribute.
68+ define i32 @direct_call_convergent_attribute_with_token_inner (i32 %a ) convergent {
69+ ; TUNIT: Function Attrs: convergent
70+ ; TUNIT-LABEL: define i32 @direct_call_convergent_attribute_with_token_inner(
71+ ; TUNIT-SAME: i32 [[A:%.*]]) #[[ATTR1]] {
72+ ; TUNIT-NEXT: [[RS:%.*]] = call i32 @direct_call_convergent_attribute_with_token_declared(i32 [[A]])
73+ ; TUNIT-NEXT: ret i32 [[RS]]
74+ ;
75+ ; CGSCC: Function Attrs: convergent
76+ ; CGSCC-LABEL: define i32 @direct_call_convergent_attribute_with_token_inner(
77+ ; CGSCC-SAME: i32 [[A:%.*]]) #[[ATTR2]] {
78+ ; CGSCC-NEXT: [[RS:%.*]] = call i32 @direct_call_convergent_attribute_with_token_declared(i32 [[A]])
79+ ; CGSCC-NEXT: ret i32 [[RS]]
80+ ;
81+ %rs = call i32 @direct_call_convergent_attribute_with_token_declared (i32 %a )
82+ ret i32 %rs
83+ }
84+
85+ define i32 @direct_call_convergent_attribute_with_token (i32 %a ) convergent {
86+ ; TUNIT: Function Attrs: convergent
87+ ; TUNIT-LABEL: define i32 @direct_call_convergent_attribute_with_token(
88+ ; TUNIT-SAME: i32 [[A:%.*]]) #[[ATTR1]] {
89+ ; TUNIT-NEXT: [[TK:%.*]] = call token @llvm.experimental.convergence.entry() #[[ATTR6:[0-9]+]]
90+ ; TUNIT-NEXT: [[RS:%.*]] = call i32 @direct_call_convergent_attribute_with_token_inner(i32 [[A]]) [ "convergencectrl"(token [[TK]]) ]
91+ ; TUNIT-NEXT: ret i32 [[RS]]
92+ ;
93+ ; CGSCC: Function Attrs: convergent
94+ ; CGSCC-LABEL: define i32 @direct_call_convergent_attribute_with_token(
95+ ; CGSCC-SAME: i32 [[A:%.*]]) #[[ATTR2]] {
96+ ; CGSCC-NEXT: [[TK:%.*]] = call token @llvm.experimental.convergence.entry() #[[ATTR8:[0-9]+]]
97+ ; CGSCC-NEXT: [[RS:%.*]] = call i32 @direct_call_convergent_attribute_with_token_inner(i32 [[A]]) [ "convergencectrl"(token [[TK]]) ]
98+ ; CGSCC-NEXT: ret i32 [[RS]]
99+ ;
100+ %tk = call token @llvm.experimental.convergence.entry ()
101+ %rs = call i32 @direct_call_convergent_attribute_with_token_inner (i32 %a ) [ "convergencectrl" (token %tk ) ]
102+ ret i32 %rs
103+ }
104+
105+ ; Function declared non-convergent.
106+ declare i32 @indirect_call_declared (i32 %a )
107+
108+ ; Function declared convergent, but which is not required to be
109+ ; marked convergent: the only used is through a call which is marked
110+ ; as convergent, hence the function attribute can be dropped.
111+ define i32 @indirect_call_inner (i32 %a ) convergent {
112+ ; CHECK-LABEL: define i32 @indirect_call_inner(
113+ ; CHECK-SAME: i32 [[A:%.*]]) {
114+ ; CHECK-NEXT: [[RS:%.*]] = call i32 @indirect_call_declared(i32 [[A]])
115+ ; CHECK-NEXT: ret i32 [[RS]]
116+ ;
117+ %rs = call i32 @indirect_call_declared (i32 %a )
118+ ret i32 %rs
119+ }
120+
121+ ; Convergent function, calling a function and marking the call as convergent.
122+ define i32 @indirect_call (i32 %a ) convergent {
123+ ; TUNIT: Function Attrs: convergent
124+ ; TUNIT-LABEL: define i32 @indirect_call(
125+ ; TUNIT-SAME: i32 [[A:%.*]]) #[[ATTR1]] {
126+ ; TUNIT-NEXT: [[TK:%.*]] = call token @llvm.experimental.convergence.entry() #[[ATTR7:[0-9]+]]
127+ ; TUNIT-NEXT: [[RS:%.*]] = call i32 @indirect_call_inner(i32 [[A]]) #[[ATTR1]] [ "convergencectrl"(token [[TK]]) ]
128+ ; TUNIT-NEXT: ret i32 [[RS]]
129+ ;
130+ ; CGSCC: Function Attrs: convergent
131+ ; CGSCC-LABEL: define i32 @indirect_call(
132+ ; CGSCC-SAME: i32 [[A:%.*]]) #[[ATTR2]] {
133+ ; CGSCC-NEXT: [[TK:%.*]] = call token @llvm.experimental.convergence.entry() #[[ATTR7]]
134+ ; CGSCC-NEXT: [[RS:%.*]] = call i32 @indirect_call_inner(i32 [[A]]) #[[ATTR2]] [ "convergencectrl"(token [[TK]]) ]
135+ ; CGSCC-NEXT: ret i32 [[RS]]
136+ ;
137+ %tk = call token @llvm.experimental.convergence.entry ()
138+ %fptr = alloca ptr
139+ store ptr @indirect_call_inner , ptr %fptr
140+ %ic = load ptr , ptr %fptr
141+ %rs = call i32 %ic (i32 %a ) convergent [ "convergencectrl" (token %tk ) ]
142+ ret i32 %rs
143+ }
144+
145+ ; A non-convergent declaration.
146+ declare i32 @leaf_convergent_indirect_declared (i32 %a )
147+
148+ ; A function calling indirectly a non-convergent function.
149+ define i32 @leaf_convergent_indirect (i32 %a ) convergent {
150+ ; TUNIT: Function Attrs: convergent
151+ ; TUNIT-LABEL: define i32 @leaf_convergent_indirect(
152+ ; TUNIT-SAME: i32 [[A:%.*]]) #[[ATTR1]] {
153+ ; TUNIT-NEXT: [[TK:%.*]] = call token @llvm.experimental.convergence.entry() #[[ATTR7]]
154+ ; TUNIT-NEXT: [[RS:%.*]] = call i32 @leaf_convergent_indirect_declared(i32 [[A]]) #[[ATTR1]] [ "convergencectrl"(token [[TK]]) ]
155+ ; TUNIT-NEXT: ret i32 [[RS]]
156+ ;
157+ ; CGSCC: Function Attrs: convergent
158+ ; CGSCC-LABEL: define i32 @leaf_convergent_indirect(
159+ ; CGSCC-SAME: i32 [[A:%.*]]) #[[ATTR2]] {
160+ ; CGSCC-NEXT: [[TK:%.*]] = call token @llvm.experimental.convergence.entry() #[[ATTR7]]
161+ ; CGSCC-NEXT: [[RS:%.*]] = call i32 @leaf_convergent_indirect_declared(i32 [[A]]) #[[ATTR2]] [ "convergencectrl"(token [[TK]]) ]
162+ ; CGSCC-NEXT: ret i32 [[RS]]
163+ ;
164+ %tk = call token @llvm.experimental.convergence.entry ()
165+ %fptr = alloca ptr
166+ store ptr @leaf_convergent_indirect_declared , ptr %fptr
167+ %ic = load ptr , ptr %fptr
168+ %rs = call i32 %ic (i32 %a ) convergent [ "convergencectrl" (token %tk ) ]
169+ ret i32 %rs
170+ }
171+
61172define i32 @defined_with_asm (i32 %a , i32 %b ) {
62- ; CHECK-LABEL: define {{[^@]+}}@ defined_with_asm
63- ; CHECK-SAME: ( i32 [[A:%.*]], i32 [[B:%.*]]) {
173+ ; CHECK-LABEL: define i32 @ defined_with_asm(
174+ ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
64175; CHECK-NEXT: [[RESULT:%.*]] = add i32 [[A]], [[B]]
65176; CHECK-NEXT: [[ASM_RESULT:%.*]] = call i32 asm sideeffect "addl $1, $0", "=r,r"(i32 [[RESULT]])
66177; CHECK-NEXT: ret i32 [[ASM_RESULT]]
@@ -72,14 +183,14 @@ define i32 @defined_with_asm(i32 %a, i32 %b) {
72183
73184define i32 @calls_defined_with_asm (i32 %a , i32 %b ) convergent {
74185; TUNIT: Function Attrs: convergent
75- ; TUNIT-LABEL: define {{[^@]+}}@ calls_defined_with_asm
76- ; TUNIT-SAME: ( i32 [[A:%.*]], i32 [[B:%.*]]) #[[ATTR1]] {
186+ ; TUNIT-LABEL: define i32 @ calls_defined_with_asm(
187+ ; TUNIT-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) #[[ATTR1]] {
77188; TUNIT-NEXT: [[C:%.*]] = call i32 @defined_with_asm(i32 [[A]], i32 [[B]])
78189; TUNIT-NEXT: ret i32 [[C]]
79190;
80191; CGSCC: Function Attrs: convergent
81- ; CGSCC-LABEL: define {{[^@]+}}@ calls_defined_with_asm
82- ; CGSCC-SAME: ( i32 [[A:%.*]], i32 [[B:%.*]]) #[[ATTR2]] {
192+ ; CGSCC-LABEL: define i32 @ calls_defined_with_asm(
193+ ; CGSCC-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) #[[ATTR2]] {
83194; CGSCC-NEXT: [[C:%.*]] = call i32 @defined_with_asm(i32 [[A]], i32 [[B]])
84195; CGSCC-NEXT: ret i32 [[C]]
85196;
@@ -91,15 +202,15 @@ declare void @llvm.convergent.copy.p0.p0.i64(ptr %dest, ptr %src, i64 %size, i1
91202
92203define void @calls_convergent_intrinsic (ptr %dest , ptr %src , i64 %size ) convergent {
93204; TUNIT: Function Attrs: convergent mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)
94- ; TUNIT-LABEL: define {{[^@]+}}@ calls_convergent_intrinsic
95- ; TUNIT-SAME: ( ptr nofree [[DEST:%.*]], ptr nofree [[SRC:%.*]], i64 [[SIZE:%.*]]) #[[ATTR3:[0-9]+]] {
96- ; TUNIT-NEXT: call void @llvm.convergent.copy.p0.p0.i64(ptr nofree [[DEST]], ptr nofree [[SRC]], i64 [[SIZE]], i1 noundef false) #[[ATTR5:[0-9]+ ]]
205+ ; TUNIT-LABEL: define void @ calls_convergent_intrinsic(
206+ ; TUNIT-SAME: ptr nofree [[DEST:%.*]], ptr nofree [[SRC:%.*]], i64 [[SIZE:%.*]]) #[[ATTR3:[0-9]+]] {
207+ ; TUNIT-NEXT: call void @llvm.convergent.copy.p0.p0.i64(ptr nofree [[DEST]], ptr nofree [[SRC]], i64 [[SIZE]], i1 noundef false) #[[ATTR6 ]]
97208; TUNIT-NEXT: ret void
98209;
99210; CGSCC: Function Attrs: convergent mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite)
100- ; CGSCC-LABEL: define {{[^@]+}}@ calls_convergent_intrinsic
101- ; CGSCC-SAME: ( ptr nofree [[DEST:%.*]], ptr nofree [[SRC:%.*]], i64 [[SIZE:%.*]]) #[[ATTR4:[0-9]+]] {
102- ; CGSCC-NEXT: call void @llvm.convergent.copy.p0.p0.i64(ptr nofree [[DEST]], ptr nofree [[SRC]], i64 [[SIZE]], i1 noundef false) #[[ATTR7:[0-9]+ ]]
211+ ; CGSCC-LABEL: define void @ calls_convergent_intrinsic(
212+ ; CGSCC-SAME: ptr nofree [[DEST:%.*]], ptr nofree [[SRC:%.*]], i64 [[SIZE:%.*]]) #[[ATTR4:[0-9]+]] {
213+ ; CGSCC-NEXT: call void @llvm.convergent.copy.p0.p0.i64(ptr nofree [[DEST]], ptr nofree [[SRC]], i64 [[SIZE]], i1 noundef false) #[[ATTR8 ]]
103214; CGSCC-NEXT: ret void
104215;
105216 call void @llvm.convergent.copy.p0.p0.i64 (ptr %dest , ptr %src , i64 %size , i1 false )
@@ -110,15 +221,15 @@ declare void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 %size, i1 %isVolati
110221
111222define void @calls_intrinsic (ptr %dest , ptr %src , i64 %size ) convergent {
112223; TUNIT: Function Attrs: convergent mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
113- ; TUNIT-LABEL: define {{[^@]+}}@ calls_intrinsic
114- ; TUNIT-SAME: ( ptr nofree writeonly captures(none) [[DEST:%.*]], ptr nofree readonly captures(none) [[SRC:%.*]], i64 [[SIZE:%.*]]) #[[ATTR2:[0-9]+]] {
115- ; TUNIT-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr nofree writeonly captures(none) [[DEST]], ptr nofree readonly captures(none) [[SRC]], i64 [[SIZE]], i1 noundef false) #[[ATTR5 ]]
224+ ; TUNIT-LABEL: define void @ calls_intrinsic(
225+ ; TUNIT-SAME: ptr nofree writeonly captures(none) [[DEST:%.*]], ptr nofree readonly captures(none) [[SRC:%.*]], i64 [[SIZE:%.*]]) #[[ATTR2:[0-9]+]] {
226+ ; TUNIT-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr nofree writeonly captures(none) [[DEST]], ptr nofree readonly captures(none) [[SRC]], i64 [[SIZE]], i1 noundef false) #[[ATTR6 ]]
116227; TUNIT-NEXT: ret void
117228;
118229; CGSCC: Function Attrs: convergent mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite)
119- ; CGSCC-LABEL: define {{[^@]+}}@ calls_intrinsic
120- ; CGSCC-SAME: ( ptr nofree writeonly captures(none) [[DEST:%.*]], ptr nofree readonly captures(none) [[SRC:%.*]], i64 [[SIZE:%.*]]) #[[ATTR3:[0-9]+]] {
121- ; CGSCC-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr nofree writeonly captures(none) [[DEST]], ptr nofree readonly captures(none) [[SRC]], i64 [[SIZE]], i1 noundef false) #[[ATTR7 ]]
230+ ; CGSCC-LABEL: define void @ calls_intrinsic(
231+ ; CGSCC-SAME: ptr nofree writeonly captures(none) [[DEST:%.*]], ptr nofree readonly captures(none) [[SRC:%.*]], i64 [[SIZE:%.*]]) #[[ATTR3:[0-9]+]] {
232+ ; CGSCC-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr nofree writeonly captures(none) [[DEST]], ptr nofree readonly captures(none) [[SRC]], i64 [[SIZE]], i1 noundef false) #[[ATTR8 ]]
122233; CGSCC-NEXT: ret void
123234;
124235 call void @llvm.memcpy.p0.p0.i64 (ptr %dest , ptr %src , i64 %size , i1 false )
@@ -133,14 +244,17 @@ attributes #0 = { convergent mustprogress nofree norecurse nosync nounwind willr
133244; TUNIT: attributes #[[ATTR2]] = { convergent mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
134245; TUNIT: attributes #[[ATTR3]] = { convergent mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) }
135246; TUNIT: attributes #[[ATTR4:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
136- ; TUNIT: attributes #[[ATTR5]] = { nofree willreturn }
247+ ; TUNIT: attributes #[[ATTR5:[0-9]+]] = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
248+ ; TUNIT: attributes #[[ATTR6]] = { nofree willreturn }
249+ ; TUNIT: attributes #[[ATTR7]] = { nofree nosync willreturn }
137250;.
138251; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
139252; CGSCC: attributes #[[ATTR1]] = { convergent mustprogress nofree nosync nounwind willreturn memory(none) }
140253; CGSCC: attributes #[[ATTR2]] = { convergent }
141254; CGSCC: attributes #[[ATTR3]] = { convergent mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
142255; CGSCC: attributes #[[ATTR4]] = { convergent mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) }
143256; CGSCC: attributes #[[ATTR5:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
144- ; CGSCC: attributes #[[ATTR6]] = { nofree nosync willreturn }
145- ; CGSCC: attributes #[[ATTR7]] = { nofree willreturn }
257+ ; CGSCC: attributes #[[ATTR6:[0-9]+]] = { convergent nocallback nofree nosync nounwind willreturn memory(none) }
258+ ; CGSCC: attributes #[[ATTR7]] = { nofree nosync willreturn }
259+ ; CGSCC: attributes #[[ATTR8]] = { nofree willreturn }
146260;.
0 commit comments