Index: llvm/include/llvm/IR/Value.h =================================================================== --- llvm/include/llvm/IR/Value.h +++ llvm/include/llvm/IR/Value.h @@ -738,6 +738,12 @@ static_cast(this)->stripInBoundsOffsets(Func)); } + /// Return true if the memory object referred to by V can by freed in the + /// scope for which the SSA value defining the allocation is statically + /// defined. E.g. deallocation after the static scope of a value does not + /// count, but a deallocation before that does. + bool canBeFreed() const; + /// Returns the number of bytes known to be dereferenceable for the /// pointer value. /// Index: llvm/lib/Analysis/Loads.cpp =================================================================== --- llvm/lib/Analysis/Loads.cpp +++ llvm/lib/Analysis/Loads.cpp @@ -162,19 +162,11 @@ Opts.RoundToAlign = false; Opts.NullIsUnknownSize = true; uint64_t ObjSize; - // TODO: Plumb through TLI so that malloc routines and such working. - if (getObjectSize(V, ObjSize, DL, nullptr, Opts)) { + if (getObjectSize(V, ObjSize, DL, TLI, Opts)) { APInt KnownDerefBytes(Size.getBitWidth(), ObjSize); if (KnownDerefBytes.getBoolValue() && KnownDerefBytes.uge(Size) && isKnownNonZero(V, DL, 0, nullptr, CtxI, DT) && - // TODO: We're currently inconsistent about whether deref(N) is a - // global fact or a point in time fact. Once D61652 eventually - // lands, this check will be restricted to the point in time - // variant. For that variant, we need to prove that object hasn't - // been conditionally freed before ontext instruction - if it has, we - // might be hoisting over the inverse conditional and creating a - // dynamic use after free. - !PointerMayBeCapturedBefore(V, true, true, CtxI, DT, true)) { + !V->canBeFreed()) { // 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 properly aligned, then the original offset accessed Index: llvm/lib/IR/Value.cpp =================================================================== --- llvm/lib/IR/Value.cpp +++ llvm/lib/IR/Value.cpp @@ -785,6 +785,11 @@ return false; } +bool Value::canBeFreed() const { + // NOTE: Wrapper exists only to simplify patch rebase. Will be inlined once + // landed. + return ::canBeFreed(this); +} uint64_t Value::getPointerDereferenceableBytes(const DataLayout &DL, bool &CanBeNull, @@ -793,7 +798,7 @@ uint64_t DerefBytes = 0; CanBeNull = false; - CanBeFreed = UseDerefAtPointSemantics && canBeFreed(this); + CanBeFreed = UseDerefAtPointSemantics && canBeFreed(); if (const Argument *A = dyn_cast(this)) { DerefBytes = A->getDereferenceableBytes(); if (DerefBytes == 0) { Index: llvm/test/Transforms/LoopVectorize/X86/load-deref-pred.ll =================================================================== --- llvm/test/Transforms/LoopVectorize/X86/load-deref-pred.ll +++ llvm/test/Transforms/LoopVectorize/X86/load-deref-pred.ll @@ -2214,7 +2214,7 @@ declare align 8 dereferenceable_or_null(8) i8* @my_alloc(i32) allocsize(0) declare align 8 dereferenceable_or_null(8) i8* @my_array_alloc(i32, i32) allocsize(0, 1) -define i32 @test_allocsize(i64 %len, i1* %test_base) { +define i32 @test_allocsize(i64 %len, i1* %test_base) nofree nosync { ; CHECK-LABEL: @test_allocsize( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ALLOCATION:%.*]] = call nonnull i8* @my_alloc(i32 16384) @@ -2382,7 +2382,7 @@ } -define i32 @test_allocsize_array(i64 %len, i1* %test_base) { +define i32 @test_allocsize_array(i64 %len, i1* %test_base) nofree nosync { ; CHECK-LABEL: @test_allocsize_array( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[ALLOCATION:%.*]] = call nonnull i8* @my_array_alloc(i32 4096, i32 4)