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