diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -2763,6 +2763,174 @@ return true; } + /// Perform the alias check at the call site. We can allow all but accesses to + /// unknown memory as long as we check accesses to arguments and globals for + /// potential aliases to the underlying call site argument. That is, if the + /// call site argument does not alias any argument or global which is accessed + /// by the callee it can be marked noalias. + bool isKnownNoAliasAtCallSiteDueToAccesses( + Attributor &A, AAResults *&AAR, const AAMemoryBehavior &MemBehaviorAA, + const AANoAlias &NoAliasAA, const AAMemoryLocation &MemLocationAA) { + + AAMemoryLocation::MemoryLocationsKind AllowedAccessLocs = + AAMemoryLocation::NO_UNKOWN_MEM; + + bool OnlyKnownLocationsAccessed = + MemLocationAA.isAssumedSpecifiedMemOnly(AllowedAccessLocs); + LLVM_DEBUG( + dbgs() << "[AANoAlias] Only known locations " + "accessed by callee: " + << OnlyKnownLocationsAccessed << " [" + << AAMemoryLocation::getMemoryLocationsAsStr(AllowedAccessLocs) + << " vs " + << AAMemoryLocation::getMemoryLocationsAsStr( + MemLocationAA.getAssumedNotAccessedLocation()) + << "]\n"); + + if (!OnlyKnownLocationsAccessed) + return false; + + bool IsReadOnly = MemBehaviorAA.isAssumedReadOnly(); + ImmutableCallSite ICS(&getAnchorValue()); + + // Helper to determine if noalias is prevented by the memory access + // instruction I which accesses Ptr of memory kind MLK. + auto AccessPred = [&](const Instruction *I, const Value *Ptr, + AAMemoryLocation::AccessKind Kind, + AAMemoryLocation::MemoryLocationsKind MLK) { + LLVM_DEBUG({ + dbgs() << "[AANoAlias] Check access by "; + if (I) + dbgs() << *I << " to "; + else + dbgs() << " to "; + if (Ptr) + dbgs() << *Ptr << " [" + << AAMemoryLocation::getMemoryLocationsAsStr(MLK) << "]\n"; + else + dbgs() << " [" + << AAMemoryLocation::getMemoryLocationsAsStr(MLK) << "]\n"; + }); + + // Ignore "read-read" "dependences". + if (Kind == AAMemoryLocation::READ && IsReadOnly) { + A.recordDependence(MemBehaviorAA, *this, DepClassTy::OPTIONAL); + return true; + } + if (!Ptr) + return false; + if (auto *PtrArg = dyn_cast(Ptr)) + return !mayAliasWithArgument(A, AAR, MemBehaviorAA, ICS, + PtrArg->getArgNo()); + + if (!AAR) + AAR = A.getInfoCache().getAAResultsForFunction(*getAnchorScope()); + + assert(isa(Ptr) && "Expected global value."); + bool IsAliasing = !AAR || !AAR->isNoAlias(&getAssociatedValue(), Ptr); + LLVM_DEBUG(dbgs() << "[AANoAlias] Check alias at " + "callsite: " + << getAssociatedValue() << " | " << *Ptr << " => " + << (IsAliasing ? "" : "no-") << "alias \n"); + + return !IsAliasing; + }; + + // We can and want to check arguments and globals for aliasing. + AAMemoryLocation::MemoryLocationsKind LocationsNotToCheck = + AAMemoryLocation::NO_ARGUMENT_MEM; + + // If the definition is not `noalias` we need to check globals in addition + // to arguments. If the definition is `noalias` we cannot alias globals to + // begin with. + bool AssociatedValueIsNoAliasAtDef = NoAliasAA.isAssumedNoAlias(); + if (!AssociatedValueIsNoAliasAtDef) + LocationsNotToCheck |= AAMemoryLocation::NO_GLOBAL_MEM; + else + A.recordDependence(NoAliasAA, *this, DepClassTy::OPTIONAL); + + AAMemoryLocation::MemoryLocationsKind LocationsToCheck = + AAMemoryLocation::inverseLocation(LocationsNotToCheck, false, false); + if (!MemLocationAA.checkForAllAccessesToMemoryKind(AccessPred, + LocationsToCheck)) + return false; + + A.recordDependence(MemLocationAA, *this, DepClassTy::OPTIONAL); + return true; + } + + /// Perform the alias check in the callee. We basically check if all + /// accesses in the callee do not violate the `noalias` property for the + /// underlying call site argument. A violation would be an access that may not + /// be derived from the argument but which aliases it. Note that this allows + /// accesses to unknown memory as long as AliasAnalysis knows it will not + /// alias with the associated argument. + bool + isKnownNoAliasInCalleeDueToAccesses(Attributor &A, + const AAMemoryBehavior &MemBehaviorAA, + const AAMemoryLocation &MemLocationAA) { + bool IsReadOnly = MemBehaviorAA.isAssumedReadOnly(); + Argument *AssociatedArg = getAssociatedArgument(); + AAResults *AAR = nullptr; + + // Helper to determine if noalias is prevented by the memory access + // instruction I which accesses Ptr of memory kind MLK. + auto AccessPred = [&](const Instruction *I, const Value *Ptr, + AAMemoryLocation::AccessKind Kind, + AAMemoryLocation::MemoryLocationsKind MLK) { + LLVM_DEBUG({ + dbgs() << "[AANoAlias] Check access by "; + if (I) + dbgs() << *I << " to "; + else + dbgs() << " to "; + if (Ptr) + dbgs() << *Ptr << " [" + << AAMemoryLocation::getMemoryLocationsAsStr(MLK) << "]\n"; + else + dbgs() << " [" + << AAMemoryLocation::getMemoryLocationsAsStr(MLK) << "]\n"; + }); + + // Ignore "read-read" "dependences". + if (Kind == AAMemoryLocation::READ && IsReadOnly) { + A.recordDependence(MemBehaviorAA, *this, DepClassTy::OPTIONAL); + return true; + } + if (!Ptr) + return false; + + // Ignore accesses derived from this argument. + if (auto *PtrArg = dyn_cast(Ptr)) + if (AssociatedArg == PtrArg) + return true; + + if (!AAR) + AAR = A.getInfoCache().getAAResultsForFunction( + *AssociatedArg->getParent()); + + bool IsAliasing = !AAR || !AAR->isNoAlias(AssociatedArg, Ptr); + LLVM_DEBUG(dbgs() << "[AANoAlias] Check alias in callee: " + << *AssociatedArg << " : " << *Ptr << " => " + << (IsAliasing ? "" : "no-") << "alias \n"); + + return !IsAliasing; + }; + + // We can and want to check arguments against all but local and inaccesible + // memory. Arguments are by definition not aliasing either of those. + AAMemoryLocation::MemoryLocationsKind LocationsToCheck = + AAMemoryLocation::ALL_LOCATIONS | AAMemoryLocation::NO_LOCAL_MEM | + AAMemoryLocation::NO_INACCESSIBLE_MEM; + + if (!MemLocationAA.checkForAllAccessesToMemoryKind(AccessPred, + LocationsToCheck)) + return false; + + A.recordDependence(MemLocationAA, *this, DepClassTy::OPTIONAL); + return true; + } + /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // If the argument is readnone we are done as there are no accesses via the @@ -2787,6 +2955,22 @@ return ChangeStatus::UNCHANGED; } + auto &MemLocationAA = A.getAAFor( + *this, IRPosition::function_scope(getIRPosition()), + /* TrackDependence */ false); + if (isKnownNoAliasAtCallSiteDueToAccesses(A, AAR, MemBehaviorAA, NoAliasAA, + MemLocationAA)) { + LLVM_DEBUG( + dbgs() << "[AANoAlias] No-Alias deduced via call site accesses\n"); + return ChangeStatus::UNCHANGED; + } + + if (isKnownNoAliasInCalleeDueToAccesses(A, MemBehaviorAA, MemLocationAA)) { + LLVM_DEBUG( + dbgs() << "[AANoAlias] No-Alias deduced via callee accesses\n"); + return ChangeStatus::UNCHANGED; + } + return indicatePessimisticFixpoint(); } diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/control-flow.ll @@ -4,7 +4,7 @@ ; Don't promote around control flow. define internal i32 @callee(i1 %C, i32* %P) { ; CHECK-LABEL: define {{[^@]+}}@callee -; CHECK-SAME: (i1 [[C:%.*]], i32* nocapture nofree readonly [[P:%.*]]) +; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree readonly [[P:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] ; CHECK: T: @@ -28,7 +28,7 @@ ; CHECK-LABEL: define {{[^@]+}}@foo ; CHECK-SAME: (i1 [[C:%.*]], i32* nocapture nofree readonly [[P:%.*]]) ; CHECK-NEXT: entry: -; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i1 [[C]], i32* nocapture nofree readonly [[P]]) +; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i1 [[C]], i32* noalias nocapture nofree readonly [[P]]) ; CHECK-NEXT: ret i32 [[X]] ; entry: diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/live_called_from_dead_2.ll @@ -25,7 +25,7 @@ ; OLDPM_MODULE-NEXT: unreachable ; ; OLDPM_CGSCC-LABEL: define {{[^@]+}}@test -; OLDPM_CGSCC-SAME: (i32* nocapture nofree writeonly [[X:%.*]]) +; OLDPM_CGSCC-SAME: (i32* noalias nocapture nofree writeonly [[X:%.*]]) ; OLDPM_CGSCC-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]] ; OLDPM_CGSCC: live: ; OLDPM_CGSCC-NEXT: store i32 0, i32* [[X]] @@ -43,7 +43,7 @@ ; NEWPM_MODULE-NEXT: unreachable ; ; NEWPM_CGSCC-LABEL: define {{[^@]+}}@test -; NEWPM_CGSCC-SAME: (i32* nocapture nofree writeonly [[X:%.*]]) +; NEWPM_CGSCC-SAME: (i32* noalias nocapture nofree writeonly [[X:%.*]]) ; NEWPM_CGSCC-NEXT: br i1 true, label [[LIVE:%.*]], label [[DEAD:%.*]] ; NEWPM_CGSCC: live: ; NEWPM_CGSCC-NEXT: store i32 0, i32* [[X]] @@ -73,7 +73,7 @@ ; OLDPM_CGSCC-SAME: (i32* nocapture nofree writeonly [[B:%.*]]) ; OLDPM_CGSCC-NEXT: [[A:%.*]] = alloca i32 ; OLDPM_CGSCC-NEXT: store i32 1, i32* [[A]], align 4 -; OLDPM_CGSCC-NEXT: [[C:%.*]] = call i32 @test(i32* nocapture nofree writeonly [[B]]) +; OLDPM_CGSCC-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree writeonly [[B]]) ; OLDPM_CGSCC-NEXT: ret i32 0 ; ; NEWPM_MODULE-LABEL: define {{[^@]+}}@caller @@ -87,7 +87,7 @@ ; NEWPM_CGSCC-SAME: (i32* nocapture nofree writeonly [[B:%.*]]) ; NEWPM_CGSCC-NEXT: [[A:%.*]] = alloca i32 ; NEWPM_CGSCC-NEXT: store i32 1, i32* [[A]], align 4 -; NEWPM_CGSCC-NEXT: [[C:%.*]] = call i32 @test(i32* nocapture nofree writeonly [[B]]) +; NEWPM_CGSCC-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree writeonly [[B]]) ; NEWPM_CGSCC-NEXT: ret i32 undef ; %A = alloca i32 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/musttail.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/musttail.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/musttail.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/musttail.ll @@ -8,7 +8,7 @@ define internal i32 @test(%T* %p) { ; CHECK-LABEL: define {{[^@]+}}@test -; CHECK-SAME: (%T* nocapture nofree readonly [[P:%.*]]) +; CHECK-SAME: (%T* noalias nocapture nofree readonly [[P:%.*]]) ; CHECK-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P]], i64 0, i32 3 ; CHECK-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], %T* [[P]], i64 0, i32 2 ; CHECK-NEXT: [[A:%.*]] = load i32, i32* [[A_GEP]] @@ -27,7 +27,7 @@ define i32 @caller(%T* %p) { ; CHECK-LABEL: define {{[^@]+}}@caller ; CHECK-SAME: (%T* nocapture nofree readonly [[P:%.*]]) -; CHECK-NEXT: [[V:%.*]] = musttail call i32 @test(%T* nocapture nofree readonly [[P]]) +; CHECK-NEXT: [[V:%.*]] = musttail call i32 @test(%T* noalias nocapture nofree readonly [[P]]) ; CHECK-NEXT: ret i32 [[V]] ; %v = musttail call i32 @test(%T* %p) @@ -81,7 +81,7 @@ define internal i32 @test2b(%T* %p, i32 %p2) { ; CHECK-LABEL: define {{[^@]+}}@test2b -; CHECK-SAME: (%T* nocapture nofree readonly [[P:%.*]], i32 [[P2:%.*]]) +; CHECK-SAME: (%T* noalias nocapture nofree readonly [[P:%.*]], i32 [[P2:%.*]]) ; CHECK-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P]], i64 0, i32 3 ; CHECK-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], %T* [[P]], i64 0, i32 2 ; CHECK-NEXT: [[A:%.*]] = load i32, i32* [[A_GEP]] @@ -102,7 +102,7 @@ define i32 @caller2b(%T* %g) { ; CHECK-LABEL: define {{[^@]+}}@caller2b ; CHECK-SAME: (%T* nocapture nofree readonly [[G:%.*]]) -; CHECK-NEXT: [[V:%.*]] = call i32 @test2b(%T* nocapture nofree readonly [[G]], i32 undef) +; CHECK-NEXT: [[V:%.*]] = call i32 @test2b(%T* noalias nocapture nofree readonly [[G]], i32 undef) ; CHECK-NEXT: ret i32 0 ; %v = call i32 @test2b(%T* %g, i32 0) diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr32917.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr32917.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr32917.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr32917.ll @@ -1,17 +1,25 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes -; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s +; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s --check-prefixes=CHECK,BASIC_AA +; RUN: opt -S -passes='require,attributor' -aa-pipeline='globals-aa,basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s -check-prefixes=CHECK,GLOBALS_AA ; PR 32917 @b = common local_unnamed_addr global i32 0, align 4 -@a = common local_unnamed_addr global i32 0, align 4 +@a = private local_unnamed_addr global i32 0, align 4 define i32 @fn2() local_unnamed_addr { -; CHECK-LABEL: define {{[^@]+}}@fn2() local_unnamed_addr -; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 -; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64 -; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to i32* -; CHECK-NEXT: call fastcc void @fn1(i32* nofree readonly align 4 [[TMP3]]) -; CHECK-NEXT: ret i32 undef +; BASIC_AA-LABEL: define {{[^@]+}}@fn2() local_unnamed_addr +; BASIC_AA-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 +; BASIC_AA-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64 +; BASIC_AA-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to i32* +; BASIC_AA-NEXT: call fastcc void @fn1(i32* nofree readonly align 4 [[TMP3]]) +; BASIC_AA-NEXT: ret i32 undef +; +; GLOBALS_AA-LABEL: define {{[^@]+}}@fn2() local_unnamed_addr +; GLOBALS_AA-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4 +; GLOBALS_AA-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64 +; GLOBALS_AA-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to i32* +; GLOBALS_AA-NEXT: call fastcc void @fn1(i32* noalias nofree readonly align 4 [[TMP3]]) +; GLOBALS_AA-NEXT: ret i32 undef ; %1 = load i32, i32* @b, align 4 %2 = sext i32 %1 to i64 @@ -21,12 +29,19 @@ } define internal fastcc void @fn1(i32* nocapture readonly) unnamed_addr { -; CHECK-LABEL: define {{[^@]+}}@fn1 -; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 [[TMP0:%.*]]) unnamed_addr -; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 -1 -; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4 -; CHECK-NEXT: store i32 [[TMP3]], i32* @a, align 4 -; CHECK-NEXT: ret void +; BASIC_AA-LABEL: define {{[^@]+}}@fn1 +; BASIC_AA-SAME: (i32* nocapture nofree nonnull readonly align 4 [[TMP0:%.*]]) unnamed_addr +; BASIC_AA-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 -1 +; BASIC_AA-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4 +; BASIC_AA-NEXT: store i32 [[TMP3]], i32* @a, align 4 +; BASIC_AA-NEXT: ret void +; +; GLOBALS_AA-LABEL: define {{[^@]+}}@fn1 +; GLOBALS_AA-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 [[TMP0:%.*]]) unnamed_addr +; GLOBALS_AA-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 -1 +; GLOBALS_AA-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4 +; GLOBALS_AA-NEXT: store i32 [[TMP3]], i32* @a, align 4 +; GLOBALS_AA-NEXT: ret void ; %2 = getelementptr inbounds i32, i32* %0, i64 -1 %3 = load i32, i32* %2, align 4 diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll @@ -15,7 +15,7 @@ define internal fastcc void @fn(i32* nocapture readonly %p1, i64* nocapture readonly %p2) { ; CHECK-LABEL: define {{[^@]+}}@fn -; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P1:%.*]]) +; CHECK-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P1:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* @g, align 4, !tbaa !0 ; CHECK-NEXT: [[CONV1:%.*]] = trunc i32 [[TMP0]] to i8 @@ -38,7 +38,7 @@ ; CHECK-NEXT: store i32* @g, i32** [[TMP0]], align 8, !tbaa !5 ; CHECK-NEXT: [[TMP1:%.*]] = load i32*, i32** @a, align 8, !tbaa !5 ; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 4, !tbaa !0 -; CHECK-NEXT: call fastcc void @fn(i32* nofree nonnull readonly align 4 dereferenceable(4) @g) +; CHECK-NEXT: call fastcc void @fn(i32* noalias nofree nonnull readonly align 4 dereferenceable(4) @g) ; CHECK-NEXT: ret i32 0 ; entry: diff --git a/llvm/test/Transforms/Attributor/dereferenceable-1.ll b/llvm/test/Transforms/Attributor/dereferenceable-1.ll --- a/llvm/test/Transforms/Attributor/dereferenceable-1.ll +++ b/llvm/test/Transforms/Attributor/dereferenceable-1.ll @@ -226,7 +226,7 @@ define internal void @fill_range_not_inbounds(i32* %p, i64 %start){ ; ATTRIBUTOR-LABEL: define {{[^@]+}}@fill_range_not_inbounds ; NOTE: %p should not be dereferenceable -; ATTRIBUTOR-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) +; ATTRIBUTOR-SAME: (i32* noalias nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) ; ATTRIBUTOR-NEXT: entry: ; ATTRIBUTOR-NEXT: [[TMP0:%.*]] = add nsw i64 [[START:%.*]], 9 ; ATTRIBUTOR-NEXT: br label [[FOR_BODY:%.*]] @@ -260,7 +260,7 @@ define internal void @fill_range_inbounds(i32* %p, i64 %start){ ; ATTRIBUTOR-LABEL: define {{[^@]+}}@fill_range_inbounds ; FIXME: %p should be dereferenceable(40) -; ATTRIBUTOR-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) +; ATTRIBUTOR-SAME: (i32* noalias nocapture nofree writeonly [[P:%.*]], i64 [[START:%.*]]) ; ATTRIBUTOR-NEXT: entry: ; ATTRIBUTOR-NEXT: [[TMP0:%.*]] = add nsw i64 [[START:%.*]], 9 ; ATTRIBUTOR-NEXT: br label [[FOR_BODY:%.*]] @@ -297,8 +297,8 @@ ; ATTRIBUTOR-SAME: (i32* nocapture nofree writeonly [[P:%.*]], i64* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[RANGE:%.*]]) ; ATTRIBUTOR-NEXT: entry: ; ATTRIBUTOR-NEXT: [[TMP0:%.*]] = load i64, i64* [[RANGE:%.*]], align 8, !range !0 -; ATTRIBUTOR-NEXT: tail call void @fill_range_inbounds(i32* nocapture nofree writeonly [[P:%.*]], i64 [[TMP0]]) -; ATTRIBUTOR-NEXT: tail call void @fill_range_not_inbounds(i32* nocapture nofree writeonly [[P]], i64 [[TMP0]]) +; ATTRIBUTOR-NEXT: tail call void @fill_range_inbounds(i32* noalias nocapture nofree writeonly [[P:%.*]], i64 [[TMP0]]) +; ATTRIBUTOR-NEXT: tail call void @fill_range_not_inbounds(i32* noalias nocapture nofree writeonly [[P]], i64 [[TMP0]]) ; ATTRIBUTOR-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/Attributor/internal-noalias.ll b/llvm/test/Transforms/Attributor/internal-noalias.ll --- a/llvm/test/Transforms/Attributor/internal-noalias.ll +++ b/llvm/test/Transforms/Attributor/internal-noalias.ll @@ -8,7 +8,7 @@ ret i32 %add } -; CHECK: define private i32 @noalias_args(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) +; CHECK: define private i32 @noalias_args(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) define private i32 @noalias_args(i32* %A, i32* %B) #0 { entry: @@ -21,7 +21,7 @@ } -; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) +; CHECK: define internal i32 @noalias_args_argmem(i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 { entry: %0 = load i32, i32* %A, align 4 diff --git a/llvm/test/Transforms/Attributor/memory_locations.ll b/llvm/test/Transforms/Attributor/memory_locations.ll --- a/llvm/test/Transforms/Attributor/memory_locations.ll +++ b/llvm/test/Transforms/Attributor/memory_locations.ll @@ -210,7 +210,7 @@ ; MODULE-LABEL: define {{[^@]+}}@internal_argmem_only_rec ; MODULE-SAME: (i32* nocapture align 4 [[ARG:%.*]]) ; MODULE-NEXT: entry: -; MODULE-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_1(i32* nocapture align 4 [[ARG]]) +; MODULE-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_1(i32* noalias nocapture align 4 [[ARG]]) ; MODULE-NEXT: ret i8* [[CALL]] ; ; CGSCC-LABEL: define {{[^@]+}}@internal_argmem_only_rec @@ -226,30 +226,55 @@ define internal i8* @internal_argmem_only_rec_1(i32* %arg) { ; CHECK: Function Attrs: inaccessiblemem_or_argmemonly -; CHECK-LABEL: define {{[^@]+}}@internal_argmem_only_rec_1 -; CHECK-SAME: (i32* nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]]) -; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP:%.*]] = load i32, i32* [[ARG]], align 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP]], 0 -; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -; CHECK: if.then: -; CHECK-NEXT: br label [[RETURN:%.*]] -; CHECK: if.end: -; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARG]], align 4 -; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 1 -; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] -; CHECK: if.then2: -; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 -1 -; CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_2(i32* nocapture nonnull align 4 dereferenceable(4) [[ADD_PTR]]) -; CHECK-NEXT: br label [[RETURN]] -; CHECK: if.end3: -; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[ARG]], align 4 -; CHECK-NEXT: [[CONV:%.*]] = sext i32 [[TMP2]] to i64 -; CHECK-NEXT: [[CALL4:%.*]] = call noalias i8* @malloc(i64 [[CONV]]) -; CHECK-NEXT: br label [[RETURN]] -; CHECK: return: -; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i8* [ null, [[IF_THEN]] ], [ [[CALL]], [[IF_THEN2]] ], [ [[CALL4]], [[IF_END3]] ] -; CHECK-NEXT: ret i8* [[RETVAL_0]] +; MODULE-LABEL: define {{[^@]+}}@internal_argmem_only_rec_1 +; MODULE-SAME: (i32* noalias nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]]) +; MODULE-NEXT: entry: +; MODULE-NEXT: [[TMP:%.*]] = load i32, i32* [[ARG]], align 4 +; MODULE-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP]], 0 +; MODULE-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; MODULE: if.then: +; MODULE-NEXT: br label [[RETURN:%.*]] +; MODULE: if.end: +; MODULE-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARG]], align 4 +; MODULE-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 1 +; MODULE-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] +; MODULE: if.then2: +; MODULE-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 -1 +; MODULE-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_2(i32* noalias nocapture nonnull align 4 dereferenceable(4) [[ADD_PTR]]) +; MODULE-NEXT: br label [[RETURN]] +; MODULE: if.end3: +; MODULE-NEXT: [[TMP2:%.*]] = load i32, i32* [[ARG]], align 4 +; MODULE-NEXT: [[CONV:%.*]] = sext i32 [[TMP2]] to i64 +; MODULE-NEXT: [[CALL4:%.*]] = call noalias i8* @malloc(i64 [[CONV]]) +; MODULE-NEXT: br label [[RETURN]] +; MODULE: return: +; MODULE-NEXT: [[RETVAL_0:%.*]] = phi i8* [ null, [[IF_THEN]] ], [ [[CALL]], [[IF_THEN2]] ], [ [[CALL4]], [[IF_END3]] ] +; MODULE-NEXT: ret i8* [[RETVAL_0]] +; +; CGSCC-LABEL: define {{[^@]+}}@internal_argmem_only_rec_1 +; CGSCC-SAME: (i32* nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]]) +; CGSCC-NEXT: entry: +; CGSCC-NEXT: [[TMP:%.*]] = load i32, i32* [[ARG]], align 4 +; CGSCC-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP]], 0 +; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CGSCC: if.then: +; CGSCC-NEXT: br label [[RETURN:%.*]] +; CGSCC: if.end: +; CGSCC-NEXT: [[TMP1:%.*]] = load i32, i32* [[ARG]], align 4 +; CGSCC-NEXT: [[CMP1:%.*]] = icmp eq i32 [[TMP1]], 1 +; CGSCC-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] +; CGSCC: if.then2: +; CGSCC-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 -1 +; CGSCC-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_2(i32* noalias nocapture nonnull align 4 dereferenceable(4) [[ADD_PTR]]) +; CGSCC-NEXT: br label [[RETURN]] +; CGSCC: if.end3: +; CGSCC-NEXT: [[TMP2:%.*]] = load i32, i32* [[ARG]], align 4 +; CGSCC-NEXT: [[CONV:%.*]] = sext i32 [[TMP2]] to i64 +; CGSCC-NEXT: [[CALL4:%.*]] = call noalias i8* @malloc(i64 [[CONV]]) +; CGSCC-NEXT: br label [[RETURN]] +; CGSCC: return: +; CGSCC-NEXT: [[RETVAL_0:%.*]] = phi i8* [ null, [[IF_THEN]] ], [ [[CALL]], [[IF_THEN2]] ], [ [[CALL4]], [[IF_END3]] ] +; CGSCC-NEXT: ret i8* [[RETVAL_0]] ; entry: %tmp = load i32, i32* %arg, align 4 @@ -283,11 +308,11 @@ define internal i8* @internal_argmem_only_rec_2(i32* %arg) { ; CHECK: Function Attrs: inaccessiblemem_or_argmemonly ; CHECK-LABEL: define {{[^@]+}}@internal_argmem_only_rec_2 -; CHECK-SAME: (i32* nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]]) +; CHECK-SAME: (i32* noalias nocapture nonnull align 4 dereferenceable(4) [[ARG:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: store i32 0, i32* [[ARG]], align 4 ; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARG]], i64 -1 -; CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_1(i32* nocapture nonnull align 4 dereferenceable(4) [[ADD_PTR]]) +; CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @internal_argmem_only_rec_1(i32* noalias nocapture nonnull align 4 dereferenceable(4) [[ADD_PTR]]) ; CHECK-NEXT: ret i8* [[CALL]] ; entry: diff --git a/llvm/test/Transforms/Attributor/misc.ll b/llvm/test/Transforms/Attributor/misc.ll --- a/llvm/test/Transforms/Attributor/misc.ll +++ b/llvm/test/Transforms/Attributor/misc.ll @@ -9,7 +9,7 @@ ; CHECK-SAME: (void (i8*)* [[FP:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]]) +; CHECK-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]]) ; CHECK-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) ; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo) ; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*)) @@ -22,7 +22,7 @@ ; DECL_CS-SAME: (void (i8*)* [[FP:%.*]]) ; DECL_CS-NEXT: entry: ; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4 -; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]]) +; DECL_CS-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]]) ; DECL_CS-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*)) ; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo) ; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*)) @@ -49,7 +49,7 @@ ; CHECK-SAME: (void (i8*)* [[FP:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]]) +; CHECK-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]]) ; CHECK-NEXT: call void @callback1(void (i32*)* nonnull @foo) ; CHECK-NEXT: call void @callback2(void (i8*)* bitcast (void (i32*)* @foo to void (i8*)*)) ; CHECK-NEXT: call void @callback2(void (i8*)* [[FP]]) @@ -63,7 +63,7 @@ ; DECL_CS-SAME: (void (i8*)* [[FP:%.*]]) ; DECL_CS-NEXT: entry: ; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4 -; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]]) +; DECL_CS-NEXT: call void @foo(i32* noalias nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[A]]) ; DECL_CS-NEXT: call void @callback1(void (i32*)* nonnull @foo) ; DECL_CS-NEXT: call void @callback2(void (i8*)* nonnull bitcast (void (i32*)* @foo to void (i8*)*)) ; DECL_CS-NEXT: call void @callback2(void (i8*)* [[FP]]) diff --git a/llvm/test/Transforms/Attributor/noalias.ll b/llvm/test/Transforms/Attributor/noalias.ll --- a/llvm/test/Transforms/Attributor/noalias.ll +++ b/llvm/test/Transforms/Attributor/noalias.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 < %s | FileCheck %s +; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 < %s | FileCheck %s ; TEST 1 - negative. diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll --- a/llvm/test/Transforms/Attributor/nonnull.ll +++ b/llvm/test/Transforms/Attributor/nonnull.ll @@ -190,7 +190,7 @@ define internal i32* @f1(i32* %arg) { ; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull readonly %arg) -; ATTRIBUTOR: define internal nonnull i32* @f1(i32* nofree readonly %arg) +; ATTRIBUTOR: define internal nonnull i32* @f1(i32* noalias nofree readonly %arg) bb: %tmp = icmp eq i32* %arg, null @@ -203,14 +203,14 @@ bb4: ; preds = %bb1 %tmp5 = getelementptr inbounds i32, i32* %arg, i64 1 -; ATTRIBUTOR: %tmp5b = tail call nonnull i32* @f3(i32* nofree nonnull readonly %tmp5) +; ATTRIBUTOR: %tmp5b = tail call nonnull i32* @f3(i32* noalias nofree nonnull readonly %tmp5) %tmp5b = tail call i32* @f3(i32* %tmp5) %tmp5c = getelementptr inbounds i32, i32* %tmp5b, i64 -1 br label %bb9 bb6: ; preds = %bb1 ; FIXME: missing nonnull. It should be @f2(i32* nonnull %arg) -; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* nofree readonly %arg) +; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* noalias nofree readonly %arg) %tmp7 = tail call i32* @f2(i32* %arg) ret i32* %tmp7 @@ -221,21 +221,22 @@ define internal i32* @f2(i32* %arg) { ; FIXME: missing nonnull. It should be nonnull @f2(i32* nonnull %arg) -; ATTRIBUTOR: define internal nonnull i32* @f2(i32* nofree readonly %arg) +; ATTRIBUTOR: define internal nonnull i32* @f2(i32* noalias nofree readonly %arg) bb: ; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg) -; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* nofree readonly %arg) +; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* noalias nofree readonly %arg) %tmp = tail call i32* @f1(i32* %arg) ret i32* %tmp } define dso_local noalias i32* @f3(i32* %arg) { +; FIXME: %arg can be noalias as well ; FIXME: missing nonnull. It should be nonnull @f3(i32* nonnull readonly %arg) ; ATTRIBUTOR: define dso_local noalias nonnull i32* @f3(i32* nofree readonly %arg) bb: ; FIXME: missing nonnull. It should be @f1(i32* nonnull readonly %arg) -; ATTRIBUTOR: %tmp = call nonnull i32* @f1(i32* nofree readonly %arg) +; ATTRIBUTOR: %tmp = call nonnull i32* @f1(i32* noalias nofree readonly %arg) %tmp = call i32* @f1(i32* %arg) ret i32* %tmp } diff --git a/llvm/test/Transforms/Attributor/range.ll b/llvm/test/Transforms/Attributor/range.ll --- a/llvm/test/Transforms/Attributor/range.ll +++ b/llvm/test/Transforms/Attributor/range.ll @@ -20,12 +20,12 @@ ; ; OLD_PM-LABEL: define {{[^@]+}}@test0-range-check ; OLD_PM-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; OLD_PM-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 +; OLD_PM-NEXT: [[A:%.*]] = tail call i32 @test0(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 ; OLD_PM-NEXT: ret i32 [[A]] ; ; NEW_PM-LABEL: define {{[^@]+}}@test0-range-check ; NEW_PM-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; NEW_PM-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 +; NEW_PM-NEXT: [[A:%.*]] = tail call i32 @test0(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 ; NEW_PM-NEXT: ret i32 [[A]] ; ; CGSCC_OLD_PM-LABEL: define {{[^@]+}}@test0-range-check @@ -40,7 +40,7 @@ ; ; MODULE-LABEL: define {{[^@]+}}@test0-range-check ; MODULE-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; MODULE-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 +; MODULE-NEXT: [[A:%.*]] = tail call i32 @test0(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 ; MODULE-NEXT: ret i32 [[A]] ; CGSCC-LABEL: define {{[^@]+}}@test0-range-check ; CGSCC-SAME: (i32* nocapture nofree nonnull readonly dereferenceable(4) [[P:%.*]]) @@ -65,7 +65,7 @@ define void @test0-icmp-check(i32* %p){ ; OLD_PM-LABEL: define {{[^@]+}}@test0-icmp-check ; OLD_PM-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; OLD_PM-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 +; OLD_PM-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 ; OLD_PM-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9 ; OLD_PM-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8 ; OLD_PM-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1 @@ -112,7 +112,7 @@ ; ; NEW_PM-LABEL: define {{[^@]+}}@test0-icmp-check ; NEW_PM-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; NEW_PM-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 +; NEW_PM-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 ; NEW_PM-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9 ; NEW_PM-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8 ; NEW_PM-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1 @@ -293,7 +293,7 @@ ; ; MODULE-LABEL: define {{[^@]+}}@test0-icmp-check ; MODULE-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; MODULE-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 +; MODULE-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !0 ; MODULE-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9 ; MODULE-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8 ; MODULE-NEXT: [[CMP_EQ_4:%.*]] = icmp eq i32 [[RET]], 1 @@ -505,13 +505,13 @@ define i1 @test1-check(i32* %p) { ; OLD_PM-LABEL: define {{[^@]+}}@test1-check ; OLD_PM-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; OLD_PM-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !2 +; OLD_PM-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !2 ; OLD_PM-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500 ; OLD_PM-NEXT: ret i1 [[CMP]] ; ; NEW_PM-LABEL: define {{[^@]+}}@test1-check ; NEW_PM-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; NEW_PM-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !2 +; NEW_PM-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !2 ; NEW_PM-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500 ; NEW_PM-NEXT: ret i1 [[CMP]] ; @@ -529,7 +529,7 @@ ; ; MODULE-LABEL: define {{[^@]+}}@test1-check ; MODULE-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; MODULE-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !2 +; MODULE-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* noalias nocapture nofree readonly [[P]]) #{{[0-9]+}}, !range !2 ; MODULE-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500 ; MODULE-NEXT: ret i1 [[CMP]] ; CGSCC-LABEL: define {{[^@]+}}@test1-check diff --git a/llvm/test/Transforms/Attributor/value-simplify.ll b/llvm/test/Transforms/Attributor/value-simplify.ll --- a/llvm/test/Transforms/Attributor/value-simplify.ll +++ b/llvm/test/Transforms/Attributor/value-simplify.ll @@ -208,7 +208,7 @@ define internal void @test_sret(%struct.X* sret %a, %struct.X** %b) { ; CHECK-LABEL: define {{[^@]+}}@test_sret -; CHECK-SAME: (%struct.X* noalias nofree sret writeonly align 536870912 [[A:%.*]], %struct.X** nocapture nofree nonnull writeonly dereferenceable(8) [[B:%.*]]) +; CHECK-SAME: (%struct.X* noalias nofree sret writeonly align 536870912 [[A:%.*]], %struct.X** noalias nocapture nofree nonnull writeonly dereferenceable(8) [[B:%.*]]) ; CHECK-NEXT: store %struct.X* [[A]], %struct.X** [[B]] ; CHECK-NEXT: ret void ; @@ -218,7 +218,7 @@ define void @complicated_args_sret(%struct.X** %b) { ; CHECK-LABEL: define {{[^@]+}}@complicated_args_sret ; CHECK-SAME: (%struct.X** nocapture nofree writeonly [[B:%.*]]) -; CHECK-NEXT: call void @test_sret(%struct.X* noalias nofree writeonly align 536870912 null, %struct.X** nocapture nofree writeonly [[B]]) +; CHECK-NEXT: call void @test_sret(%struct.X* noalias nofree writeonly align 536870912 null, %struct.X** noalias nocapture nofree writeonly [[B]]) ; CHECK-NEXT: ret void ; call void @test_sret(%struct.X* null, %struct.X** %b)