1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -instsimplify < %s | FileCheck %s
4 declare void @bar(i8* %a, i8* nonnull %b)
8 define i1 @caller1(i8* %x, i8* %y) {
9 ; CHECK-LABEL: @caller1(
10 ; CHECK-NEXT: call void @bar(i8* [[X:%.*]], i8* [[Y:%.*]])
11 ; CHECK-NEXT: ret i1 false
13 call void @bar(i8* %x, i8* %y)
14 %null_check = icmp eq i8* %y, null
18 ; Don't know anything about 'y'.
20 define i1 @caller2(i8* %x, i8* %y) {
21 ; CHECK-LABEL: @caller2(
22 ; CHECK-NEXT: call void @bar(i8* [[Y:%.*]], i8* [[X:%.*]])
23 ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[Y]], null
24 ; CHECK-NEXT: ret i1 [[NULL_CHECK]]
26 call void @bar(i8* %y, i8* %x)
27 %null_check = icmp eq i8* %y, null
31 ; 'y' must be nonnull.
33 define i1 @caller3(i8* %x, i8* %y) {
34 ; CHECK-LABEL: @caller3(
35 ; CHECK-NEXT: call void @bar(i8* [[X:%.*]], i8* [[Y:%.*]])
36 ; CHECK-NEXT: ret i1 true
38 call void @bar(i8* %x, i8* %y)
39 %null_check = icmp ne i8* %y, null
43 ; FIXME: The call is guaranteed to execute, so 'y' must be nonnull throughout.
45 define i1 @caller4(i8* %x, i8* %y) {
46 ; CHECK-LABEL: @caller4(
47 ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp ne i8* [[Y:%.*]], null
48 ; CHECK-NEXT: call void @bar(i8* [[X:%.*]], i8* [[Y]])
49 ; CHECK-NEXT: ret i1 [[NULL_CHECK]]
51 %null_check = icmp ne i8* %y, null
52 call void @bar(i8* %x, i8* %y)
56 ; The call to bar() does not dominate the null check, so no change.
58 define i1 @caller5(i8* %x, i8* %y) {
59 ; CHECK-LABEL: @caller5(
60 ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[Y:%.*]], null
61 ; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[T:%.*]], label [[F:%.*]]
63 ; CHECK-NEXT: ret i1 [[NULL_CHECK]]
65 ; CHECK-NEXT: call void @bar(i8* [[X:%.*]], i8* [[Y]])
66 ; CHECK-NEXT: ret i1 [[NULL_CHECK]]
68 %null_check = icmp eq i8* %y, null
69 br i1 %null_check, label %t, label %f
73 call void @bar(i8* %x, i8* %y)
77 ; Make sure that an invoke works similarly to a call.
79 declare i32 @esfp(...)
81 define i1 @caller6(i8* %x, i8* %y) personality i8* bitcast (i32 (...)* @esfp to i8*){
82 ; CHECK-LABEL: @caller6(
83 ; CHECK-NEXT: invoke void @bar(i8* [[X:%.*]], i8* nonnull [[Y:%.*]])
84 ; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]]
86 ; CHECK-NEXT: ret i1 false
88 ; CHECK-NEXT: [[LP:%.*]] = landingpad { i8*, i32 }
89 ; CHECK-NEXT: filter [0 x i8*] zeroinitializer
90 ; CHECK-NEXT: unreachable
92 invoke void @bar(i8* %x, i8* nonnull %y)
93 to label %cont unwind label %exc
96 %null_check = icmp eq i8* %y, null
100 %lp = landingpad { i8*, i32 }
101 filter [0 x i8*] zeroinitializer
105 declare i8* @returningPtr(i8* returned %p)
107 define i1 @nonnullReturnTest(i8* nonnull %x) {
108 ; CHECK-LABEL: @nonnullReturnTest(
109 ; CHECK-NEXT: [[X2:%.*]] = call i8* @returningPtr(i8* [[X:%.*]])
110 ; CHECK-NEXT: ret i1 false
112 %x2 = call i8* @returningPtr(i8* %x)
113 %null_check = icmp eq i8* %x2, null
117 define i1 @unknownReturnTest(i8* %x) {
118 ; CHECK-LABEL: @unknownReturnTest(
119 ; CHECK-NEXT: [[X2:%.*]] = call i8* @returningPtr(i8* [[X:%.*]])
120 ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[X2]], null
121 ; CHECK-NEXT: ret i1 [[NULL_CHECK]]
123 %x2 = call i8* @returningPtr(i8* %x)
124 %null_check = icmp eq i8* %x2, null
128 ; Make sure that if load/store happened, the pointer is nonnull.
130 define i32 @test_null_after_store(i32* %0) {
131 ; CHECK-LABEL: @test_null_after_store(
132 ; CHECK-NEXT: store i32 123, i32* [[TMP0:%.*]], align 4
133 ; CHECK-NEXT: ret i32 2
135 store i32 123, i32* %0, align 4
136 %2 = icmp eq i32* %0, null
137 %3 = select i1 %2, i32 1, i32 2
141 define i32 @test_null_after_load(i32* %0) {
142 ; CHECK-LABEL: @test_null_after_load(
143 ; CHECK-NEXT: ret i32 1
145 %2 = load i32, i32* %0, align 4
146 %3 = icmp eq i32* %0, null
147 %4 = select i1 %3, i32 %2, i32 1
151 ; Make sure that different address space does not affect null pointer check.
153 define i32 @test_null_after_store_addrspace(i32 addrspace(1)* %0) {
154 ; CHECK-LABEL: @test_null_after_store_addrspace(
155 ; CHECK-NEXT: store i32 123, i32 addrspace(1)* [[TMP0:%.*]], align 4
156 ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 addrspace(1)* [[TMP0]], null
157 ; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 1, i32 2
158 ; CHECK-NEXT: ret i32 [[TMP3]]
160 store i32 123, i32 addrspace(1)* %0, align 4
161 %2 = icmp eq i32 addrspace(1)* %0, null
162 %3 = select i1 %2, i32 1, i32 2
166 define i32 @test_null_after_load_addrspace(i32 addrspace(1)* %0) {
167 ; CHECK-LABEL: @test_null_after_load_addrspace(
168 ; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32 addrspace(1)* [[TMP0:%.*]], align 4
169 ; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 addrspace(1)* [[TMP0]], null
170 ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 1
171 ; CHECK-NEXT: ret i32 [[TMP4]]
173 ; CHECK-NEXT ret i32 %4
174 %2 = load i32, i32 addrspace(1)* %0, align 4
175 %3 = icmp eq i32 addrspace(1)* %0, null
176 %4 = select i1 %3, i32 %2, i32 1
180 ; Make sure if store happened after the check, nullptr check is not removed.
182 declare i8* @func(i64)
184 define i8* @test_load_store_after_check(i8* %0) {
185 ; CHECK-LABEL: @test_load_store_after_check(
187 ; CHECK-NEXT: [[TMP1:%.*]] = call i8* @func(i64 0)
188 ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[TMP1]], null
189 ; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[RETURN:%.*]], label [[IF_END:%.*]]
191 ; CHECK-NEXT: store i8 7, i8* [[TMP1]]
192 ; CHECK-NEXT: br label [[RETURN]]
194 ; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i8* [ [[TMP1]], [[IF_END]] ], [ null, [[ENTRY:%.*]] ]
195 ; CHECK-NEXT: ret i8* [[RETVAL_0]]
198 %1 = call i8* @func(i64 0)
199 %null_check = icmp eq i8* %1, null
200 br i1 %null_check, label %return, label %if.end
207 %retval.0 = phi i8* [ %1, %if.end ], [ null, %entry ]