/// 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
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
/// 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
// 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.
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()
; 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: