From: Artur Pilipenko Date: Mon, 8 Jun 2015 11:58:13 +0000 (+0000) Subject: Minor refactoring of GEP handling in isDereferenceablePointer X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=1328b67dd1faf6edbe06bcf7189cc86db9f619cb;p=oota-llvm.git Minor refactoring of GEP handling in isDereferenceablePointer 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 --- diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index a55712c6296..c4f046340fc 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -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(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(Ty)) - continue; - ConstantInt *CI = dyn_cast(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(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 diff --git a/test/Analysis/ValueTracking/memory-dereferenceable.ll b/test/Analysis/ValueTracking/memory-dereferenceable.ll index dae64d7acc2..f49f4f77f40 100644 --- a/test/Analysis/ValueTracking/memory-dereferenceable.ll +++ b/test/Analysis/ValueTracking/memory-dereferenceable.ll @@ -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 }