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