Minor refactoring of GEP handling in isDereferenceablePointer
authorArtur Pilipenko <apilipenko@azulsystems.com>
Mon, 8 Jun 2015 11:58:13 +0000 (11:58 +0000)
committerArtur Pilipenko <apilipenko@azulsystems.com>
Mon, 8 Jun 2015 11:58:13 +0000 (11:58 +0000)
For GEP instructions isDereferenceablePointer checks that all indices are constant and within bounds. Replace this index calculation logic to a call to accumulateConstantOffset. Separated from the http://reviews.llvm.org/D9791

Reviewed By: sanjoy

Differential Revision: http://reviews.llvm.org/D9874

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239299 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/ValueTracking.cpp
test/Analysis/ValueTracking/memory-dereferenceable.ll

index a55712c6296a2bf0f5875ed323de495b563f19f7..c4f046340fce4881b78ef4fb343162851a011985 100644 (file)
@@ -2967,38 +2967,25 @@ static bool isDereferenceablePointer(const Value *V, const DataLayout &DL,
 
   // For GEPs, determine if the indexing lands within the allocated object.
   if (const GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
+    Type *VTy = GEP->getType();
+    Type *Ty = VTy->getPointerElementType();
+    const Value *Base = GEP->getPointerOperand();
+
     // Conservatively require that the base pointer be fully dereferenceable.
-    if (!Visited.insert(GEP->getOperand(0)).second)
+    if (!Visited.insert(Base).second)
       return false;
-    if (!isDereferenceablePointer(GEP->getOperand(0), DL, CtxI,
+    if (!isDereferenceablePointer(Base, DL, CtxI,
                                   DT, TLI, Visited))
       return false;
-    // Check the indices.
-    gep_type_iterator GTI = gep_type_begin(GEP);
-    for (User::const_op_iterator I = GEP->op_begin()+1,
-         E = GEP->op_end(); I != E; ++I) {
-      Value *Index = *I;
-      Type *Ty = *GTI++;
-      // Struct indices can't be out of bounds.
-      if (isa<StructType>(Ty))
-        continue;
-      ConstantInt *CI = dyn_cast<ConstantInt>(Index);
-      if (!CI)
-        return false;
-      // Zero is always ok.
-      if (CI->isZero())
-        continue;
-      // Check to see that it's within the bounds of an array.
-      ArrayType *ATy = dyn_cast<ArrayType>(Ty);
-      if (!ATy)
-        return false;
-      if (CI->getValue().getActiveBits() > 64)
-        return false;
-      if (CI->getZExtValue() >= ATy->getNumElements())
-        return false;
-    }
-    // Indices check out; this is dereferenceable.
-    return true;
+    
+    APInt Offset(DL.getPointerTypeSizeInBits(VTy), 0);
+    if (!GEP->accumulateConstantOffset(DL, Offset))
+      return false;
+    
+    // Check if the load is within the bounds of the underlying object.
+    uint64_t LoadSize = DL.getTypeStoreSize(Ty);
+    Type *BaseType = Base->getType()->getPointerElementType();
+    return (Offset + LoadSize).ule(DL.getTypeAllocSize(BaseType));
   }
 
   // For gc.relocate, look through relocations
index dae64d7acc228aa1484e9999669fd83a0cfe4fa3..f49f4f77f404f7998bf27eecdee09dc9a7bf3099 100644 (file)
@@ -10,6 +10,9 @@ declare zeroext i1 @return_i1()
 @globalstr = global [6 x i8] c"hello\00"
 @globali32ptr = external global i32*
 
+%struct.A = type { [8 x i8], [5 x i8] }
+@globalstruct = external global %struct.A
+
 define void @test(i32 addrspace(1)* dereferenceable(8) %dparam) gc "statepoint-example" {
 ; CHECK: The following are dereferenceable:
 ; CHECK: %globalptr
@@ -22,6 +25,8 @@ define void @test(i32 addrspace(1)* dereferenceable(8) %dparam) gc "statepoint-e
 ; CHECK-NOT: %d2_load
 ; CHECK-NOT: %d_or_null_load
 ; CHECK: %d_or_null_non_null_load
+; CHECK: %within_allocation
+; CHECK-NOT: %outside_allocation
 entry:
     %globalptr = getelementptr inbounds [6 x i8], [6 x i8]* @globalstr, i32 0, i32 0
     %load1 = load i8, i8* %globalptr
@@ -54,6 +59,14 @@ entry:
     %d_or_null_non_null_load = load i32*, i32** @globali32ptr, !nonnull !2, !dereferenceable_or_null !0
     %load10 = load i32, i32* %d_or_null_non_null_load
 
+    ; It's OK to overrun static array size as long as we stay within underlying object size
+    %within_allocation = getelementptr inbounds %struct.A, %struct.A* @globalstruct, i64 0, i32 0, i64 10
+    %load11 = load i8, i8* %within_allocation
+
+    ; GEP is outside the underlying object size
+    %outside_allocation = getelementptr inbounds %struct.A, %struct.A* @globalstruct, i64 0, i32 1, i64 10
+    %load12 = load i8, i8* %outside_allocation
+
     ret void
 }