xref: /llvm-project/llvm/test/Transforms/Attributor/convergent.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
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
4
5define i32 @defined() convergent {
6; CHECK: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
7; CHECK-LABEL: define {{[^@]+}}@defined
8; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
9; CHECK-NEXT:    ret i32 1
10;
11  ret i32 1
12}
13
14define i32 @calls_defined() convergent {
15; TUNIT: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none)
16; TUNIT-LABEL: define {{[^@]+}}@calls_defined
17; TUNIT-SAME: () #[[ATTR0]] {
18; TUNIT-NEXT:    ret i32 1
19;
20; 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]+]]
24; CGSCC-NEXT:    ret i32 [[A]]
25;
26  %a = call i32 @defined()
27  ret i32 %a
28}
29
30declare void @declared_non_convergent()
31
32define void @calls_declared_non_convergent() convergent {
33; CHECK-LABEL: define {{[^@]+}}@calls_declared_non_convergent() {
34; CHECK-NEXT:    call void @declared_non_convergent()
35; CHECK-NEXT:    ret void
36;
37  call void @declared_non_convergent()
38  ret void
39}
40
41; CHECK: Function Attrs: convergent
42declare i32 @declared_convergent() convergent
43
44define i32 @calls_declared_convergent() convergent {
45; TUNIT: Function Attrs: convergent
46; TUNIT-LABEL: define {{[^@]+}}@calls_declared_convergent
47; TUNIT-SAME: () #[[ATTR1:[0-9]+]] {
48; TUNIT-NEXT:    [[A:%.*]] = call i32 @declared_convergent()
49; TUNIT-NEXT:    ret i32 [[A]]
50;
51; CGSCC: Function Attrs: convergent
52; CGSCC-LABEL: define {{[^@]+}}@calls_declared_convergent
53; CGSCC-SAME: () #[[ATTR2:[0-9]+]] {
54; CGSCC-NEXT:    [[A:%.*]] = call i32 @declared_convergent()
55; CGSCC-NEXT:    ret i32 [[A]]
56;
57  %a = call i32 @declared_convergent()
58  ret i32 %a
59}
60
61define i32 @defined_with_asm(i32 %a, i32 %b) {
62; CHECK-LABEL: define {{[^@]+}}@defined_with_asm
63; CHECK-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) {
64; CHECK-NEXT:    [[RESULT:%.*]] = add i32 [[A]], [[B]]
65; CHECK-NEXT:    [[ASM_RESULT:%.*]] = call i32 asm sideeffect "addl $1, $0", "=r,r"(i32 [[RESULT]])
66; CHECK-NEXT:    ret i32 [[ASM_RESULT]]
67;
68  %result = add i32 %a, %b
69  %asm_result = call i32 asm sideeffect "addl $1, $0", "=r,r"(i32 %result)
70  ret i32 %asm_result
71}
72
73define i32 @calls_defined_with_asm(i32 %a, i32 %b) convergent {
74; TUNIT: Function Attrs: convergent
75; TUNIT-LABEL: define {{[^@]+}}@calls_defined_with_asm
76; TUNIT-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) #[[ATTR1]] {
77; TUNIT-NEXT:    [[C:%.*]] = call i32 @defined_with_asm(i32 [[A]], i32 [[B]])
78; TUNIT-NEXT:    ret i32 [[C]]
79;
80; CGSCC: Function Attrs: convergent
81; CGSCC-LABEL: define {{[^@]+}}@calls_defined_with_asm
82; CGSCC-SAME: (i32 [[A:%.*]], i32 [[B:%.*]]) #[[ATTR2]] {
83; CGSCC-NEXT:    [[C:%.*]] = call i32 @defined_with_asm(i32 [[A]], i32 [[B]])
84; CGSCC-NEXT:    ret i32 [[C]]
85;
86  %c = call i32 @defined_with_asm(i32 %a, i32 %b)
87  ret i32 %c
88}
89
90declare void @llvm.convergent.copy.p0.p0.i64(ptr %dest, ptr %src, i64 %size, i1 %isVolatile) #0
91
92define void @calls_convergent_intrinsic(ptr %dest, ptr %src, i64 %size) convergent {
93; 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]+]]
97; TUNIT-NEXT:    ret void
98;
99; 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]+]]
103; CGSCC-NEXT:    ret void
104;
105  call void @llvm.convergent.copy.p0.p0.i64(ptr %dest, ptr %src, i64 %size, i1 false)
106  ret void
107}
108
109declare void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 %size, i1 %isVolatile) #0
110
111define void @calls_intrinsic(ptr %dest, ptr %src, i64 %size) convergent {
112; 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]]
116; TUNIT-NEXT:    ret void
117;
118; 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]]
122; CGSCC-NEXT:    ret void
123;
124  call void @llvm.memcpy.p0.p0.i64(ptr %dest, ptr %src, i64 %size, i1 false)
125  ret void
126}
127
128attributes #0 = { convergent mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
129
130;.
131; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
132; TUNIT: attributes #[[ATTR1]] = { convergent }
133; TUNIT: attributes #[[ATTR2]] = { convergent mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
134; TUNIT: attributes #[[ATTR3]] = { convergent mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) }
135; TUNIT: attributes #[[ATTR4:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
136; TUNIT: attributes #[[ATTR5]] = { nofree willreturn }
137;.
138; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) }
139; CGSCC: attributes #[[ATTR1]] = { convergent mustprogress nofree nosync nounwind willreturn memory(none) }
140; CGSCC: attributes #[[ATTR2]] = { convergent }
141; CGSCC: attributes #[[ATTR3]] = { convergent mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) }
142; CGSCC: attributes #[[ATTR4]] = { convergent mustprogress nofree nosync nounwind willreturn memory(argmem: readwrite) }
143; 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 }
146;.
147