Addresses a regression reported in D145210.
Unescaped local values cannot be Mod'd by fences since other threads
either cannot know the address (unescaped alloca) or it would be UB
(noalias).
Differential D153932
[AliasAnalysis] Mark fences as not Mod'ing unescaped local values aeubanks on Jun 27 2023, 5:40 PM. Authored by
Details
Diff Detail
Unit Tests Event Timeline
Comment Actions Unfortunately, I'm not an LLVM expert, so let me try to answer in terms of atomic<int*> y(nullptr); Thread 1: x = 17; atomic_thread_fence(memory_order::release); // Address of x not yet taken. y.store(&x, memory_order::relaxed); } Thread 2: And that assertion should not fail. Without the fence, it may fail, so the Does that answer the question? Or did I misinterpret it? Hans Comment Actions The relevant scenario would be a bit more complicated, I think, since we're returning that the fence is "ModRefInfo::Ref". Basically, that means non-atomic loads can move across the fence, but stores and atomic ops can't move across the fence. But consider transforming something like the following: atomic<int*> y(nullptr); // Thread 1: x = 17; z = x; atomic_thread_fence(memory_order::release); // Address of x not yet taken. y.store(&x, memory_order::relaxed); assert(z == 17); // Thread 2: int* tmp = y.load(memory_order::acquire); if (tmp != nullptr) *tmp += 100; To something like: atomic<int*> y(nullptr); // Thread 1: x = 17; atomic_thread_fence(memory_order::release); // Address of x not yet taken. z = x; y.store(&x, memory_order::relaxed); assert(z == 17); // Thread 2: int* tmp = y.load(memory_order::acquire); if (tmp != nullptr) *tmp += 100; The original is legal C++, but the modified version has undefined behavior, I think. And actually, I guess this reasoning also applies to hoisting/sinking across arbitrary calls, since any function can contain a fence. So BasicAAResult::getModRefInfo for CallInst also needs to be fixed. Comment Actions Thanks for the correction. Subject to my limited understanding of LLVM The behavior of release/acquire is completely symmetric with respect to a |
isNotCapturedBeforeOrAt() implies isIdentifiedFunctionLocal().