Skip to content

Commit 8206364

Browse files
nikicAlexisPerry
authored andcommitted
[ValueTracking] Support gep nuw in isKnownNonZero()
gep nuw can be null if and only if both the base pointer and offset are null. Unlike the inbounds case this does not depend on whether the null pointer is valid. Proofs: https://alive2.llvm.org/ce/z/PLoqK5
1 parent e17889f commit 8206364

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,8 +2293,11 @@ static bool isGEPKnownNonNull(const GEPOperator *GEP, unsigned Depth,
22932293
if (const Instruction *I = dyn_cast<Instruction>(GEP))
22942294
F = I->getFunction();
22952295

2296-
if (!GEP->isInBounds() ||
2297-
NullPointerIsDefined(F, GEP->getPointerAddressSpace()))
2296+
// If the gep is nuw or inbounds with invalid null pointer, then the GEP
2297+
// may be null iff the base pointer is null and the offset is zero.
2298+
if (!GEP->hasNoUnsignedWrap() &&
2299+
!(GEP->isInBounds() &&
2300+
!NullPointerIsDefined(F, GEP->getPointerAddressSpace())))
22982301
return false;
22992302

23002303
// FIXME: Support vector-GEPs.

llvm/test/Transforms/InstSimplify/compare.ll

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,61 @@ define i1 @gep13_no_null_opt(ptr %ptr) #0 {
207207
ret i1 %cmp
208208
}
209209

210+
; We can prove this GEP is non-null because it is nuw.
211+
define i1 @gep_nuw_not_null(ptr %ptr) {
212+
; CHECK-LABEL: @gep_nuw_not_null(
213+
; CHECK-NEXT: ret i1 false
214+
;
215+
%x = getelementptr nuw i8, ptr %ptr, i32 1
216+
%cmp = icmp eq ptr %x, null
217+
ret i1 %cmp
218+
}
219+
220+
; Unlike the inbounds case, this holds even if the null pointer is valid.
221+
define i1 @gep_nuw_null_pointer_valid(ptr %ptr) null_pointer_is_valid {
222+
; CHECK-LABEL: @gep_nuw_null_pointer_valid(
223+
; CHECK-NEXT: ret i1 false
224+
;
225+
%x = getelementptr nuw i8, ptr %ptr, i32 1
226+
%cmp = icmp eq ptr %x, null
227+
ret i1 %cmp
228+
}
229+
230+
; If the base pointer is non-null, the offset doesn't matter.
231+
define i1 @gep_nuw_maybe_zero_offset(ptr nonnull %ptr, i32 %offset) {
232+
; CHECK-LABEL: @gep_nuw_maybe_zero_offset(
233+
; CHECK-NEXT: ret i1 false
234+
;
235+
%x = getelementptr nuw i8, ptr %ptr, i32 %offset
236+
%cmp = icmp eq ptr %x, null
237+
ret i1 %cmp
238+
}
239+
240+
; We can not prove non-null if both the base pointer may be null and the
241+
; offset zero.
242+
define i1 @gep13_nuw_maybe_zero_offset(ptr %ptr, i32 %offset) {
243+
; CHECK-LABEL: @gep13_nuw_maybe_zero_offset(
244+
; CHECK-NEXT: [[X:%.*]] = getelementptr nuw i8, ptr [[PTR:%.*]], i32 [[OFFSET:%.*]]
245+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
246+
; CHECK-NEXT: ret i1 [[CMP]]
247+
;
248+
%x = getelementptr nuw i8, ptr %ptr, i32 %offset
249+
%cmp = icmp eq ptr %x, null
250+
ret i1 %cmp
251+
}
252+
253+
; For gep nusw we don't have any non-null information.
254+
define i1 @gep_nusw_may_be_null(ptr %ptr) {
255+
; CHECK-LABEL: @gep_nusw_may_be_null(
256+
; CHECK-NEXT: [[X:%.*]] = getelementptr nusw i8, ptr [[PTR:%.*]], i32 1
257+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
258+
; CHECK-NEXT: ret i1 [[CMP]]
259+
;
260+
%x = getelementptr nusw i8, ptr %ptr, i32 1
261+
%cmp = icmp eq ptr %x, null
262+
ret i1 %cmp
263+
}
264+
210265
define i1 @gep14(ptr %ptr) {
211266
; CHECK-LABEL: @gep14(
212267
; CHECK-NEXT: [[X:%.*]] = getelementptr inbounds { {}, i8 }, ptr [[PTR:%.*]], i32 0, i32 1

0 commit comments

Comments
 (0)