xref: /llvm-project/llvm/test/Transforms/SCCP/ipscp-drop-argmemonly.ll (revision 304f1d59ca41872c094def3aee0a8689df6aa398)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --check-globals
2; RUN: opt -passes=ipsccp -S %s | FileCheck %s
3
4; Test cases to ensure argmemonly/inaccessiblemem_or_argmemonly attributes are
5; dropped, if a function argument is replaced by a constant.
6;
7; PR46717
8
9@g = internal global i32 0
10
11; Here the pointer argument %arg will be replaced by a constant. We need to
12; drop argmemonly.
13;.
14; CHECK: @[[G:[a-zA-Z0-9_$"\\.-]+]] = internal global i32 0
15;.
16define internal void @ptrarg.1(ptr %arg, i32 %val) argmemonly nounwind {
17; CHECK: Function Attrs: nounwind memory(readwrite, inaccessiblemem: none)
18; CHECK-LABEL: @ptrarg.1(
19; CHECK-NEXT:    store i32 10, ptr @g, align 4
20; CHECK-NEXT:    ret void
21;
22  store i32 %val, ptr %arg
23  ret void
24}
25
26define i32 @caller.1(i32 %n) {
27; CHECK-LABEL: @caller.1(
28; CHECK-NEXT:    store i32 1, ptr @g, align 4
29; CHECK-NEXT:    tail call void @ptrarg.1(ptr @g, i32 10)
30; CHECK-NEXT:    [[G_VAL:%.*]] = load i32, ptr @g, align 4
31; CHECK-NEXT:    ret i32 [[G_VAL]]
32;
33  store i32 1, ptr @g
34  tail call void @ptrarg.1(ptr @g, i32 10)
35  %g.val = load i32, ptr @g
36  ret i32 %g.val
37}
38
39
40; Here only the non-pointer argument %val is replaced, no need
41; to drop the argmemonly attribute.
42define internal void @ptrarg.2(ptr %arg, i32 %val) argmemonly nounwind {
43; CHECK: Function Attrs: nounwind memory(argmem: readwrite)
44; CHECK-LABEL: @ptrarg.2(
45; CHECK-NEXT:    store i32 10, ptr [[ARG:%.*]], align 4
46; CHECK-NEXT:    ret void
47;
48  store i32 %val, ptr %arg
49  ret void
50}
51
52define void @caller.2(ptr %ptr) {
53; CHECK-LABEL: @caller.2(
54; CHECK-NEXT:    tail call void @ptrarg.2(ptr [[PTR:%.*]], i32 10)
55; CHECK-NEXT:    ret void
56;
57  tail call void @ptrarg.2(ptr %ptr, i32 10)
58  ret void
59}
60
61
62; Here the pointer argument %arg will be replaced by a constant. We need to
63; drop inaccessiblemem_or_argmemonly.
64define internal void @ptrarg.3(ptr %arg, i32 %val) inaccessiblemem_or_argmemonly nounwind {
65; CHECK: Function Attrs: nounwind memory(readwrite)
66; CHECK-LABEL: @ptrarg.3(
67; CHECK-NEXT:    store i32 10, ptr @g, align 4
68; CHECK-NEXT:    ret void
69;
70  store i32 %val, ptr %arg
71  ret void
72}
73
74define i32 @caller.3(i32 %n) {
75; CHECK-LABEL: @caller.3(
76; CHECK-NEXT:    store i32 1, ptr @g, align 4
77; CHECK-NEXT:    tail call void @ptrarg.3(ptr @g, i32 10)
78; CHECK-NEXT:    [[G_VAL:%.*]] = load i32, ptr @g, align 4
79; CHECK-NEXT:    ret i32 [[G_VAL]]
80;
81  store i32 1, ptr @g
82  tail call void @ptrarg.3(ptr @g, i32 10)
83  %g.val = load i32, ptr @g
84  ret i32 %g.val
85}
86
87
88; Here only the non-pointer argument %val is replaced, no need
89; to drop the inaccessiblemem_or_argmemonly attribute.
90define internal void @ptrarg.4(ptr %arg, i32 %val) inaccessiblemem_or_argmemonly nounwind {
91; CHECK: Function Attrs: nounwind memory(argmem: readwrite, inaccessiblemem: readwrite)
92; CHECK-LABEL: @ptrarg.4(
93; CHECK-NEXT:    store i32 10, ptr [[ARG:%.*]], align 4
94; CHECK-NEXT:    ret void
95;
96  store i32 %val, ptr %arg
97  ret void
98}
99
100define void @caller.4(ptr %ptr) {
101; CHECK-LABEL: @caller.4(
102; CHECK-NEXT:    tail call void @ptrarg.4(ptr [[PTR:%.*]], i32 10)
103; CHECK-NEXT:    ret void
104;
105  tail call void @ptrarg.4(ptr %ptr, i32 10)
106  ret void
107}
108
109
110; Here the pointer argument %arg will be replaced by a constant. We need to
111; drop inaccessiblemem_or_argmemonly.
112define internal void @ptrarg.5(ptr %arg, i32 %val) argmemonly inaccessiblemem_or_argmemonly nounwind {
113; CHECK: Function Attrs: nounwind memory(readwrite, inaccessiblemem: none)
114; CHECK-LABEL: @ptrarg.5(
115; CHECK-NEXT:    store i32 10, ptr @g, align 4
116; CHECK-NEXT:    ret void
117;
118  store i32 %val, ptr %arg
119  ret void
120}
121
122define i32 @caller.5(i32 %n) {
123; CHECK-LABEL: @caller.5(
124; CHECK-NEXT:    store i32 1, ptr @g, align 4
125; CHECK-NEXT:    tail call void @ptrarg.5(ptr @g, i32 10)
126; CHECK-NEXT:    [[G_VAL:%.*]] = load i32, ptr @g, align 4
127; CHECK-NEXT:    ret i32 [[G_VAL]]
128;
129  store i32 1, ptr @g
130  tail call void @ptrarg.5(ptr @g, i32 10)
131  %g.val = load i32, ptr @g
132  ret i32 %g.val
133}
134
135
136; Make sure callsite attributes are also dropped when a pointer argument is
137; replaced.
138define internal void @ptrarg.6.cs.attributes(ptr %arg, i32 %val) {
139; CHECK-LABEL: @ptrarg.6.cs.attributes(
140; CHECK-NEXT:    unreachable
141;
142  store i32 %val, ptr %arg
143  ret void
144}
145
146define i32 @caller.6.cs.attributes(i32 %n) {
147; CHECK-LABEL: @caller.6.cs.attributes(
148; CHECK-NEXT:    store i32 1, ptr @g, align 4
149; CHECK-NEXT:    tail call void @ptrarg.5(ptr @g, i32 10) #[[ATTR0:[0-9]+]]
150; CHECK-NEXT:    tail call void @ptrarg.5(ptr @g, i32 10) #[[ATTR2:[0-9]+]]
151; CHECK-NEXT:    tail call void @ptrarg.5(ptr @g, i32 10) #[[ATTR0]]
152; CHECK-NEXT:    tail call void @ptrarg.5(ptr @g, i32 10) #[[ATTR4:[0-9]+]]
153; CHECK-NEXT:    [[G_VAL:%.*]] = load i32, ptr @g, align 4
154; CHECK-NEXT:    ret i32 [[G_VAL]]
155;
156  store i32 1, ptr @g
157  tail call void @ptrarg.5(ptr @g, i32 10) argmemonly inaccessiblemem_or_argmemonly nounwind
158  tail call void @ptrarg.5(ptr @g, i32 10) inaccessiblemem_or_argmemonly nounwind
159  tail call void @ptrarg.5(ptr @g, i32 10) argmemonly nounwind
160  tail call void @ptrarg.5(ptr @g, i32 10) nounwind
161  %g.val = load i32, ptr @g
162  ret i32 %g.val
163}
164
165;.
166; CHECK: attributes #[[ATTR0]] = { nounwind memory(readwrite, inaccessiblemem: none) }
167; CHECK: attributes #[[ATTR1:[0-9]+]] = { nounwind memory(argmem: readwrite) }
168; CHECK: attributes #[[ATTR2]] = { nounwind memory(readwrite) }
169; CHECK: attributes #[[ATTR3:[0-9]+]] = { nounwind memory(argmem: readwrite, inaccessiblemem: readwrite) }
170; CHECK: attributes #[[ATTR4]] = { nounwind }
171;.
172