diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h --- a/llvm/include/llvm/Analysis/AliasAnalysis.h +++ b/llvm/include/llvm/Analysis/AliasAnalysis.h @@ -1264,6 +1264,10 @@ /// bool isIdentifiedObject(const Value *V); +/// Returns true if the pointer is one which would have been considered an +/// escape by isNonEscapingLocalObject. +bool isEscapeSource(const Value *V); + /// Return true if V is umabigously identified at the function-level. /// Different IdentifiedFunctionLocals can't alias. /// Further, an IdentifiedFunctionLocal can not alias with any function diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp --- a/llvm/lib/Analysis/AliasAnalysis.cpp +++ b/llvm/lib/Analysis/AliasAnalysis.cpp @@ -983,6 +983,27 @@ return false; } +bool llvm::isEscapeSource(const Value *V) { + if (isa(V)) + return true; + + // The load case works because isNonEscapingLocalObject considers all + // stores to be escapes (it passes true for the StoreCaptures argument + // to PointerMayBeCaptured). + if (isa(V)) + return true; + + // The inttoptr case works because isNonEscapingLocalObject considers all + // means of converting or equating a pointer to an int (ptrtoint, ptr store + // which could be followed by an integer load, ptr<->int compare) as + // escaping, and objects located at well-known addresses via platform-specific + // means cannot be considered non-escaping local objects. + if (isa(V)) + return true; + + return false; +} + bool llvm::isIdentifiedFunctionLocal(const Value *V) { return isa(V) || isNoAliasCall(V) || isNoAliasOrByValArgument(V); } diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -103,29 +103,6 @@ // Useful predicates //===----------------------------------------------------------------------===// -/// Returns true if the pointer is one which would have been considered an -/// escape by isNonEscapingLocalObject. -static bool isEscapeSource(const Value *V) { - if (isa(V)) - return true; - - // The load case works because isNonEscapingLocalObject considers all - // stores to be escapes (it passes true for the StoreCaptures argument - // to PointerMayBeCaptured). - if (isa(V)) - return true; - - // The inttoptr case works because isNonEscapingLocalObject considers all - // means of converting or equating a pointer to an int (ptrtoint, ptr store - // which could be followed by an integer load, ptr<->int compare) as - // escaping, and objects located at well-known addresses via platform-specific - // means cannot be considered non-escaping local objects. - if (isa(V)) - return true; - - return false; -} - /// Returns the size of the object specified by V or UnknownSize if unknown. static uint64_t getObjectSize(const Value *V, const DataLayout &DL, const TargetLibraryInfo &TLI, diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -1079,7 +1079,8 @@ // Figure out if we're derived from anything that is not a noalias // argument. - bool CanDeriveViaCapture = false, UsesAliasingPtr = false; + bool CanDeriveViaCapture = false, UsesAliasingPtr = false, + MayAliasForUnidentify = false; for (const Value *V : ObjSet) { // Is this value a constant that cannot be derived from any pointer // value (we need to exclude constant expressions, for example, that @@ -1105,8 +1106,18 @@ // by definition, also cannot alias a noalias argument), then we could // alias a noalias argument that has been captured). if (!isa(V) && - !isIdentifiedFunctionLocal(const_cast(V))) + !isIdentifiedFunctionLocal(const_cast(V))) { CanDeriveViaCapture = true; + // If the underlying object is not a must-not-alias object and it is + // not an identified object, it still may be pointers derived from + // noalias argument as `getUnderlyingObjects()` may not check deep + // enough to get the real underlying object. + // For escaped objects, PointerMayBeCapturedBefore() can check if they + // are alias to the noalias argument or not, so don't treat them as + // unidentified objects. + if (!isIdentifiedObject(V) && !isEscapeSource(V)) + MayAliasForUnidentify = true; + } } // A function call can always get captured noalias pointers (via other @@ -1119,20 +1130,22 @@ // 1. The noalias argument is not in the set of objects from which we // definitely derive. // 2. The noalias argument has not yet been captured. + // 3. The underlying object is identified. // An arbitrary function that might load pointers could see captured // noalias arguments via other noalias arguments or globals, and so we // must always check for prior capture. for (const Argument *A : NoAliasArgs) { - if (!ObjSet.count(A) && (!CanDeriveViaCapture || - // It might be tempting to skip the - // PointerMayBeCapturedBefore check if - // A->hasNoCaptureAttr() is true, but this is - // incorrect because nocapture only guarantees - // that no copies outlive the function, not - // that the value cannot be locally captured. - !PointerMayBeCapturedBefore(A, - /* ReturnCaptures */ false, - /* StoreCaptures */ false, I, &DT))) + if (!ObjSet.count(A) && !MayAliasForUnidentify && + (!CanDeriveViaCapture || + // It might be tempting to skip the + // PointerMayBeCapturedBefore check if + // A->hasNoCaptureAttr() is true, but this is + // incorrect because nocapture only guarantees + // that no copies outlive the function, not + // that the value cannot be locally captured. + !PointerMayBeCapturedBefore(A, + /* ReturnCaptures */ false, + /* StoreCaptures */ false, I, &DT))) NoAliases.push_back(NewScopes[A]); } diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll b/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll --- a/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-opaque-ptr.ll @@ -34,8 +34,8 @@ ; CHECK-LABEL: @main( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @print(i32 4) -; CHECK-NEXT: call void @print(i32 5), !noalias !0 -; CHECK-NEXT: call void @print(i32 6), !noalias !3 +; CHECK-NEXT: call void @print(i32 5) +; CHECK-NEXT: call void @print(i32 6) ; CHECK-NEXT: ret i32 0 ; entry: diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll --- a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll @@ -66,7 +66,7 @@ ; CHECK-NEXT: [[N_VAL3_RELOAD_ADDR11_I5:%.*]] = getelementptr inbounds [[F_FRAME]], %f.Frame* [[FRAMEPTR_I2]], i64 0, i32 1 ; CHECK-NEXT: [[N_VAL3_RELOAD12_I6:%.*]] = load i32, i32* [[N_VAL3_RELOAD_ADDR11_I5]], align 4, !noalias !6 ; CHECK-NEXT: [[SUM7_I7:%.*]] = add i32 [[N_VAL3_RELOAD12_I6]], [[INPUT_RELOAD14_I4]] -; CHECK-NEXT: call void @print(i32 [[SUM7_I7]]), !noalias !6 +; CHECK-NEXT: call void @print(i32 [[SUM7_I7]]) ; CHECK-NEXT: [[TMP5:%.*]] = bitcast %f.Frame* [[FRAMEPTR_I2]] to i8* ; CHECK-NEXT: call void @deallocate(i8* [[TMP5]]), !noalias !6 ; CHECK-NEXT: ret i32 0 diff --git a/llvm/test/Transforms/Coroutines/coro-retcon.ll b/llvm/test/Transforms/Coroutines/coro-retcon.ll --- a/llvm/test/Transforms/Coroutines/coro-retcon.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon.ll @@ -36,8 +36,8 @@ ; CHECK-LABEL: @main( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @print(i32 4) -; CHECK-NEXT: call void @print(i32 5), !noalias !0 -; CHECK-NEXT: call void @print(i32 6), !noalias !3 +; CHECK-NEXT: call void @print(i32 5) +; CHECK-NEXT: call void @print(i32 6) ; CHECK-NEXT: ret i32 0 ; entry: diff --git a/llvm/test/Transforms/Inline/inline-noalias-unidentify-object.ll b/llvm/test/Transforms/Inline/inline-noalias-unidentify-object.ll --- a/llvm/test/Transforms/Inline/inline-noalias-unidentify-object.ll +++ b/llvm/test/Transforms/Inline/inline-noalias-unidentify-object.ll @@ -14,7 +14,7 @@ ; CHECK-NEXT: [[P_6_I:%.*]] = getelementptr i8, ptr [[P_5_I]], i64 1 ; CHECK-NEXT: [[P_7_I:%.*]] = getelementptr i8, ptr [[P_6_I]], i64 1 ; CHECK-NEXT: [[P_8_ALIAS_I:%.*]] = getelementptr i8, ptr [[P_7_I]], i64 1 -; CHECK-NEXT: store i32 42, ptr [[P_8_ALIAS_I]], align 4, !noalias !0 +; CHECK-NEXT: store i32 42, ptr [[P_8_ALIAS_I]], align 4 ; CHECK-NEXT: ret i32 [[V_I]] ; %v = call i32 @callee(ptr %p)