diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index 7246adf7ec651..074d42d728c95 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -834,13 +834,12 @@ bool Value::canBeFreed() const { if (auto *A = dyn_cast(this)) { if (A->hasPointeeInMemoryValueAttr()) return false; - // A pointer to an object in a function which neither frees, nor can arrange - // for another thread to free on its behalf, can not be freed in the scope - // of the function. Note that this logic is restricted to memory - // allocations in existance before the call; a nofree function *is* allowed - // to free memory it allocated. + // A nofree function can not free (including via synchronization) any + // allocations that existed prior to the call, but may free allocations + // created inside the function. This logic is limited to argument pointers, + // as they definitely exist prior to the call. const Function *F = A->getParent(); - if (F->doesNotFreeMemory() && F->hasNoSync()) + if (F->doesNotFreeMemory()) return false; } diff --git a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll index fc40c68624f2d..43f2c156b2ddc 100644 --- a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll +++ b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll @@ -248,16 +248,14 @@ define void @negative(ptr dereferenceable(8) %p) { ; CHECK-LABEL: 'infer_func_attrs1' ; CHECK: %p -define void @infer_func_attrs1(ptr dereferenceable(8) %p) nofree nosync { +define void @infer_func_attrs1(ptr dereferenceable(8) %p) nofree { call void @mayfree() %v = load i32, ptr %p ret void } ; CHECK-LABEL: 'infer_func_attrs2' -; GLOBAL: %p -; POINT-NOT: %p -; FIXME: Can be inferred from attributes +; CHECK: %p define void @infer_func_attrs2(ptr dereferenceable(8) %p) readonly { call void @mayfree() %v = load i32, ptr %p