Follow up to d0858bffa11, add missing REQUIRES x86
[llvm-project.git] / llvm / test / Transforms / InstSimplify / redundant-null-check-in-uadd_with_overflow-of-nonnull-ptr.ll
blob6976e31c2c9fb55a2059ad6efc19b2c606ba9ee7
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) {
11 ; CHECK-LABEL: @t0(
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
22   ret i1 %res
24 define i1 @t1(ptr nonnull %base, i64 %offset) {
25 ; CHECK-LABEL: @t1(
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
36   ret i1 %res
38 define i1 @t2(ptr nonnull %base, i64 %offset) {
39 ; CHECK-LABEL: @t2(
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
50   ret i1 %res
52 define i1 @t3(ptr nonnull %base, i64 %offset) {
53 ; CHECK-LABEL: @t3(
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
64   ret i1 %res
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) {
71 ; CHECK-LABEL: @t4(
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
82   ret i1 %res
84 define i1 @t5(ptr nonnull %base, i64 %offset) {
85 ; CHECK-LABEL: @t5(
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
96   ret i1 %res
98 define i1 @t6(ptr nonnull %base, i64 %offset) {
99 ; CHECK-LABEL: @t6(
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
110   ret i1 %res
112 define i1 @t7(ptr nonnull %base, i64 %offset) {
113 ; CHECK-LABEL: @t7(
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
124   ret i1 %res
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
129 ; can be dropped.
131 define i1 @t8(ptr nonnull %base, i64 %offset) {
132 ; CHECK-LABEL: @t8(
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
143   ret i1 %res
145 define i1 @t9(ptr nonnull %base, i64 %offset) {
146 ; CHECK-LABEL: @t9(
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
157   ret i1 %res
159 define i1 @t10(ptr nonnull %base, i64 %offset) {
160 ; CHECK-LABEL: @t10(
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
171   ret i1 %res
173 define i1 @t11(ptr nonnull %base, i64 %offset) {
174 ; CHECK-LABEL: @t11(
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
185   ret i1 %res
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) {
192 ; CHECK-LABEL: @t12(
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
203   ret i1 %res
205 define i1 @t13(ptr nonnull %base, i64 %offset) {
206 ; CHECK-LABEL: @t13(
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
217   ret i1 %res
219 define i1 @t14(ptr nonnull %base, i64 %offset) {
220 ; CHECK-LABEL: @t14(
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
231   ret i1 %res
233 define i1 @t15(ptr nonnull %base, i64 %offset) {
234 ; CHECK-LABEL: @t15(
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
245   ret i1 %res
248 declare void @llvm.assume(i1)
249 define i1 @t16(i64 %base, i64 %offset) {
250 ; CHECK-LABEL: @t16(
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
264   ret i1 %res