mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
Update basic deref API to account for possiblity of free [NFC]
This patch is plumbing to support work towards the goal outlined in the recent llvm-dev post "[llvm-dev] RFC: Decomposing deref(N) into deref(N) + nofree". The point of this change is purely to simplify iteration on other pieces on way to making the switch. Rebuilding with a change to Value.h is slow and painful, so I want to get the API change landed. Once that's done, I plan to more closely audit each caller, add the inference rules in their own patch, then post a patch with the langref changes and test diffs. The value of the command line flag is that we can exercise the inference logic in standalone patches without needing the whole switch ready to go just yet. Differential Revision: https://reviews.llvm.org/D98908
This commit is contained in:
parent
1e97683a06
commit
eaf092af50
@ -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 = {});
|
||||
|
||||
|
@ -743,8 +743,13 @@ public:
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
|
@ -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())
|
||||
|
@ -68,8 +68,8 @@ bool CaptureTracker::isDereferenceableOrNull(Value *O, const DataLayout &DL) {
|
||||
if (auto *GEP = dyn_cast<GetElementPtrInst>(O))
|
||||
if (GEP->isInBounds())
|
||||
return true;
|
||||
bool CanBeNull;
|
||||
return O->getPointerDereferenceableBytes(DL, CanBeNull);
|
||||
bool CanBeNull, CanBeFreed;
|
||||
return O->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -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
|
||||
|
@ -38,6 +38,11 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<unsigned> 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<unsigned> 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<void(const Value *)> 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<Argument>(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<GlobalVariable>(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;
|
||||
|
@ -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<AANonNull>(*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();
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user