diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -1954,10 +1954,21 @@ } }; +bool isNotCapturedBeforeOrInLoop(const Value *V, const Loop *L, + DominatorTree *DT) { + // We can perform the captured-before check against any instruction in the + // loop header, as the loop header is reachable from any instruction inside + // the loop. + // TODO: ReturnCaptures=true shouldn't be necessary here. + return !PointerMayBeCapturedBefore(V, /* ReturnCaptures */ true, + /* StoreCaptures */ true, + L->getHeader()->getTerminator(), DT); +} /// 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) { +bool isKnownNonEscaping(Value *Object, const Loop *L, + const TargetLibraryInfo *TLI, DominatorTree *DT) { if (isa(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 @@ -1974,7 +1985,7 @@ // weaker condition and handle only AllocLikeFunctions (which are // known to be noalias). TODO return isAllocLikeFn(Object, TLI) && - !PointerMayBeCaptured(Object, true, true); + isNotCapturedBeforeOrInLoop(Object, L, DT); } } // namespace @@ -2060,7 +2071,7 @@ // 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 (!isKnownNonEscaping(Object, TLI)) + if (!isKnownNonEscaping(Object, CurLoop, TLI, 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. @@ -2195,7 +2206,7 @@ Value *Object = getUnderlyingObject(SomePtr); SafeToInsertStore = (isAllocLikeFn(Object, TLI) || isa(Object)) && - !PointerMayBeCaptured(Object, true, true); + isNotCapturedBeforeOrInLoop(Object, CurLoop, DT); } } diff --git a/llvm/test/Transforms/LICM/promote-capture.ll b/llvm/test/Transforms/LICM/promote-capture.ll --- a/llvm/test/Transforms/LICM/promote-capture.ll +++ b/llvm/test/Transforms/LICM/promote-capture.ll @@ -9,21 +9,24 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[COUNT:%.*]] = alloca i32, align 4 ; CHECK-NEXT: store i32 0, i32* [[COUNT]], align 4 +; CHECK-NEXT: [[COUNT_PROMOTED:%.*]] = load i32, i32* [[COUNT]], align 4 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: -; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[LATCH:%.*]] ] +; CHECK-NEXT: [[C_INC2:%.*]] = phi i32 [ [[COUNT_PROMOTED]], [[ENTRY:%.*]] ], [ [[C_INC1:%.*]], [[LATCH:%.*]] ] +; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[I_NEXT:%.*]], [[LATCH]] ] ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond(i32 [[I]]) ; CHECK-NEXT: br i1 [[COND]], label [[IF:%.*]], label [[LATCH]] ; CHECK: if: -; CHECK-NEXT: [[C:%.*]] = load i32, i32* [[COUNT]], align 4 -; CHECK-NEXT: [[C_INC:%.*]] = add i32 [[C]], 1 -; CHECK-NEXT: store i32 [[C_INC]], i32* [[COUNT]], align 4 +; CHECK-NEXT: [[C_INC:%.*]] = add i32 [[C_INC2]], 1 ; CHECK-NEXT: br label [[LATCH]] ; CHECK: latch: +; CHECK-NEXT: [[C_INC1]] = phi i32 [ [[C_INC]], [[IF]] ], [ [[C_INC2]], [[LOOP]] ] ; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I_NEXT]], [[LEN:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[LOOP]] ; CHECK: exit: +; CHECK-NEXT: [[C_INC1_LCSSA:%.*]] = phi i32 [ [[C_INC1]], [[LATCH]] ] +; CHECK-NEXT: store i32 [[C_INC1_LCSSA]], i32* [[COUNT]], align 4 ; CHECK-NEXT: call void @capture(i32* [[COUNT]]) ; CHECK-NEXT: ret void ;