forked from OSchip/llvm-project
[LICM] Generalize unwinding check during scalar promotion
This extract a common isNotVisibleOnUnwind() helper into AliasAnalysis, which handles allocas, byval arguments and noalias calls. After D116998 this could also handle sret arguments. We have similar logic in DSE and MemCpyOpt, which will be switched to use this helper as well. The noalias call case is a bit different from the others, because it also requires that the object is not captured. The caller is responsible for doing the appropriate check. Differential Revision: https://reviews.llvm.org/D117000
This commit is contained in:
parent
7c02776567
commit
44cfc3a816
|
@ -1267,6 +1267,14 @@ bool isIdentifiedObject(const Value *V);
|
|||
/// IdentifiedObjects.
|
||||
bool isIdentifiedFunctionLocal(const Value *V);
|
||||
|
||||
/// Return true if Object memory is not visible after an unwind, in the sense
|
||||
/// that program semantics cannot depend on Object containing any particular
|
||||
/// value on unwind. If the RequiresNoCaptureBeforeUnwind out parameter is set
|
||||
/// to true, then the memory is only not visible if the object has not been
|
||||
/// captured prior to the unwind. Otherwise it is not visible even if captured.
|
||||
bool isNotVisibleOnUnwind(const Value *Object,
|
||||
bool &RequiresNoCaptureBeforeUnwind);
|
||||
|
||||
/// A manager for alias analyses.
|
||||
///
|
||||
/// This class can have analyses registered with it and when run, it will run
|
||||
|
|
|
@ -988,6 +988,29 @@ bool llvm::isIdentifiedFunctionLocal(const Value *V) {
|
|||
return isa<AllocaInst>(V) || isNoAliasCall(V) || isNoAliasOrByValArgument(V);
|
||||
}
|
||||
|
||||
bool llvm::isNotVisibleOnUnwind(const Value *Object,
|
||||
bool &RequiresNoCaptureBeforeUnwind) {
|
||||
RequiresNoCaptureBeforeUnwind = false;
|
||||
|
||||
// Alloca goes out of scope on unwind.
|
||||
if (isa<AllocaInst>(Object))
|
||||
return true;
|
||||
|
||||
// Byval goes out of scope on unwind.
|
||||
if (auto *A = dyn_cast<Argument>(Object))
|
||||
return A->hasByValAttr();
|
||||
|
||||
// A noalias return is not accessible from any other code. If the pointer
|
||||
// does not escape prior to the unwind, then the caller cannot access the
|
||||
// memory either.
|
||||
if (isNoAliasCall(Object)) {
|
||||
RequiresNoCaptureBeforeUnwind = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void llvm::getAAResultsAnalysisUsage(AnalysisUsage &AU) {
|
||||
// This function needs to be in sync with llvm::createLegacyPMAAResults -- if
|
||||
// more alias analyses are added to llvm::createLegacyPMAAResults, they need
|
||||
|
|
|
@ -1925,21 +1925,14 @@ bool isNotCapturedBeforeOrInLoop(const Value *V, const Loop *L,
|
|||
|
||||
/// Return true if we can prove that a caller cannot inspect the object if an
|
||||
/// unwind occurs inside the loop.
|
||||
bool isNotVisibleOnUnwind(Value *Object, const Loop *L, DominatorTree *DT) {
|
||||
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;
|
||||
bool isNotVisibleOnUnwindInLoop(const Value *Object, const Loop *L,
|
||||
DominatorTree *DT) {
|
||||
bool RequiresNoCaptureBeforeUnwind;
|
||||
if (!isNotVisibleOnUnwind(Object, RequiresNoCaptureBeforeUnwind))
|
||||
return false;
|
||||
|
||||
// For all other objects we need to know that the caller can't possibly
|
||||
// have gotten a reference to the object prior to an unwind in the loop.
|
||||
// There are two components of that:
|
||||
// 1) Object can't have been captured prior to the definition site.
|
||||
// For this, we need to know the return value is noalias.
|
||||
// 1) Object can't be captured before or inside the loop. This is what
|
||||
// isNotCapturedBeforeOrInLoop() checks.
|
||||
return isNoAliasCall(Object) && isNotCapturedBeforeOrInLoop(Object, L, DT);
|
||||
return !RequiresNoCaptureBeforeUnwind ||
|
||||
isNotCapturedBeforeOrInLoop(Object, L, DT);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -2026,7 +2019,7 @@ bool llvm::promoteLoopAccessesToScalars(
|
|||
// this by proving that the caller can't have a reference to the object
|
||||
// after return and thus can't possibly load from the object.
|
||||
Value *Object = getUnderlyingObject(SomePtr);
|
||||
if (!isNotVisibleOnUnwind(Object, CurLoop, DT))
|
||||
if (!isNotVisibleOnUnwindInLoop(Object, CurLoop, DT))
|
||||
return false;
|
||||
// Subtlety: Alloca's aren't visible to callers, but *are* potentially
|
||||
// visible to other threads if captured and used during their lifetimes.
|
||||
|
|
|
@ -100,16 +100,16 @@ for.cond.cleanup:
|
|||
ret void
|
||||
}
|
||||
|
||||
; TODO: byval memory cannot be accessed on unwind either.
|
||||
; byval memory cannot be accessed on unwind either.
|
||||
define void @test_byval(i32* byval(i32) %a, i1 zeroext %y) uwtable {
|
||||
; CHECK-LABEL: @test_byval(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[A_PROMOTED:%.*]] = load i32, i32* [[A:%.*]], align 4
|
||||
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I_03:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_INC:%.*]] ]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[A:%.*]], align 4
|
||||
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], 1
|
||||
; CHECK-NEXT: store i32 [[ADD]], i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[ADD1:%.*]] = phi i32 [ [[A_PROMOTED]], [[ENTRY:%.*]] ], [ [[ADD:%.*]], [[FOR_INC:%.*]] ]
|
||||
; CHECK-NEXT: [[I_03:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[INC:%.*]], [[FOR_INC]] ]
|
||||
; CHECK-NEXT: [[ADD]] = add nsw i32 [[ADD1]], 1
|
||||
; CHECK-NEXT: br i1 [[Y:%.*]], label [[IF_THEN:%.*]], label [[FOR_INC]]
|
||||
; CHECK: if.then:
|
||||
; CHECK-NEXT: tail call void @f()
|
||||
|
@ -119,6 +119,8 @@ define void @test_byval(i32* byval(i32) %a, i1 zeroext %y) uwtable {
|
|||
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i32 [[INC]], 10000
|
||||
; CHECK-NEXT: br i1 [[EXITCOND]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY]]
|
||||
; CHECK: for.cond.cleanup:
|
||||
; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], [[FOR_INC]] ]
|
||||
; CHECK-NEXT: store i32 [[ADD_LCSSA]], i32* [[A]], align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
|
|
Loading…
Reference in New Issue