1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt %s -passes=instsimplify -S | FileCheck %s
4 ; Here we have add some offset to a non-null pointer,
5 ; and check that the result does not overflow and is not a null pointer.
6 ; But since the base pointer is already non-null, and we check for overflow,
7 ; that will already catch the get null pointer,
8 ; so the separate null check is redundant and can be dropped.
10 define i1 @t0(ptr nonnull %base, i64 %offset) {
12 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
13 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
14 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE_INT]]
15 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
17 %base_int = ptrtoint ptr %base to i64
18 %adjusted = add i64 %base_int, %offset
19 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
20 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base_int
21 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment
24 define i1 @t1(ptr nonnull %base, i64 %offset) {
26 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
27 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
28 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ule i64 [[BASE_INT]], [[ADJUSTED]]
29 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
31 %base_int = ptrtoint ptr %base to i64
32 %adjusted = add i64 %base_int, %offset
33 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
34 %no_overflow_during_adjustment = icmp ule i64 %base_int, %adjusted ; swapped
35 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment
38 define i1 @t2(ptr nonnull %base, i64 %offset) {
40 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
41 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
42 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE_INT]]
43 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
45 %base_int = ptrtoint ptr %base to i64
46 %adjusted = add i64 %base_int, %offset
47 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
48 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base_int
49 %res = and i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped
52 define i1 @t3(ptr nonnull %base, i64 %offset) {
54 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
55 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
56 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ule i64 [[BASE_INT]], [[ADJUSTED]]
57 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
59 %base_int = ptrtoint ptr %base to i64
60 %adjusted = add i64 %base_int, %offset
61 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
62 %no_overflow_during_adjustment = icmp ule i64 %base_int, %adjusted ; swapped
63 %res = and i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped
67 ; If the joining operator was 'or', i.e. we check that either we produced non-null
68 ; pointer, or no overflow happened, then the overflow check itself is redundant.
70 define i1 @t4(ptr nonnull %base, i64 %offset) {
72 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
73 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
74 ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0
75 ; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]]
77 %base_int = ptrtoint ptr %base to i64
78 %adjusted = add i64 %base_int, %offset
79 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
80 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base_int
81 %res = or i1 %non_null_after_adjustment, %no_overflow_during_adjustment
84 define i1 @t5(ptr nonnull %base, i64 %offset) {
86 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
87 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
88 ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0
89 ; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]]
91 %base_int = ptrtoint ptr %base to i64
92 %adjusted = add i64 %base_int, %offset
93 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
94 %no_overflow_during_adjustment = icmp ule i64 %base_int, %adjusted ; swapped
95 %res = or i1 %non_null_after_adjustment, %no_overflow_during_adjustment
98 define i1 @t6(ptr nonnull %base, i64 %offset) {
100 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
101 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
102 ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0
103 ; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]]
105 %base_int = ptrtoint ptr %base to i64
106 %adjusted = add i64 %base_int, %offset
107 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
108 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base_int
109 %res = or i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped
112 define i1 @t7(ptr nonnull %base, i64 %offset) {
114 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
115 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
116 ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp ne i64 [[ADJUSTED]], 0
117 ; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]]
119 %base_int = ptrtoint ptr %base to i64
120 %adjusted = add i64 %base_int, %offset
121 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
122 %no_overflow_during_adjustment = icmp ule i64 %base_int, %adjusted ; swapped
123 %res = or i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped
127 ; Or, we could be checking the reverse condition, that we either get null pointer,
128 ; or overflow happens, then again, the standalone null check is redundant and
131 define i1 @t8(ptr nonnull %base, i64 %offset) {
133 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
134 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
135 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE_INT]]
136 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
138 %base_int = ptrtoint ptr %base to i64
139 %adjusted = add i64 %base_int, %offset
140 %non_null_after_adjustment = icmp eq i64 %adjusted, 0
141 %no_overflow_during_adjustment = icmp ult i64 %adjusted, %base_int
142 %res = or i1 %non_null_after_adjustment, %no_overflow_during_adjustment
145 define i1 @t9(ptr nonnull %base, i64 %offset) {
147 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
148 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
149 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ugt i64 [[BASE_INT]], [[ADJUSTED]]
150 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
152 %base_int = ptrtoint ptr %base to i64
153 %adjusted = add i64 %base_int, %offset
154 %non_null_after_adjustment = icmp eq i64 %adjusted, 0
155 %no_overflow_during_adjustment = icmp ugt i64 %base_int, %adjusted ; swapped
156 %res = or i1 %non_null_after_adjustment, %no_overflow_during_adjustment
159 define i1 @t10(ptr nonnull %base, i64 %offset) {
161 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
162 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
163 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE_INT]]
164 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
166 %base_int = ptrtoint ptr %base to i64
167 %adjusted = add i64 %base_int, %offset
168 %non_null_after_adjustment = icmp eq i64 %adjusted, 0
169 %no_overflow_during_adjustment = icmp ult i64 %adjusted, %base_int
170 %res = or i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped
173 define i1 @t11(ptr nonnull %base, i64 %offset) {
175 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
176 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
177 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp ugt i64 [[BASE_INT]], [[ADJUSTED]]
178 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
180 %base_int = ptrtoint ptr %base to i64
181 %adjusted = add i64 %base_int, %offset
182 %non_null_after_adjustment = icmp eq i64 %adjusted, 0
183 %no_overflow_during_adjustment = icmp ugt i64 %base_int, %adjusted ; swapped
184 %res = or i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped
188 ; If the joining operator was 'and', i.e. we check that we both get null pointer
189 ; AND overflow happens, then the overflow check is redundant.
191 define i1 @t12(ptr nonnull %base, i64 %offset) {
193 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
194 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
195 ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0
196 ; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]]
198 %base_int = ptrtoint ptr %base to i64
199 %adjusted = add i64 %base_int, %offset
200 %non_null_after_adjustment = icmp eq i64 %adjusted, 0
201 %no_overflow_during_adjustment = icmp ult i64 %adjusted, %base_int
202 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment
205 define i1 @t13(ptr nonnull %base, i64 %offset) {
207 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
208 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
209 ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0
210 ; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]]
212 %base_int = ptrtoint ptr %base to i64
213 %adjusted = add i64 %base_int, %offset
214 %non_null_after_adjustment = icmp eq i64 %adjusted, 0
215 %no_overflow_during_adjustment = icmp ugt i64 %base_int, %adjusted ; swapped
216 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment
219 define i1 @t14(ptr nonnull %base, i64 %offset) {
221 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
222 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
223 ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0
224 ; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]]
226 %base_int = ptrtoint ptr %base to i64
227 %adjusted = add i64 %base_int, %offset
228 %non_null_after_adjustment = icmp eq i64 %adjusted, 0
229 %no_overflow_during_adjustment = icmp ult i64 %adjusted, %base_int
230 %res = and i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped
233 define i1 @t15(ptr nonnull %base, i64 %offset) {
235 ; CHECK-NEXT: [[BASE_INT:%.*]] = ptrtoint ptr [[BASE:%.*]] to i64
236 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE_INT]], [[OFFSET:%.*]]
237 ; CHECK-NEXT: [[NON_NULL_AFTER_ADJUSTMENT:%.*]] = icmp eq i64 [[ADJUSTED]], 0
238 ; CHECK-NEXT: ret i1 [[NON_NULL_AFTER_ADJUSTMENT]]
240 %base_int = ptrtoint ptr %base to i64
241 %adjusted = add i64 %base_int, %offset
242 %non_null_after_adjustment = icmp eq i64 %adjusted, 0
243 %no_overflow_during_adjustment = icmp ugt i64 %base_int, %adjusted ; swapped
244 %res = and i1 %no_overflow_during_adjustment, %non_null_after_adjustment ; swapped
248 declare void @llvm.assume(i1)
249 define i1 @t16(i64 %base, i64 %offset) {
251 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[BASE:%.*]], 0
252 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
253 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i64 [[BASE]], [[OFFSET:%.*]]
254 ; CHECK-NEXT: [[NO_OVERFLOW_DURING_ADJUSTMENT:%.*]] = icmp uge i64 [[ADJUSTED]], [[BASE]]
255 ; CHECK-NEXT: ret i1 [[NO_OVERFLOW_DURING_ADJUSTMENT]]
257 %cmp = icmp slt i64 %base, 0
258 call void @llvm.assume(i1 %cmp)
260 %adjusted = add i64 %base, %offset
261 %non_null_after_adjustment = icmp ne i64 %adjusted, 0
262 %no_overflow_during_adjustment = icmp uge i64 %adjusted, %base
263 %res = and i1 %non_null_after_adjustment, %no_overflow_during_adjustment