1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt %s -instsimplify -S | FileCheck %s
3
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.
9
10define i1 @t0(i8* nonnull %base, i64 %offset) {
11; CHECK-LABEL: @t0(
12; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
16;
17  %base_int = ptrtoint i8* %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
23}
24define i1 @t1(i8* nonnull %base, i64 %offset) {
25; CHECK-LABEL: @t1(
26; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
30;
31  %base_int = ptrtoint i8* %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
37}
38define i1 @t2(i8* nonnull %base, i64 %offset) {
39; CHECK-LABEL: @t2(
40; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
44;
45  %base_int = ptrtoint i8* %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
51}
52define i1 @t3(i8* nonnull %base, i64 %offset) {
53; CHECK-LABEL: @t3(
54; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
58;
59  %base_int = ptrtoint i8* %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
65}
66
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.
69
70define i1 @t4(i8* nonnull %base, i64 %offset) {
71; CHECK-LABEL: @t4(
72; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
76;
77  %base_int = ptrtoint i8* %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
83}
84define i1 @t5(i8* nonnull %base, i64 %offset) {
85; CHECK-LABEL: @t5(
86; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
90;
91  %base_int = ptrtoint i8* %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
97}
98define i1 @t6(i8* nonnull %base, i64 %offset) {
99; CHECK-LABEL: @t6(
100; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
104;
105  %base_int = ptrtoint i8* %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
111}
112define i1 @t7(i8* nonnull %base, i64 %offset) {
113; CHECK-LABEL: @t7(
114; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
118;
119  %base_int = ptrtoint i8* %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
125}
126
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.
130
131define i1 @t8(i8* nonnull %base, i64 %offset) {
132; CHECK-LABEL: @t8(
133; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
137;
138  %base_int = ptrtoint i8* %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
144}
145define i1 @t9(i8* nonnull %base, i64 %offset) {
146; CHECK-LABEL: @t9(
147; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
151;
152  %base_int = ptrtoint i8* %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
158}
159define i1 @t10(i8* nonnull %base, i64 %offset) {
160; CHECK-LABEL: @t10(
161; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
165;
166  %base_int = ptrtoint i8* %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
172}
173define i1 @t11(i8* nonnull %base, i64 %offset) {
174; CHECK-LABEL: @t11(
175; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
179;
180  %base_int = ptrtoint i8* %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
186}
187
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.
190
191define i1 @t12(i8* nonnull %base, i64 %offset) {
192; CHECK-LABEL: @t12(
193; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
197;
198  %base_int = ptrtoint i8* %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
204}
205define i1 @t13(i8* nonnull %base, i64 %offset) {
206; CHECK-LABEL: @t13(
207; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
211;
212  %base_int = ptrtoint i8* %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
218}
219define i1 @t14(i8* nonnull %base, i64 %offset) {
220; CHECK-LABEL: @t14(
221; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
225;
226  %base_int = ptrtoint i8* %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
232}
233define i1 @t15(i8* nonnull %base, i64 %offset) {
234; CHECK-LABEL: @t15(
235; CHECK-NEXT:    [[BASE_INT:%.*]] = ptrtoint i8* [[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]]
239;
240  %base_int = ptrtoint i8* %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
246}
247
248declare void @llvm.assume(i1)
249define 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]]
256;
257  %cmp = icmp slt i64 %base, 0
258  call void @llvm.assume(i1 %cmp)
259
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
265}
266