isNotCapturedBeforeOrInLoop(Object, L, DT);
}
+bool isWritableObject(const Value *Object) {
+ // TODO: Alloca might not be writable after its lifetime ends.
+ // See https://github.com/llvm/llvm-project/issues/51838.
+ if (isa<AllocaInst>(Object))
+ return true;
+
+ // TODO: Also handle sret.
+ if (auto *A = dyn_cast<Argument>(Object))
+ return A->hasByValAttr();
+
+ // TODO: Noalias has nothing to do with writability, this should check for
+ // an allocator function.
+ return isNoAliasCall(Object);
+}
+
+bool isThreadLocalObject(const Value *Object, const Loop *L,
+ DominatorTree *DT) {
+ // The object must be function-local to start with, and then not captured
+ // before/in the loop.
+ return isIdentifiedFunctionLocal(Object) &&
+ isNotCapturedBeforeOrInLoop(Object, L, DT);
+}
+
} // namespace
/// Try to promote memory values to scalars by sinking stores out of the
}
// We know we can hoist the load, but don't have a guaranteed store.
- // Check whether the location is thread-local. If it is, then we can insert
- // stores along paths which originally didn't have them without violating the
- // memory model.
+ // Check whether the location is writable and thread-local. If it is, then we
+ // can insert stores along paths which originally didn't have them without
+ // violating the memory model.
if (StoreSafety == StoreSafetyUnknown) {
Value *Object = getUnderlyingObject(SomePtr);
- if ((isNoAliasCall(Object) || isa<AllocaInst>(Object) ||
- (isa<Argument>(Object) && cast<Argument>(Object)->hasByValAttr())) &&
- isNotCapturedBeforeOrInLoop(Object, CurLoop, DT))
+ if (isWritableObject(Object) && isThreadLocalObject(Object, CurLoop, DT))
StoreSafety = StoreSafe;
}