[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