[llvm-commits] [PATCH] Add support to ValueTracking for determining that a pointer is non-null by virtue of inbounds GEPs that preclude a null pointer.
Chandler Carruth
chandlerc at gmail.com
Tue Dec 4 05:41:58 PST 2012
Hi bkramer,
This is a very common pattern in the code generated by std::vector and other standard library routines which use allocators that test for null pervasively.
http://llvm-reviews.chandlerc.com/D160
Files:
lib/Analysis/ValueTracking.cpp
test/Transforms/InstSimplify/compare.ll
Index: lib/Analysis/ValueTracking.cpp
===================================================================
--- lib/Analysis/ValueTracking.cpp
+++ lib/Analysis/ValueTracking.cpp
@@ -862,6 +862,51 @@
return false;
}
+/// \brief Test whether a GEP's result is known to be non-null.
+///
+/// This routine relies on the GEP being an inbounds GEP in address space zero,
+/// and leverages that to demonstrate that it cannot start or end at a null
+/// pointer while remaining inbounds due to non-zero offsets being applied
+/// during the GEP.
+static bool isGEPKnownNonNull(GEPOperator *GEP, const DataLayout *DL,
+ unsigned Depth) {
+ if (!GEP->isInBounds() || GEP->getPointerAddressSpace() != 0)
+ return false;
+
+ // If the base poniter is non-null, we cannot walk to a null address with an
+ // inbounds GEP in address space zero.
+ if (isKnownNonZero(GEP->getPointerOperand(), DL, Depth))
+ return true;
+
+ // Walk the GEP operands and see if there are any non-zero operands. If
+ // so, then the GEP cannot produce a null pointer, as doing so would
+ // inherently violate the inbounds contract within address space zero.
+ for (gep_type_iterator GTI = gep_type_begin(GEP), GTE = gep_type_end(GEP);
+ GTI != GTE; ++GTI) {
+ ConstantInt *OpC = dyn_cast<ConstantInt>(GTI.getOperand());
+ if (!OpC && Depth >= MaxDepth)
+ return false;
+
+ // If we have a non-zero constant or a known-non-zero value, we can try to
+ // reason about the GEP.
+ if ((!OpC && !isKnownNonZero(GTI.getOperand(), DL, Depth++)) ||
+ OpC->isZero())
+ continue;
+
+ if (StructType *STy = dyn_cast<StructType>(*GTI)) {
+ unsigned ElementIdx = OpC ? OpC->getZExtValue() : 1;
+ const StructLayout *SL = DL->getStructLayout(STy);
+ uint64_t ElementOffset = SL->getElementOffset(ElementIdx);
+ if (ElementOffset > 0)
+ return true;
+ } else if (DL->getTypeAllocSize(GTI.getIndexedType()) > 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/// isKnownNonZero - Return true if the given value is known to be non-zero
/// when defined. For vectors return true if every element is known to be
/// non-zero when defined. Supports values with integer or pointer type and
@@ -881,6 +926,13 @@
if (Depth++ >= MaxDepth)
return false;
+ // Check for pointer simplifications.
+ if (V->getType()->isPointerTy()) {
+ if (GEPOperator *GEP = dyn_cast<GEPOperator>(V))
+ if (isGEPKnownNonNull(GEP, TD, Depth))
+ return true;
+ }
+
unsigned BitWidth = getBitWidth(V->getType(), TD);
// X | Y != 0 if X != 0 or Y != 0.
Index: test/Transforms/InstSimplify/compare.ll
===================================================================
--- test/Transforms/InstSimplify/compare.ll
+++ test/Transforms/InstSimplify/compare.ll
@@ -165,6 +165,35 @@
ret i1 %cmp
}
+define i1 @gep13(i8* %ptr) {
+; CHECK: @gep13
+; We can prove this GEP is non-null because it is inbounds.
+ %x = getelementptr inbounds i8* %ptr, i32 1
+ %cmp = icmp eq i8* %x, null
+ ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
+define i1 @gep14({ {}, i8 }* %ptr) {
+; CHECK: @gep14
+; We can't simplify this because the offset of one in the GEP actually doesn't
+; move the pointer.
+ %x = getelementptr inbounds { {}, i8 }* %ptr, i32 0, i32 1
+ %cmp = icmp eq i8* %x, null
+ ret i1 %cmp
+; CHECK-NOT: ret i1 false
+}
+
+define i1 @gep15({ {}, [4 x {i8, i8}]}* %ptr, i32 %y) {
+; CHECK: @gep15
+; We can prove this GEP is non-null even though there is a user value, as we
+; would necessarily violate inbounds on one side or the other.
+ %x = getelementptr inbounds { {}, [4 x {i8, i8}]}* %ptr, i32 0, i32 1, i32 %y, i32 1
+ %cmp = icmp eq i8* %x, null
+ ret i1 %cmp
+; CHECK-NEXT: ret i1 false
+}
+
define i1 @zext(i32 %x) {
; CHECK: @zext
%e1 = zext i32 %x to i64
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D160.1.patch
Type: text/x-patch
Size: 3872 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20121204/43b19d15/attachment.bin>
More information about the llvm-commits
mailing list