xref: /llvm-project/llvm/test/Transforms/SCCP/pointer-nonnull.ll (revision b7e51b4f139ec18c498c818c6bcaa5a842cea83c)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2; RUN: opt -S -passes=sccp < %s | FileCheck %s --check-prefixes=CHECK,SCCP
3; RUN: opt -S -passes=ipsccp < %s | FileCheck %s --check-prefixes=CHECK,IPSCCP
4
5declare ptr @get()
6
7define i1 @test_no_attr(ptr %p) {
8; CHECK-LABEL: define i1 @test_no_attr(
9; CHECK-SAME: ptr [[P:%.*]]) {
10; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[P]], null
11; CHECK-NEXT:    ret i1 [[CMP]]
12;
13  %cmp = icmp ne ptr %p, null
14  ret i1 %cmp
15}
16
17define i1 @test_nonnull(ptr nonnull %p) {
18; CHECK-LABEL: define i1 @test_nonnull(
19; CHECK-SAME: ptr nonnull [[P:%.*]]) {
20; CHECK-NEXT:    ret i1 true
21;
22  %cmp = icmp ne ptr %p, null
23  ret i1 %cmp
24}
25
26define i1 @test_nonnull_eq(ptr nonnull %p) {
27; CHECK-LABEL: define i1 @test_nonnull_eq(
28; CHECK-SAME: ptr nonnull [[P:%.*]]) {
29; CHECK-NEXT:    ret i1 false
30;
31  %cmp = icmp eq ptr %p, null
32  ret i1 %cmp
33}
34
35define i1 @test_dereferenceable(ptr dereferenceable(4) %p) {
36; CHECK-LABEL: define i1 @test_dereferenceable(
37; CHECK-SAME: ptr dereferenceable(4) [[P:%.*]]) {
38; CHECK-NEXT:    ret i1 true
39;
40  %cmp = icmp ne ptr %p, null
41  ret i1 %cmp
42}
43
44define i1 @test_alloca() {
45; CHECK-LABEL: define i1 @test_alloca() {
46; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
47; CHECK-NEXT:    ret i1 true
48;
49  %a = alloca i32
50  %cmp = icmp ne ptr %a, null
51  ret i1 %cmp
52}
53
54define i1 @test_alloca_addrspace() {
55; CHECK-LABEL: define i1 @test_alloca_addrspace() {
56; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4, addrspace(1)
57; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr addrspace(1) [[A]], null
58; CHECK-NEXT:    ret i1 [[CMP]]
59;
60  %a = alloca i32, addrspace(1)
61  %cmp = icmp ne ptr addrspace(1) %a, null
62  ret i1 %cmp
63}
64
65define i1 @test_alloca_null_pointer_valid() null_pointer_is_valid {
66; CHECK-LABEL: define i1 @test_alloca_null_pointer_valid(
67; CHECK-SAME: ) #[[ATTR0:[0-9]+]] {
68; CHECK-NEXT:    [[A:%.*]] = alloca i32, align 4
69; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[A]], null
70; CHECK-NEXT:    ret i1 [[CMP]]
71;
72  %a = alloca i32
73  %cmp = icmp ne ptr %a, null
74  ret i1 %cmp
75}
76
77define i1 @test_load_nonnull(ptr %p) {
78; CHECK-LABEL: define i1 @test_load_nonnull(
79; CHECK-SAME: ptr [[P:%.*]]) {
80; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P]], align 8, !nonnull [[META0:![0-9]+]]
81; CHECK-NEXT:    ret i1 true
82;
83  %p2 = load ptr, ptr %p, !nonnull !{}
84  %cmp = icmp ne ptr %p2, null
85  ret i1 %cmp
86}
87
88define i1 @test_call_nonnull() {
89; CHECK-LABEL: define i1 @test_call_nonnull() {
90; CHECK-NEXT:    [[P:%.*]] = call nonnull ptr @get()
91; CHECK-NEXT:    ret i1 true
92;
93  %p = call nonnull ptr @get()
94  %cmp = icmp ne ptr %p, null
95  ret i1 %cmp
96}
97
98define i1 @test_call_dereferenceable() {
99; CHECK-LABEL: define i1 @test_call_dereferenceable() {
100; CHECK-NEXT:    [[P:%.*]] = call dereferenceable(4) ptr @get()
101; CHECK-NEXT:    ret i1 true
102;
103  %p = call dereferenceable(4) ptr @get()
104  %cmp = icmp ne ptr %p, null
105  ret i1 %cmp
106}
107
108define i1 @test_gep_no_flags(ptr nonnull %p, i64 %x) {
109; CHECK-LABEL: define i1 @test_gep_no_flags(
110; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
111; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
112; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[GEP]], null
113; CHECK-NEXT:    ret i1 [[CMP]]
114;
115  %gep = getelementptr i8, ptr %p, i64 %x
116  %cmp = icmp ne ptr %gep, null
117  ret i1 %cmp
118}
119
120define i1 @test_gep_nuw(ptr nonnull %p, i64 %x) {
121; CHECK-LABEL: define i1 @test_gep_nuw(
122; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
123; CHECK-NEXT:    [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]]
124; CHECK-NEXT:    ret i1 true
125;
126  %gep = getelementptr nuw i8, ptr %p, i64 %x
127  %cmp = icmp ne ptr %gep, null
128  ret i1 %cmp
129}
130
131define i1 @test_gep_inbounds(ptr nonnull %p, i64 %x) {
132; CHECK-LABEL: define i1 @test_gep_inbounds(
133; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
134; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[X]]
135; CHECK-NEXT:    ret i1 true
136;
137  %gep = getelementptr inbounds i8, ptr %p, i64 %x
138  %cmp = icmp ne ptr %gep, null
139  ret i1 %cmp
140}
141
142define i1 @test_gep_inbounds_null_pointer_valid(ptr nonnull %p, i64 %x) null_pointer_is_valid {
143; CHECK-LABEL: define i1 @test_gep_inbounds_null_pointer_valid(
144; CHECK-SAME: ptr nonnull [[P:%.*]], i64 [[X:%.*]]) #[[ATTR0]] {
145; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[P]], i64 [[X]]
146; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[GEP]], null
147; CHECK-NEXT:    ret i1 [[CMP]]
148;
149  %gep = getelementptr inbounds i8, ptr %p, i64 %x
150  %cmp = icmp ne ptr %gep, null
151  ret i1 %cmp
152}
153
154define i1 @test_select(i1 %c, ptr nonnull %p, i64 %x) {
155; CHECK-LABEL: define i1 @test_select(
156; CHECK-SAME: i1 [[C:%.*]], ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
157; CHECK-NEXT:    [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]]
158; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[C]], ptr [[P]], ptr [[GEP]]
159; CHECK-NEXT:    ret i1 true
160;
161  %gep = getelementptr nuw i8, ptr %p, i64 %x
162  %sel = select i1 %c, ptr %p, ptr %gep
163  %cmp = icmp ne ptr %sel, null
164  ret i1 %cmp
165}
166
167define i1 @test_select_not_nuw(i1 %c, ptr nonnull %p, i64 %x) {
168; CHECK-LABEL: define i1 @test_select_not_nuw(
169; CHECK-SAME: i1 [[C:%.*]], ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
170; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]]
171; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[C]], ptr [[P]], ptr [[GEP]]
172; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[SEL]], null
173; CHECK-NEXT:    ret i1 [[CMP]]
174;
175  %gep = getelementptr i8, ptr %p, i64 %x
176  %sel = select i1 %c, ptr %p, ptr %gep
177  %cmp = icmp ne ptr %sel, null
178  ret i1 %cmp
179}
180
181define i1 @test_phi(i1 %c, ptr nonnull %p, i64 %x) {
182; CHECK-LABEL: define i1 @test_phi(
183; CHECK-SAME: i1 [[C:%.*]], ptr nonnull [[P:%.*]], i64 [[X:%.*]]) {
184; CHECK-NEXT:  [[ENTRY:.*]]:
185; CHECK-NEXT:    br i1 [[C]], label %[[IF:.*]], label %[[JOIN:.*]]
186; CHECK:       [[IF]]:
187; CHECK-NEXT:    [[GEP:%.*]] = getelementptr nuw i8, ptr [[P]], i64 [[X]]
188; CHECK-NEXT:    br label %[[JOIN]]
189; CHECK:       [[JOIN]]:
190; CHECK-NEXT:    [[PHI:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[GEP]], %[[IF]] ]
191; CHECK-NEXT:    ret i1 true
192;
193entry:
194  br i1 %c, label %if, label %join
195
196if:
197  %gep = getelementptr nuw i8, ptr %p, i64 %x
198  br label %join
199
200join:
201  %phi = phi ptr [ %p, %entry ], [ %gep, %if ]
202  %cmp = icmp ne ptr %phi, null
203  ret i1 %cmp
204}
205
206define internal i1 @ip_test_nonnull_callee(ptr nonnull %p) {
207; SCCP-LABEL: define internal i1 @ip_test_nonnull_callee(
208; SCCP-SAME: ptr nonnull [[P:%.*]]) {
209; SCCP-NEXT:    ret i1 true
210;
211; IPSCCP-LABEL: define internal i1 @ip_test_nonnull_callee(
212; IPSCCP-SAME: ptr nonnull [[P:%.*]]) {
213; IPSCCP-NEXT:    ret i1 poison
214;
215  %cmp = icmp ne ptr %p, null
216  ret i1 %cmp
217}
218
219define i1 @ip_test_nonnull_caller(ptr %p) {
220; SCCP-LABEL: define i1 @ip_test_nonnull_caller(
221; SCCP-SAME: ptr [[P:%.*]]) {
222; SCCP-NEXT:    [[RES:%.*]] = call i1 @ip_test_nonnull_callee(ptr [[P]])
223; SCCP-NEXT:    ret i1 [[RES]]
224;
225; IPSCCP-LABEL: define i1 @ip_test_nonnull_caller(
226; IPSCCP-SAME: ptr [[P:%.*]]) {
227; IPSCCP-NEXT:    [[RES:%.*]] = call i1 @ip_test_nonnull_callee(ptr [[P]])
228; IPSCCP-NEXT:    ret i1 true
229;
230  %res = call i1 @ip_test_nonnull_callee(ptr %p)
231  ret i1 %res
232}
233
234define ptr @ret_nonnull_pointer(ptr nonnull %p) {
235; CHECK-LABEL: define nonnull ptr @ret_nonnull_pointer(
236; CHECK-SAME: ptr nonnull [[P:%.*]]) {
237; CHECK-NEXT:    ret ptr [[P]]
238;
239  ret ptr %p
240}
241
242define ptr @ret_maybe_null_pointer(ptr %p) {
243; CHECK-LABEL: define ptr @ret_maybe_null_pointer(
244; CHECK-SAME: ptr [[P:%.*]]) {
245; CHECK-NEXT:    ret ptr [[P]]
246;
247  ret ptr %p
248}
249
250define internal void @ip_nonnull_arg_callee(ptr %p) {
251; SCCP-LABEL: define internal void @ip_nonnull_arg_callee(
252; SCCP-SAME: ptr [[P:%.*]]) {
253; SCCP-NEXT:    ret void
254;
255; IPSCCP-LABEL: define internal void @ip_nonnull_arg_callee(
256; IPSCCP-SAME: ptr nonnull [[P:%.*]]) {
257; IPSCCP-NEXT:    ret void
258;
259  ret void
260}
261
262define internal void @ip_not_nonnull_arg_callee(ptr %p) {
263; CHECK-LABEL: define internal void @ip_not_nonnull_arg_callee(
264; CHECK-SAME: ptr [[P:%.*]]) {
265; CHECK-NEXT:    ret void
266;
267  ret void
268}
269
270define void @ip_nonnull_arg_caller(ptr nonnull %p) {
271; CHECK-LABEL: define void @ip_nonnull_arg_caller(
272; CHECK-SAME: ptr nonnull [[P:%.*]]) {
273; CHECK-NEXT:    call void @ip_nonnull_arg_callee(ptr [[P]])
274; CHECK-NEXT:    call void @ip_not_nonnull_arg_callee(ptr [[P]])
275; CHECK-NEXT:    call void @ip_not_nonnull_arg_callee(ptr null)
276; CHECK-NEXT:    ret void
277;
278  call void @ip_nonnull_arg_callee(ptr %p)
279  call void @ip_not_nonnull_arg_callee(ptr %p)
280  call void @ip_not_nonnull_arg_callee(ptr null)
281  ret void
282}
283
284;.
285; SCCP: [[META0]] = !{}
286;.
287; IPSCCP: [[META0]] = !{}
288;.
289