diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h index c5428726995e4..39ade20df53f6 100644 --- a/llvm/include/llvm/Analysis/MemoryBuiltins.h +++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h @@ -212,6 +212,10 @@ struct ObjectSizeOpts { /// object size in Size if successful, and false otherwise. In this context, by /// object we mean the region of memory starting at Ptr to the end of the /// underlying object pointed to by Ptr. +/// +/// WARNING: The object size returned is the allocation size. This does not +/// imply dereferenceability at site of use since the object may be freeed in +/// between. bool getObjectSize(const Value *Ptr, uint64_t &Size, const DataLayout &DL, const TargetLibraryInfo *TLI, ObjectSizeOpts Opts = {}); diff --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h index 5a7e90aeb0f64..e9a9acfd69baa 100644 --- a/llvm/include/llvm/IR/Value.h +++ b/llvm/include/llvm/IR/Value.h @@ -743,8 +743,13 @@ class Value { /// /// If CanBeNull is set by this function the pointer can either be null or be /// dereferenceable up to the returned number of bytes. + /// + /// IF CanBeFreed is true, the pointer is known to be dereferenceable at + /// point of definition only. Caller must prove that allocation is not + /// deallocated between point of definition and use. uint64_t getPointerDereferenceableBytes(const DataLayout &DL, - bool &CanBeNull) const; + bool &CanBeNull, + bool &CanBeFreed) const; /// Returns an alignment of the pointer value. /// diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp index 11fa4d2893e67..a8c5b9ca80e45 100644 --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -199,9 +199,11 @@ static uint64_t getMinimalExtentFrom(const Value &V, // If we have dereferenceability information we know a lower bound for the // extent as accesses for a lower offset would be valid. We need to exclude // the "or null" part if null is a valid pointer. - bool CanBeNull; - uint64_t DerefBytes = V.getPointerDereferenceableBytes(DL, CanBeNull); + bool CanBeNull, CanBeFreed; + uint64_t DerefBytes = + V.getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed); DerefBytes = (CanBeNull && NullIsValidLoc) ? 0 : DerefBytes; + DerefBytes = CanBeFreed ? 0 : DerefBytes; // If queried with a precise location size, we assume that location size to be // accessed, thus valid. if (LocSize.isPrecise()) diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp index b2fc6e603f9ea..cf5e53b26b5d8 100644 --- a/llvm/lib/Analysis/CaptureTracking.cpp +++ b/llvm/lib/Analysis/CaptureTracking.cpp @@ -68,8 +68,8 @@ bool CaptureTracker::isDereferenceableOrNull(Value *O, const DataLayout &DL) { if (auto *GEP = dyn_cast(O)) if (GEP->isInBounds()) return true; - bool CanBeNull; - return O->getPointerDereferenceableBytes(DL, CanBeNull); + bool CanBeNull, CanBeFreed; + return O->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed); } namespace { diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp index 88e4c723331ae..7279ed59c440a 100644 --- a/llvm/lib/Analysis/Loads.cpp +++ b/llvm/lib/Analysis/Loads.cpp @@ -67,10 +67,12 @@ static bool isDereferenceableAndAlignedPointer( Visited, MaxDepth); } - bool CheckForNonNull = false; + bool CheckForNonNull, CheckForFreed; APInt KnownDerefBytes(Size.getBitWidth(), - V->getPointerDereferenceableBytes(DL, CheckForNonNull)); - if (KnownDerefBytes.getBoolValue() && KnownDerefBytes.uge(Size)) + V->getPointerDereferenceableBytes(DL, CheckForNonNull, + CheckForFreed)); + if (KnownDerefBytes.getBoolValue() && KnownDerefBytes.uge(Size) && + !CheckForFreed) if (!CheckForNonNull || isKnownNonZero(V, DL, 0, nullptr, CtxI, DT)) { // As we recursed through GEPs to get here, we've incrementally checked // that each step advanced by a multiple of the alignment. If our base is diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index 92ffae18ae6fa..cfb91b55f707e 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -38,6 +38,11 @@ using namespace llvm; +static cl::opt UseDerefAtPointSemantics( + "use-dereferenceable-at-point-semantics", cl::Hidden, cl::init(false), + cl::desc("Deref attributes and metadata infer facts at definition only")); + + static cl::opt NonGlobalValueMaxNameSize( "non-global-value-max-name-size", cl::Hidden, cl::init(1024), cl::desc("Maximum size for the name of non-global values.")); @@ -724,11 +729,13 @@ Value::stripInBoundsOffsets(function_ref Func) const { } uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL, - bool &CanBeNull) const { + bool &CanBeNull, + bool &CanBeFreed) const { assert(getType()->isPointerTy() && "must be pointer"); uint64_t DerefBytes = 0; CanBeNull = false; + CanBeFreed = UseDerefAtPointSemantics; if (const Argument *A = dyn_cast(this)) { DerefBytes = A->getDereferenceableBytes(); if (DerefBytes == 0) { @@ -783,6 +790,7 @@ uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL, DerefBytes = DL.getTypeStoreSize(AI->getAllocatedType()).getKnownMinSize(); CanBeNull = false; + CanBeFreed = false; } } else if (auto *GV = dyn_cast(this)) { if (GV->getValueType()->isSized() && !GV->hasExternalWeakLinkage()) { @@ -790,6 +798,7 @@ uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL, // CanBeNull flag. DerefBytes = DL.getTypeStoreSize(GV->getValueType()).getFixedSize(); CanBeNull = false; + CanBeFreed = false; } } return DerefBytes; diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index 21fa11aadea8f..fa32a22059ac3 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -1750,8 +1750,9 @@ struct AANonNullImpl : AANonNull { AANonNull::initialize(A); - bool CanBeNull = true; - if (V.getPointerDereferenceableBytes(A.getDataLayout(), CanBeNull)) { + bool CanBeNull, CanBeFreed; + if (V.getPointerDereferenceableBytes(A.getDataLayout(), CanBeNull, + CanBeFreed)) { if (!CanBeNull) { indicateOptimisticFixpoint(); return; @@ -3548,10 +3549,10 @@ struct AADereferenceableImpl : AADereferenceable { const IRPosition &IRP = this->getIRPosition(); NonNullAA = &A.getAAFor(*this, IRP, DepClassTy::NONE); - bool CanBeNull; + bool CanBeNull, CanBeFreed; takeKnownDerefBytesMaximum( IRP.getAssociatedValue().getPointerDereferenceableBytes( - A.getDataLayout(), CanBeNull)); + A.getDataLayout(), CanBeNull, CanBeFreed)); bool IsFnInterface = IRP.isFnInterfaceKind(); Function *FnScope = IRP.getAnchorScope(); @@ -3661,8 +3662,9 @@ struct AADereferenceableFloating : AADereferenceableImpl { if (!Stripped && this == &AA) { // Use IR information if we did not strip anything. // TODO: track globally. - bool CanBeNull; - DerefBytes = Base->getPointerDereferenceableBytes(DL, CanBeNull); + bool CanBeNull, CanBeFreed; + DerefBytes = + Base->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed); T.GlobalState.indicatePessimisticFixpoint(); } else { const DerefState &DS = AA.getState(); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index e6e90b915bb86..ae72123e3f001 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -2593,8 +2593,8 @@ Instruction *InstCombinerImpl::visitBitCast(BitCastInst &CI) { // If the source pointer is dereferenceable, then assume it points to an // allocated object and apply "inbounds" to the GEP. - bool CanBeNull; - if (Src->getPointerDereferenceableBytes(DL, CanBeNull)) { + bool CanBeNull, CanBeFreed; + if (Src->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed)) { // In a non-default address space (not 0), a null pointer can not be // assumed inbounds, so ignore that case (dereferenceable_or_null). // The reason is that 'null' is not treated differently in these address