forked from OSchip/llvm-project
[LICM] Restructure implicit exit handling to be more clear [NFCI]
When going to explain this to someone else, I got tripped up by the complicated meaning of IsKnownNonEscapingObject in load-store promotion. Extract a helper routine and clarify naming/scopes to make this a bit more obvious. llvm-svn: 316699
This commit is contained in:
parent
e4b9ae666e
commit
21cc2fa3f6
|
|
@ -1033,6 +1033,30 @@ public:
|
||||||
}
|
}
|
||||||
void instructionDeleted(Instruction *I) const override { AST.deleteValue(I); }
|
void instructionDeleted(Instruction *I) const override { AST.deleteValue(I); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// Return true iff we can prove that a caller of this function can not inspect
|
||||||
|
/// the contents of the provided object in a well defined program.
|
||||||
|
bool isKnownNonEscaping(Value *Object, const TargetLibraryInfo *TLI) {
|
||||||
|
if (isa<AllocaInst>(Object))
|
||||||
|
// Since the alloca goes out of scope, we know the caller can't retain a
|
||||||
|
// reference to it and be well defined. Thus, we don't need to check for
|
||||||
|
// capture.
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// For all other objects we need to know that the caller can't possibly
|
||||||
|
// have gotten a reference to the object. There are two components of
|
||||||
|
// that:
|
||||||
|
// 1) Object can't be escaped by this function. This is what
|
||||||
|
// PointerMayBeCaptured checks.
|
||||||
|
// 2) Object can't have been captured at definition site. For this, we
|
||||||
|
// need to know the return value is noalias. At the moment, we use a
|
||||||
|
// weaker condition and handle only AllocLikeFunctions (which are
|
||||||
|
// known to be noalias). TODO
|
||||||
|
return isAllocLikeFn(Object, TLI) &&
|
||||||
|
!PointerMayBeCaptured(Object, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
/// Try to promote memory values to scalars by sinking stores out of the
|
/// Try to promote memory values to scalars by sinking stores out of the
|
||||||
|
|
@ -1107,35 +1131,19 @@ bool llvm::promoteLoopAccessesToScalars(
|
||||||
|
|
||||||
const DataLayout &MDL = Preheader->getModule()->getDataLayout();
|
const DataLayout &MDL = Preheader->getModule()->getDataLayout();
|
||||||
|
|
||||||
// Do we know this object does not escape ?
|
bool IsKnownThreadLocalObject = false;
|
||||||
bool IsKnownNonEscapingObject = false;
|
|
||||||
if (SafetyInfo->MayThrow) {
|
if (SafetyInfo->MayThrow) {
|
||||||
// If a loop can throw, we have to insert a store along each unwind edge.
|
// If a loop can throw, we have to insert a store along each unwind edge.
|
||||||
// That said, we can't actually make the unwind edge explicit. Therefore,
|
// That said, we can't actually make the unwind edge explicit. Therefore,
|
||||||
// we have to prove that the store is dead along the unwind edge.
|
// we have to prove that the store is dead along the unwind edge. We do
|
||||||
//
|
// this by proving that the caller can't have a reference to the object
|
||||||
// If the underlying object is not an alloca, nor a pointer that does not
|
// after return and thus can't possibly load from the object.
|
||||||
// escape, then we can not effectively prove that the store is dead along
|
|
||||||
// the unwind edge. i.e. the caller of this function could have ways to
|
|
||||||
// access the pointed object.
|
|
||||||
Value *Object = GetUnderlyingObject(SomePtr, MDL);
|
Value *Object = GetUnderlyingObject(SomePtr, MDL);
|
||||||
// If this is a base pointer we do not understand, simply bail.
|
if (!isKnownNonEscaping(Object, TLI))
|
||||||
// We only handle alloca and return value from alloc-like fn right now.
|
return false;
|
||||||
if (!isa<AllocaInst>(Object)) {
|
// Subtlety: Alloca's aren't visible to callers, but *are* potentially
|
||||||
if (!isAllocLikeFn(Object, TLI))
|
// visible to other threads if captured and used during their lifetimes.
|
||||||
return false;
|
IsKnownThreadLocalObject = !isa<AllocaInst>(Object);
|
||||||
// If this is an alloc like fn. There are more constraints we need to
|
|
||||||
// verify. More specifically, we must make sure that the pointer can not
|
|
||||||
// escape.
|
|
||||||
//
|
|
||||||
// NOTE: PointerMayBeCaptured is not enough as the pointer may have
|
|
||||||
// escaped even though its not captured by the enclosing function.
|
|
||||||
// Standard allocation functions like malloc, calloc, and operator new
|
|
||||||
// return values which can be assumed not to have previously escaped.
|
|
||||||
if (PointerMayBeCaptured(Object, true, true))
|
|
||||||
return false;
|
|
||||||
IsKnownNonEscapingObject = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that all of the pointers in the alias set have the same type. We
|
// Check that all of the pointers in the alias set have the same type. We
|
||||||
|
|
@ -1247,8 +1255,7 @@ bool llvm::promoteLoopAccessesToScalars(
|
||||||
// stores along paths which originally didn't have them without violating the
|
// stores along paths which originally didn't have them without violating the
|
||||||
// memory model.
|
// memory model.
|
||||||
if (!SafeToInsertStore) {
|
if (!SafeToInsertStore) {
|
||||||
// If this is a known non-escaping object, it is safe to insert the stores.
|
if (IsKnownThreadLocalObject)
|
||||||
if (IsKnownNonEscapingObject)
|
|
||||||
SafeToInsertStore = true;
|
SafeToInsertStore = true;
|
||||||
else {
|
else {
|
||||||
Value *Object = GetUnderlyingObject(SomePtr, MDL);
|
Value *Object = GetUnderlyingObject(SomePtr, MDL);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue