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 @@ -2697,6 +2697,148 @@ return true; } + bool isKnownNoAliasAtCallSiteDueToAccesses( + Attributor &A, AAResults *&AAR, const AAMemoryBehavior &MemBehaviorAA, + const AANoAlias &NoAliasAA, const AAMemoryLocation &MemLocationAA) { + // 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. + + 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(); + Argument *AssociatedArg = getAssociatedArgument(); + 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({ + if (Ptr) + dbgs() << "[AANoAlias] Check access by " << I << " to " << *Ptr + << " [" << AAMemoryLocation::getMemoryLocationsAsStr(MLK) + << "]\n"; + else + dbgs() << "[AANoAlias] Check access by " << I << " to [" + << AAMemoryLocation::getMemoryLocationsAsStr(MLK) << "]\n"; + }); + 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; + } + + bool + isKnownNoAliasAtCalleeDueToAccesses(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 " << I << " to " << Ptr << " [" + << AAMemoryLocation::getMemoryLocationsAsStr(MLK) << "]\n"); + if (Kind == AAMemoryLocation::READ && IsReadOnly) { + A.recordDependence(MemBehaviorAA, *this, DepClassTy::OPTIONAL); + return true; + } + if (!Ptr) + return false; + 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 and globals for aliasing. + 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 @@ -2721,6 +2863,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 (isKnownNoAliasAtCalleeDueToAccesses(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/chained.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/chained.ll @@ -6,7 +6,7 @@ define internal i32 @test(i32** %x) { ; CHECK-LABEL: define {{[^@]+}}@test -; CHECK-SAME: (i32** nocapture nofree nonnull readonly align 8 dereferenceable(8) [[X:%.*]]) +; CHECK-SAME: (i32** noalias nocapture nofree nonnull readonly align 8 dereferenceable(8) [[X:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: [[Y:%.*]] = load i32*, i32** @G2, align 8 ; CHECK-NEXT: [[Z:%.*]] = load i32, i32* [[Y]] @@ -21,7 +21,7 @@ define i32 @caller() { ; CHECK-LABEL: define {{[^@]+}}@caller() ; CHECK-NEXT: entry: -; CHECK-NEXT: [[X:%.*]] = call i32 @test(i32** nofree nonnull readonly align 8 dereferenceable(8) @G2) +; CHECK-NEXT: [[X:%.*]] = call i32 @test(i32** noalias nofree nonnull readonly align 8 dereferenceable(8) @G2) ; CHECK-NEXT: ret i32 [[X]] ; entry: 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/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) @@ -46,7 +46,7 @@ define internal i32 @test2(%T* %p, i32 %p2) { ; CHECK-LABEL: define {{[^@]+}}@test2 -; CHECK-SAME: (%T* nocapture nofree readonly [[P:%.*]], i32 [[P2:%.*]]) +; CHECK-SAME: (%T* noalias nocapture nofree readonly [[P:%.*]], i32 [[P2:%.*]]) ; CHECK-NEXT: [[CA:%.*]] = musttail call i32 @foo(%T* undef, i32 undef) ; CHECK-NEXT: ret i32 [[CA]] ; @@ -62,7 +62,7 @@ define i32 @caller2(%T* %g) { ; CHECK-LABEL: define {{[^@]+}}@caller2 ; CHECK-SAME: (%T* nocapture nofree readonly [[G:%.*]]) -; CHECK-NEXT: [[V:%.*]] = call i32 @test2(%T* nocapture nofree readonly undef, i32 undef) +; CHECK-NEXT: [[V:%.*]] = call i32 @test2(%T* noalias nocapture nofree readonly undef, i32 undef) ; CHECK-NEXT: ret i32 0 ; %v = call i32 @test2(%T* %g, i32 0) 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 i64, i64* undef, align 8, !tbaa !0 ; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32 @@ -40,7 +40,7 @@ ; CHECK-NEXT: store i32* @g, i32** [[TMP0]], align 8, !tbaa !7 ; CHECK-NEXT: [[TMP1:%.*]] = load i32*, i32** @a, align 8, !tbaa !7 ; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 4, !tbaa !4 -; 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/ArgumentPromotion/variadic.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll @@ -18,7 +18,7 @@ ; CHECK-LABEL: define {{[^@]+}}@main ; CHECK-SAME: (i32 [[ARGC:%.*]], i8** nocapture nofree readnone [[ARGV:%.*]]) ; CHECK-NEXT: entry: -; CHECK-NEXT: tail call void (i8*, i8*, i8*, i8*, i8*, ...) @callee_t0f(i8* undef, i8* undef, i8* undef, i8* undef, i8* undef, %struct.tt0* nonnull byval align 8 dereferenceable(16) @t45) +; CHECK-NEXT: tail call void (i8*, i8*, i8*, i8*, i8*, ...) @callee_t0f(i8* undef, i8* undef, i8* undef, i8* undef, i8* undef, %struct.tt0* noalias nonnull byval align 8 dereferenceable(16) @t45) ; 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/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 @@ -15,7 +15,7 @@ define i32 @test0-range-check(i32* %p) { ; CHECK-LABEL: define {{[^@]+}}@test0-range-check ; CHECK-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; CHECK-NEXT: [[A:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly [[P]]) +; CHECK-NEXT: [[A:%.*]] = tail call i32 @test0(i32* noalias nocapture nofree readonly [[P]]) ; CHECK-SAME: !range !0 ; CHECK-NEXT: ret i32 [[A]] ; @@ -38,7 +38,7 @@ define void @test0-icmp-check(i32* %p){ ; CHECK-LABEL: define {{[^@]+}}@test0-icmp-check ; CHECK-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; CHECK-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* nocapture nofree readonly [[P]]) +; CHECK-NEXT: [[RET:%.*]] = tail call i32 @test0(i32* noalias nocapture nofree readonly [[P]]) ; CHECK-SAME: !range !0 ; CHECK-NEXT: [[CMP_EQ_2:%.*]] = icmp eq i32 [[RET]], 9 ; CHECK-NEXT: [[CMP_EQ_3:%.*]] = icmp eq i32 [[RET]], 8 @@ -186,7 +186,7 @@ define i1 @test1-check(i32* %p) { ; CHECK-LABEL: define {{[^@]+}}@test1-check ; CHECK-SAME: (i32* nocapture nofree readonly [[P:%.*]]) -; CHECK-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* nocapture nofree readonly [[P]]) +; CHECK-NEXT: [[RES:%.*]] = tail call i32 @test1(i32* noalias nocapture nofree readonly [[P]]) ; CHECK-SANME: !range !2 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[RES]], 500 ; CHECK-NEXT: ret i1 [[CMP]] 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 @@ -210,7 +210,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 ; @@ -220,7 +220,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) @@ -257,7 +257,7 @@ } define void @complicated_args_byval() { ; CHECK-LABEL: define {{[^@]+}}@complicated_args_byval() -; CHECK-NEXT: call void @test_byval(%struct.X* nofree nonnull readonly align 8 dereferenceable(8) @S) +; CHECK-NEXT: call void @test_byval(%struct.X* noalias nofree nonnull readonly align 8 dereferenceable(8) @S) ; CHECK-NEXT: ret void ; call void @test_byval(%struct.X* @S)