diff options
author | Philip Reames <listmail@philipreames.com> | 2021-04-16 11:37:36 -0700 |
---|---|---|
committer | Philip Reames <listmail@philipreames.com> | 2021-04-16 11:38:55 -0700 |
commit | ff55d01a8e1b60c137cd8cab7d9eeef14284fd7a (patch) | |
tree | 905a719f5648bd40fd65be731a91fcd67e2bd1be /llvm/lib/IR/Value.cpp | |
parent | 0daf27302518dcc521fae5cb5c7f72b783c13c35 (diff) | |
download | llvm-ff55d01a8e1b60c137cd8cab7d9eeef14284fd7a.zip llvm-ff55d01a8e1b60c137cd8cab7d9eeef14284fd7a.tar.gz llvm-ff55d01a8e1b60c137cd8cab7d9eeef14284fd7a.tar.bz2 |
[nofree] Restrict semantics to memory visible to caller
This patch clarifies the semantics of the nofree function attribute to make clear that it provides an "as if" semantic. That is, a nofree function is guaranteed not to free memory which existed before the call, but might allocate and then deallocate that same memory within the lifetime of the callee.
This is the result of the discussion on llvm-dev under the thread "Ambiguity in the nofree function attribute".
The most important part of this change is the LangRef wording. The rest is minor comment changes to emphasize the new semantics where code was accidentally consistent, and fix one place which wasn't consistent. That one place is currently narrowly used as it is primarily part of the ongoing (and not yet enabled) deref-at-point semantics work.
Differential Revision: https://reviews.llvm.org/D100141
Diffstat (limited to 'llvm/lib/IR/Value.cpp')
-rw-r--r-- | llvm/lib/IR/Value.cpp | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index 544f4d6..7003508 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -736,9 +736,18 @@ bool Value::canBeFreed() const { // Handle byval/byref/sret/inalloca/preallocated arguments. The storage // lifetime is guaranteed to be longer than the callee's lifetime. - if (auto *A = dyn_cast<Argument>(this)) + if (auto *A = dyn_cast<Argument>(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. + const Function *F = A->getParent(); + if (F->doesNotFreeMemory() && F->hasNoSync()) + return false; + } const Function *F = nullptr; if (auto *I = dyn_cast<Instruction>(this)) @@ -749,12 +758,6 @@ bool Value::canBeFreed() const { if (!F) return true; - // 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. - if (F->doesNotFreeMemory() && F->hasNoSync()) - return false; - // With garbage collection, deallocation typically occurs solely at or after // safepoints. If we're compiling for a collector which uses the // gc.statepoint infrastructure, safepoints aren't explicitly present |