blob: 4a1ff14b2041aa6d61b527ff9970dec7203cc97a [file] [log] [blame]
Sanjay Patel4f742162017-02-13 23:10:51 +00001; RUN: opt -S -functionattrs -enable-nonnull-arg-prop %s | FileCheck %s
Philip Reamesa88caea2015-08-31 19:44:38 +00002declare nonnull i8* @ret_nonnull()
3
4; Return a pointer trivially nonnull (call return attribute)
5define i8* @test1() {
6; CHECK: define nonnull i8* @test1
7 %ret = call i8* @ret_nonnull()
8 ret i8* %ret
9}
10
11; Return a pointer trivially nonnull (argument attribute)
12define i8* @test2(i8* nonnull %p) {
13; CHECK: define nonnull i8* @test2
14 ret i8* %p
15}
16
17; Given an SCC where one of the functions can not be marked nonnull,
18; can we still mark the other one which is trivially nonnull
19define i8* @scc_binder() {
20; CHECK: define i8* @scc_binder
21 call i8* @test3()
22 ret i8* null
23}
24
25define i8* @test3() {
26; CHECK: define nonnull i8* @test3
27 call i8* @scc_binder()
28 %ret = call i8* @ret_nonnull()
29 ret i8* %ret
30}
31
32; Given a mutual recursive set of functions, we can mark them
33; nonnull if neither can ever return null. (In this case, they
34; just never return period.)
35define i8* @test4_helper() {
36; CHECK: define noalias nonnull i8* @test4_helper
37 %ret = call i8* @test4()
38 ret i8* %ret
39}
40
41define i8* @test4() {
42; CHECK: define noalias nonnull i8* @test4
43 %ret = call i8* @test4_helper()
44 ret i8* %ret
45}
46
47; Given a mutual recursive set of functions which *can* return null
48; make sure we haven't marked them as nonnull.
49define i8* @test5_helper() {
50; CHECK: define noalias i8* @test5_helper
51 %ret = call i8* @test5()
52 ret i8* null
53}
54
55define i8* @test5() {
56; CHECK: define noalias i8* @test5
57 %ret = call i8* @test5_helper()
58 ret i8* %ret
59}
60
61; Local analysis, but going through a self recursive phi
62define i8* @test6() {
63entry:
64; CHECK: define nonnull i8* @test6
65 %ret = call i8* @ret_nonnull()
66 br label %loop
67loop:
68 %phi = phi i8* [%ret, %entry], [%phi, %loop]
69 br i1 undef, label %loop, label %exit
70exit:
71 ret i8* %phi
72}
73
Sanjay Patel4f742162017-02-13 23:10:51 +000074; Test propagation of nonnull callsite args back to caller.
75
76declare void @use1(i8* %x)
77declare void @use2(i8* %x, i8* %y);
78declare void @use3(i8* %x, i8* %y, i8* %z);
79
80declare void @use1nonnull(i8* nonnull %x);
81declare void @use2nonnull(i8* nonnull %x, i8* nonnull %y);
82declare void @use3nonnull(i8* nonnull %x, i8* nonnull %y, i8* nonnull %z);
83
84declare i8 @use1safecall(i8* %x) readonly nounwind ; readonly+nounwind guarantees that execution continues to successor
85
86; Can't extend non-null to parent for any argument because the 2nd call is not guaranteed to execute.
87
88define void @parent1(i8* %a, i8* %b, i8* %c) {
89; CHECK-LABEL: @parent1(i8* %a, i8* %b, i8* %c)
90; CHECK-NEXT: call void @use3(i8* %c, i8* %a, i8* %b)
91; CHECK-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a)
92; CHECK-NEXT: ret void
93;
94 call void @use3(i8* %c, i8* %a, i8* %b)
95 call void @use3nonnull(i8* %b, i8* %c, i8* %a)
96 ret void
97}
98
99; Extend non-null to parent for all arguments.
100
101define void @parent2(i8* %a, i8* %b, i8* %c) {
102; CHECK-LABEL: @parent2(i8* nonnull %a, i8* nonnull %b, i8* nonnull %c)
103; CHECK-NEXT: call void @use3nonnull(i8* %b, i8* %c, i8* %a)
104; CHECK-NEXT: call void @use3(i8* %c, i8* %a, i8* %b)
105; CHECK-NEXT: ret void
106;
107 call void @use3nonnull(i8* %b, i8* %c, i8* %a)
108 call void @use3(i8* %c, i8* %a, i8* %b)
109 ret void
110}
111
112; Extend non-null to parent for 1st argument.
113
114define void @parent3(i8* %a, i8* %b, i8* %c) {
115; CHECK-LABEL: @parent3(i8* nonnull %a, i8* %b, i8* %c)
116; CHECK-NEXT: call void @use1nonnull(i8* %a)
117; CHECK-NEXT: call void @use3(i8* %c, i8* %b, i8* %a)
118; CHECK-NEXT: ret void
119;
120 call void @use1nonnull(i8* %a)
121 call void @use3(i8* %c, i8* %b, i8* %a)
122 ret void
123}
124
125; Extend non-null to parent for last 2 arguments.
126
127define void @parent4(i8* %a, i8* %b, i8* %c) {
128; CHECK-LABEL: @parent4(i8* %a, i8* nonnull %b, i8* nonnull %c)
129; CHECK-NEXT: call void @use2nonnull(i8* %c, i8* %b)
130; CHECK-NEXT: call void @use2(i8* %a, i8* %c)
131; CHECK-NEXT: call void @use1(i8* %b)
132; CHECK-NEXT: ret void
133;
134 call void @use2nonnull(i8* %c, i8* %b)
135 call void @use2(i8* %a, i8* %c)
136 call void @use1(i8* %b)
137 ret void
138}
139
140; The callsite must execute in order for the attribute to transfer to the parent.
141; It appears benign to extend non-null to the parent in this case, but we can't do that
142; because it would incorrectly propagate the wrong information to its callers.
143
144define void @parent5(i8* %a, i1 %a_is_notnull) {
145; CHECK-LABEL: @parent5(i8* %a, i1 %a_is_notnull)
146; CHECK-NEXT: br i1 %a_is_notnull, label %t, label %f
147; CHECK: t:
148; CHECK-NEXT: call void @use1nonnull(i8* %a)
149; CHECK-NEXT: ret void
150; CHECK: f:
151; CHECK-NEXT: ret void
152;
153 br i1 %a_is_notnull, label %t, label %f
154t:
155 call void @use1nonnull(i8* %a)
156 ret void
157f:
158 ret void
159}
160
161; The callsite must execute in order for the attribute to transfer to the parent.
162; The volatile load might trap, so there's no guarantee that we'll ever get to the call.
163
164define i8 @parent6(i8* %a, i8* %b) {
165; CHECK-LABEL: @parent6(i8* %a, i8* %b)
166; CHECK-NEXT: [[C:%.*]] = load volatile i8, i8* %b
167; CHECK-NEXT: call void @use1nonnull(i8* %a)
168; CHECK-NEXT: ret i8 [[C]]
169;
170 %c = load volatile i8, i8* %b
171 call void @use1nonnull(i8* %a)
172 ret i8 %c
173}
174
175; The nonnull callsite is guaranteed to execute, so the argument must be nonnull throughout the parent.
176
177define i8 @parent7(i8* %a) {
178; CHECK-LABEL: @parent7(i8* nonnull %a)
179; CHECK-NEXT: [[RET:%.*]] = call i8 @use1safecall(i8* %a)
180; CHECK-NEXT: call void @use1nonnull(i8* %a)
181; CHECK-NEXT: ret i8 [[RET]]
182;
183 %ret = call i8 @use1safecall(i8* %a)
184 call void @use1nonnull(i8* %a)
185 ret i8 %ret
186}
187
188; Make sure that an invoke works similarly to a call.
189
190declare i32 @esfp(...)
191
192define i1 @parent8(i8* %a, i8* %bogus1, i8* %b) personality i8* bitcast (i32 (...)* @esfp to i8*){
193; CHECK-LABEL: @parent8(i8* nonnull %a, i8* nocapture readnone %bogus1, i8* nonnull %b)
194; CHECK-NEXT: entry:
195; CHECK-NEXT: invoke void @use2nonnull(i8* %a, i8* %b)
196; CHECK-NEXT: to label %cont unwind label %exc
197; CHECK: cont:
198; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %b, null
199; CHECK-NEXT: ret i1 [[NULL_CHECK]]
200; CHECK: exc:
201; CHECK-NEXT: [[LP:%.*]] = landingpad { i8*, i32 }
202; CHECK-NEXT: filter [0 x i8*] zeroinitializer
203; CHECK-NEXT: unreachable
204;
205entry:
206 invoke void @use2nonnull(i8* %a, i8* %b)
207 to label %cont unwind label %exc
208
209cont:
210 %null_check = icmp eq i8* %b, null
211 ret i1 %null_check
212
213exc:
214 %lp = landingpad { i8*, i32 }
215 filter [0 x i8*] zeroinitializer
216 unreachable
217}
Philip Reamesa88caea2015-08-31 19:44:38 +0000218