From 3eb4f7e2dd98038f94e45d1c45ccff49e6659c87 Mon Sep 17 00:00:00 2001 From: Bob Wilson Date: Fri, 29 Jan 2010 19:19:08 +0000 Subject: Improve isSafeToLoadUnconditionally to recognize that GEPs with constant indices are safe if the result is known to be within the bounds of the underlying object. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@94829 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Utils/Local.cpp | 69 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 8 deletions(-) (limited to 'lib/Transforms/Utils/Local.cpp') diff --git a/lib/Transforms/Utils/Local.cpp b/lib/Transforms/Utils/Local.cpp index 92bdf2de44..f0097d0362 100644 --- a/lib/Transforms/Utils/Local.cpp +++ b/lib/Transforms/Utils/Local.cpp @@ -38,20 +38,73 @@ using namespace llvm; // Local analysis. // +/// getUnderlyingObjectWithOffset - Strip off up to MaxLookup GEPs and +/// bitcasts to get back to the underlying object being addressed, keeping +/// track of the offset in bytes from the GEPs relative to the result. +/// This is closely related to Value::getUnderlyingObject but is located +/// here to avoid making VMCore depend on TargetData. +static Value *getUnderlyingObjectWithOffset(Value *V, const TargetData *TD, + unsigned &ByteOffset, + unsigned MaxLookup = 6) { + if (!isa(V->getType())) + return V; + for (unsigned Count = 0; MaxLookup == 0 || Count < MaxLookup; ++Count) { + if (GEPOperator *GEP = dyn_cast(V)) { + if (!GEP->hasAllConstantIndices()) + return V; + SmallVector Indices(GEP->op_begin() + 1, GEP->op_end()); + ByteOffset += TD->getIndexedOffset(GEP->getPointerOperandType(), + &Indices[0], Indices.size()); + V = GEP->getPointerOperand(); + } else if (Operator::getOpcode(V) == Instruction::BitCast) { + V = cast(V)->getOperand(0); + } else if (GlobalAlias *GA = dyn_cast(V)) { + if (GA->mayBeOverridden()) + return V; + V = GA->getAliasee(); + } else { + return V; + } + assert(isa(V->getType()) && "Unexpected operand type!"); + } + return V; +} + /// isSafeToLoadUnconditionally - Return true if we know that executing a load /// from this value cannot trap. If it is not obviously safe to load from the /// specified pointer, we do a quick local scan of the basic block containing /// ScanFrom, to determine if the address is already accessed. -bool llvm::isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom) { - // If it is an alloca it is always safe to load from. - if (isa(V)) return true; +bool llvm::isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom, + const TargetData *TD) { + unsigned ByteOffset = 0; + Value *Base = V; + if (TD) + Base = getUnderlyingObjectWithOffset(V, TD, ByteOffset); + + const Type *BaseType = 0; + if (const AllocaInst *AI = dyn_cast(Base)) + // If it is an alloca it is always safe to load from. + BaseType = AI->getAllocatedType(); + else if (const GlobalValue *GV = dyn_cast(Base)) { + // Global variables are safe to load from but their size cannot be + // guaranteed if they are overridden. + if (!isa(GV) && !GV->mayBeOverridden()) + BaseType = GV->getType()->getElementType(); + } - // If it is a global variable it is mostly safe to load from. - if (const GlobalValue *GV = dyn_cast(V)) - // Don't try to evaluate aliases. External weak GV can be null. - return !isa(GV) && !GV->hasExternalWeakLinkage(); + if (BaseType) { + if (!TD) + return true; // Loading directly from an alloca or global is OK. + if (BaseType->isSized()) { + // Check if the load is within the bounds of the underlying object. + const PointerType *AddrTy = cast(V->getType()); + unsigned LoadSize = TD->getTypeStoreSize(AddrTy->getElementType()); + if (ByteOffset + LoadSize <= TD->getTypeAllocSize(BaseType)) + return true; + } + } - // Otherwise, be a little bit agressive by scanning the local block where we + // Otherwise, be a little bit aggressive by scanning the local block where we // want to check to see if the pointer is already being loaded or stored // from/to. If so, the previous load or store would have already trapped, // so there is no harm doing an extra load (also, CSE will later eliminate -- cgit v1.2.3-18-g5258