@@ -7,7 +7,7 @@ declare void @bar(i8* %a, i8* nonnull %b)
7
7
8
8
define i1 @caller1 (i8* %x , i8* %y ) {
9
9
; CHECK-LABEL: @caller1(
10
- ; CHECK-NEXT: call void @bar(i8* %x , i8* %y )
10
+ ; CHECK-NEXT: call void @bar(i8* [[X:%.*]] , i8* [[Y:%.*]] )
11
11
; CHECK-NEXT: ret i1 false
12
12
;
13
13
call void @bar (i8* %x , i8* %y )
@@ -19,8 +19,8 @@ define i1 @caller1(i8* %x, i8* %y) {
19
19
20
20
define i1 @caller2 (i8* %x , i8* %y ) {
21
21
; CHECK-LABEL: @caller2(
22
- ; CHECK-NEXT: call void @bar(i8* %y , i8* %x )
23
- ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* %y , null
22
+ ; CHECK-NEXT: call void @bar(i8* [[Y:%.*]] , i8* [[X:%.*]] )
23
+ ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[Y]] , null
24
24
; CHECK-NEXT: ret i1 [[NULL_CHECK]]
25
25
;
26
26
call void @bar (i8* %y , i8* %x )
@@ -32,7 +32,7 @@ define i1 @caller2(i8* %x, i8* %y) {
32
32
33
33
define i1 @caller3 (i8* %x , i8* %y ) {
34
34
; CHECK-LABEL: @caller3(
35
- ; CHECK-NEXT: call void @bar(i8* %x , i8* %y )
35
+ ; CHECK-NEXT: call void @bar(i8* [[X:%.*]] , i8* [[Y:%.*]] )
36
36
; CHECK-NEXT: ret i1 true
37
37
;
38
38
call void @bar (i8* %x , i8* %y )
@@ -44,8 +44,8 @@ define i1 @caller3(i8* %x, i8* %y) {
44
44
45
45
define i1 @caller4 (i8* %x , i8* %y ) {
46
46
; CHECK-LABEL: @caller4(
47
- ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp ne i8* %y , null
48
- ; CHECK-NEXT: call void @bar(i8* %x , i8* %y )
47
+ ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp ne i8* [[Y:%.*]] , null
48
+ ; CHECK-NEXT: call void @bar(i8* [[X:%.*]] , i8* [[Y]] )
49
49
; CHECK-NEXT: ret i1 [[NULL_CHECK]]
50
50
;
51
51
%null_check = icmp ne i8* %y , null
@@ -57,12 +57,12 @@ define i1 @caller4(i8* %x, i8* %y) {
57
57
58
58
define i1 @caller5 (i8* %x , i8* %y ) {
59
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
60
+ ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[Y:%.*]] , null
61
+ ; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[T:%.*]] , label [[F:%.*]]
62
62
; CHECK: t:
63
63
; CHECK-NEXT: ret i1 [[NULL_CHECK]]
64
64
; CHECK: f:
65
- ; CHECK-NEXT: call void @bar(i8* %x , i8* %y )
65
+ ; CHECK-NEXT: call void @bar(i8* [[X:%.*]] , i8* [[Y]] )
66
66
; CHECK-NEXT: ret i1 [[NULL_CHECK]]
67
67
;
68
68
%null_check = icmp eq i8* %y , null
@@ -80,42 +80,135 @@ declare i32 @esfp(...)
80
80
81
81
define i1 @caller6 (i8* %x , i8* %y ) personality i8* bitcast (i32 (...)* @esfp to i8* ){
82
82
; CHECK-LABEL: @caller6(
83
- ; CHECK-NEXT: invoke void @bar(i8* %x , i8* nonnull %y )
84
- ; CHECK-NEXT: to label %cont unwind label %exc
83
+ ; CHECK-NEXT: invoke void @bar(i8* [[X:%.*]] , i8* nonnull [[Y:%.*]] )
84
+ ; CHECK-NEXT: to label [[CONT:%.*]] unwind label [[EXC:%.*]]
85
85
; CHECK: cont:
86
86
; CHECK-NEXT: ret i1 false
87
+ ; CHECK: exc:
88
+ ; CHECK-NEXT: [[LP:%.*]] = landingpad { i8*, i32 }
89
+ ; CHECK-NEXT: filter [0 x i8*] zeroinitializer
90
+ ; CHECK-NEXT: unreachable
87
91
;
88
92
invoke void @bar (i8* %x , i8* nonnull %y )
89
- to label %cont unwind label %exc
93
+ to label %cont unwind label %exc
90
94
91
95
cont:
92
96
%null_check = icmp eq i8* %y , null
93
97
ret i1 %null_check
94
98
95
99
exc:
96
100
%lp = landingpad { i8* , i32 }
97
- filter [0 x i8* ] zeroinitializer
101
+ filter [0 x i8* ] zeroinitializer
98
102
unreachable
99
103
}
100
104
101
105
declare i8* @returningPtr (i8* returned %p )
102
106
103
107
define i1 @nonnullReturnTest (i8* nonnull %x ) {
104
108
; CHECK-LABEL: @nonnullReturnTest(
105
- ; CHECK-NEXT: %x2 = call i8* @returningPtr(i8* %x )
109
+ ; CHECK-NEXT: [[X2:%.*]] = call i8* @returningPtr(i8* [[X:%.*]] )
106
110
; CHECK-NEXT: ret i1 false
111
+ ;
107
112
%x2 = call i8* @returningPtr (i8* %x )
108
113
%null_check = icmp eq i8* %x2 , null
109
114
ret i1 %null_check
110
115
}
111
116
112
117
define i1 @unknownReturnTest (i8* %x ) {
113
118
; CHECK-LABEL: @unknownReturnTest(
114
- ; CHECK-NEXT: %x2 = call i8* @returningPtr(i8* %x)
115
- ; CHECK-NEXT: %null_check = icmp eq i8* %x2, null
116
- ; CHECK-NEXT: ret i1 %null_check
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]]
122
+ ;
117
123
%x2 = call i8* @returningPtr (i8* %x )
118
124
%null_check = icmp eq i8* %x2 , null
119
125
ret i1 %null_check
120
126
}
121
127
128
+ ; TODO: Make sure that if load/store happened, the pointer is nonnull.
129
+
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: [[TMP2:%.*]] = icmp eq i32* [[TMP0]], null
134
+ ; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 1, i32 2
135
+ ; CHECK-NEXT: ret i32 [[TMP3]]
136
+ ;
137
+ store i32 123 , i32* %0 , align 4
138
+ %2 = icmp eq i32* %0 , null
139
+ %3 = select i1 %2 , i32 1 , i32 2
140
+ ret i32 %3
141
+ }
142
+
143
+ define i32 @test_null_after_load (i32* %0 ) {
144
+ ; CHECK-LABEL: @test_null_after_load(
145
+ ; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP0:%.*]], align 4
146
+ ; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32* [[TMP0]], null
147
+ ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 1
148
+ ; CHECK-NEXT: ret i32 [[TMP4]]
149
+ ;
150
+ %2 = load i32 , i32* %0 , align 4
151
+ %3 = icmp eq i32* %0 , null
152
+ %4 = select i1 %3 , i32 %2 , i32 1
153
+ ret i32 %4
154
+ }
155
+
156
+ ; Make sure that different address space does not affect null pointer check.
157
+
158
+ define i32 @test_null_after_store_addrspace (i32 addrspace (1 )* %0 ) {
159
+ ; CHECK-LABEL: @test_null_after_store_addrspace(
160
+ ; CHECK-NEXT: store i32 123, i32 addrspace(1)* [[TMP0:%.*]], align 4
161
+ ; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 addrspace(1)* [[TMP0]], null
162
+ ; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i32 1, i32 2
163
+ ; CHECK-NEXT: ret i32 [[TMP3]]
164
+ ;
165
+ store i32 123 , i32 addrspace (1 )* %0 , align 4
166
+ %2 = icmp eq i32 addrspace (1 )* %0 , null
167
+ %3 = select i1 %2 , i32 1 , i32 2
168
+ ret i32 %3
169
+ }
170
+
171
+ define i32 @test_null_after_load_addrspace (i32 addrspace (1 )* %0 ) {
172
+ ; CHECK-LABEL: @test_null_after_load_addrspace(
173
+ ; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32 addrspace(1)* [[TMP0:%.*]], align 4
174
+ ; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 addrspace(1)* [[TMP0]], null
175
+ ; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i32 [[TMP2]], i32 1
176
+ ; CHECK-NEXT: ret i32 [[TMP4]]
177
+ ;
178
+ ; CHECK-NEXT ret i32 %4
179
+ %2 = load i32 , i32 addrspace (1 )* %0 , align 4
180
+ %3 = icmp eq i32 addrspace (1 )* %0 , null
181
+ %4 = select i1 %3 , i32 %2 , i32 1
182
+ ret i32 %4
183
+ }
184
+
185
+ ; Make sure if store happened after the check, nullptr check is not removed.
186
+
187
+ declare i8* @func (i64 )
188
+
189
+ define i8* @test_load_store_after_check (i8* %0 ) {
190
+ ; CHECK-LABEL: @test_load_store_after_check(
191
+ ; CHECK-NEXT: entry:
192
+ ; CHECK-NEXT: [[TMP1:%.*]] = call i8* @func(i64 0)
193
+ ; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i8* [[TMP1]], null
194
+ ; CHECK-NEXT: br i1 [[NULL_CHECK]], label [[RETURN:%.*]], label [[IF_END:%.*]]
195
+ ; CHECK: if.end:
196
+ ; CHECK-NEXT: store i8 7, i8* [[TMP1]]
197
+ ; CHECK-NEXT: br label [[RETURN]]
198
+ ; CHECK: return:
199
+ ; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i8* [ [[TMP1]], [[IF_END]] ], [ null, [[ENTRY:%.*]] ]
200
+ ; CHECK-NEXT: ret i8* [[RETVAL_0]]
201
+ ;
202
+ entry:
203
+ %1 = call i8* @func (i64 0 )
204
+ %null_check = icmp eq i8* %1 , null
205
+ br i1 %null_check , label %return , label %if.end
206
+
207
+ if.end:
208
+ store i8 7 , i8* %1
209
+ br label %return
210
+
211
+ return:
212
+ %retval.0 = phi i8* [ %1 , %if.end ], [ null , %entry ]
213
+ ret i8* %retval.0
214
+ }
0 commit comments