diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 306bfc43dce4f4..2cac89a9c7c892 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -2504,8 +2504,57 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl { indicateOptimisticFixpoint(); } - /// See AbstractAttribute::updateImpl(...). - ChangeStatus updateImpl(Attributor &A) override { + /// Determine if the underlying value may alias with the call site argument + /// \p OtherArgNo of \p ICS (= the underlying call site). + bool mayAliasWithArgument(Attributor &A, AAResults *&AAR, + const AAMemoryBehavior &MemBehaviorAA, + ImmutableCallSite ICS, unsigned OtherArgNo) { + // We do not need to worry about aliasing with the underlying IRP. + if (this->getArgNo() == (int)OtherArgNo) + return false; + + // If it is not a pointer or pointer vector we do not alias. + const Value *ArgOp = ICS.getArgOperand(OtherArgNo); + if (!ArgOp->getType()->isPtrOrPtrVectorTy()) + return false; + + auto &ICSArgMemBehaviorAA = A.getAAFor( + *this, IRPosition::callsite_argument(ICS, OtherArgNo), + /* TrackDependence */ false); + + // If the argument is readnone, there is no read-write aliasing. + if (ICSArgMemBehaviorAA.isAssumedReadNone()) { + A.recordDependence(ICSArgMemBehaviorAA, *this, DepClassTy::OPTIONAL); + return false; + } + + // If the argument is readonly and the underlying value is readonly, there + // is no read-write aliasing. + bool IsReadOnly = MemBehaviorAA.isAssumedReadOnly(); + if (ICSArgMemBehaviorAA.isAssumedReadOnly() && IsReadOnly) { + A.recordDependence(MemBehaviorAA, *this, DepClassTy::OPTIONAL); + A.recordDependence(ICSArgMemBehaviorAA, *this, DepClassTy::OPTIONAL); + return false; + } + + // We have to utilize actual alias analysis queries so we need the object. + if (!AAR) + AAR = A.getInfoCache().getAAResultsForFunction(*getAnchorScope()); + + // Try to rule it out at the call site. + bool IsAliasing = !AAR || !AAR->isNoAlias(&getAssociatedValue(), ArgOp); + LLVM_DEBUG(dbgs() << "[NoAliasCSArg] Check alias between " + "callsite arguments: " + << getAssociatedValue() << " " << *ArgOp << " => " + << (IsAliasing ? "" : "no-") << "alias \n"); + + return IsAliasing; + } + + bool + isKnownNoAliasDueToNoAliasPreservation(Attributor &A, AAResults *&AAR, + const AAMemoryBehavior &MemBehaviorAA, + const AANoAlias &NoAliasAA) { // We can deduce "noalias" if the following conditions hold. // (i) Associated value is assumed to be noalias in the definition. // (ii) Associated value is assumed to be no-capture in all the uses @@ -2513,62 +2562,64 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl { // (iii) There is no other pointer argument which could alias with the // value. - const Value &V = getAssociatedValue(); - const IRPosition IRP = IRPosition::value(V); - - // (i) Check whether noalias holds in the definition. - - auto &NoAliasAA = A.getAAFor(*this, IRP); - LLVM_DEBUG(dbgs() << "[AANoAliasCSArg] check definition: " << V - << " :: " << NoAliasAA << "\n"); - - if (!NoAliasAA.isAssumedNoAlias()) - return indicatePessimisticFixpoint(); - - LLVM_DEBUG(dbgs() << "[AANoAliasCSArg] " << V - << " is assumed NoAlias in the definition\n"); - - // (ii) Check whether the value is captured in the scope using AANoCapture. - // FIXME: This is conservative though, it is better to look at CFG and - // check only uses possibly executed before this callsite. + bool AssociatedValueIsNoAliasAtDef = NoAliasAA.isAssumedNoAlias(); + if (!AssociatedValueIsNoAliasAtDef) { + LLVM_DEBUG(dbgs() << "[AANoAlias] " << getAssociatedValue() + << " is not no-alias at the definition\n"); + return false; + } - auto &NoCaptureAA = A.getAAFor(*this, IRP); + const IRPosition &VIRP = IRPosition::value(getAssociatedValue()); + auto &NoCaptureAA = + A.getAAFor(*this, VIRP, /* TrackDependence */ false); + // Check whether the value is captured in the scope using AANoCapture. + // FIXME: This is conservative though, it is better to look at CFG and + // check only uses possibly executed before this callsite. if (!NoCaptureAA.isAssumedNoCaptureMaybeReturned()) { LLVM_DEBUG( - dbgs() << "[AANoAliasCSArg] " << V + dbgs() << "[AANoAliasCSArg] " << getAssociatedValue() << " cannot be noalias as it is potentially captured\n"); - return indicatePessimisticFixpoint(); + return false; } + A.recordDependence(NoCaptureAA, *this, DepClassTy::OPTIONAL); - // (iii) Check there is no other pointer argument which could alias with the - // value. + // Check there is no other pointer argument which could alias with the + // value passed at this call site. // TODO: AbstractCallSite ImmutableCallSite ICS(&getAnchorValue()); - for (unsigned i = 0; i < ICS.getNumArgOperands(); i++) { - if (getArgNo() == (int)i) - continue; - const Value *ArgOp = ICS.getArgOperand(i); - if (!ArgOp->getType()->isPointerTy()) - continue; + for (unsigned OtherArgNo = 0; OtherArgNo < ICS.getNumArgOperands(); + OtherArgNo++) + if (mayAliasWithArgument(A, AAR, MemBehaviorAA, ICS, OtherArgNo)) + return false; - if (const Function *F = getAnchorScope()) { - if (AAResults *AAR = A.getInfoCache().getAAResultsForFunction(*F)) { - bool IsAliasing = !AAR->isNoAlias(&getAssociatedValue(), ArgOp); - LLVM_DEBUG(dbgs() - << "[NoAliasCSArg] Check alias between " - "callsite arguments " - << AAR->isNoAlias(&getAssociatedValue(), ArgOp) << " " - << getAssociatedValue() << " " << *ArgOp << " => " - << (IsAliasing ? "" : "no-") << "alias \n"); - - if (!IsAliasing) - continue; - } - } - return indicatePessimisticFixpoint(); + 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 + // argument. + auto &MemBehaviorAA = + A.getAAFor(*this, getIRPosition(), + /* TrackDependence */ false); + if (MemBehaviorAA.isAssumedReadNone()) { + A.recordDependence(MemBehaviorAA, *this, DepClassTy::OPTIONAL); + return ChangeStatus::UNCHANGED; } - return ChangeStatus::UNCHANGED; + const IRPosition &VIRP = IRPosition::value(getAssociatedValue()); + const auto &NoAliasAA = A.getAAFor(*this, VIRP, + /* TrackDependence */ false); + + AAResults *AAR = nullptr; + if (isKnownNoAliasDueToNoAliasPreservation(A, AAR, MemBehaviorAA, + NoAliasAA)) { + LLVM_DEBUG( + dbgs() << "[AANoAlias] No-Alias deduced via no-alias preservation\n"); + return ChangeStatus::UNCHANGED; + } + + return indicatePessimisticFixpoint(); } /// See AbstractAttribute::trackStatistics() diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll index b42d4bc419b299..8ce8789bb8cc2d 100644 --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll @@ -29,7 +29,7 @@ entry: ; Function Attrs: nounwind uwtable define internal void @callee_t0f(i8* nocapture readnone %tp13, i8* nocapture readnone %tp14, i8* nocapture readnone %tp15, i8* nocapture readnone %tp16, i8* nocapture readnone %tp17, ...) { ; CHECK-LABEL: define {{[^@]+}}@callee_t0f -; CHECK-SAME: (i8* nocapture nofree nonnull readnone [[TP13:%.*]], i8* nocapture nofree nonnull readnone [[TP14:%.*]], i8* nocapture nofree nonnull readnone [[TP15:%.*]], i8* nocapture nofree nonnull readnone [[TP16:%.*]], i8* nocapture nofree nonnull readnone [[TP17:%.*]], ...) +; CHECK-SAME: (i8* noalias nocapture nofree nonnull readnone [[TP13:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP14:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP15:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP16:%.*]], i8* noalias nocapture nofree nonnull readnone [[TP17:%.*]], ...) ; CHECK-NEXT: entry: ; CHECK-NEXT: ret void ; diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll index 2aa6e61eea7890..846f0d9468b156 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/pthreads.ll @@ -34,9 +34,9 @@ define dso_local i32 @main() { ; CHECK-NEXT: [[ALLOC2:%.*]] = alloca i8, align 8 ; CHECK-NEXT: [[THREAD:%.*]] = alloca i64, align 8 ; CHECK-NEXT: [[CALL:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @foo, i8* noalias nofree readnone align 536870912 null) -; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*)) +; CHECK-NEXT: [[CALL1:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @bar, i8* noalias nofree nonnull readnone align 8 dereferenceable(8) bitcast (i8** @GlobalVPtr to i8*)) ; CHECK-NEXT: [[CALL2:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @baz, i8* noalias nocapture nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC1]]) -; CHECK-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]]) +; CHECK-NEXT: [[CALL3:%.*]] = call i32 @pthread_create(i64* nonnull align 8 dereferenceable(8) [[THREAD]], %union.pthread_attr_t* noalias align 536870912 null, i8* (i8*)* nonnull @buz, i8* noalias nofree nonnull readnone align 8 dereferenceable(1) [[ALLOC2]]) ; CHECK-NEXT: ret i32 0 ; entry: @@ -64,7 +64,7 @@ entry: define internal i8* @bar(i8* %arg) { ; CHECK-LABEL: define {{[^@]+}}@bar -; CHECK-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(8) [[ARG:%.*]]) +; CHECK-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(8) [[ARG:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: ret i8* bitcast (i8** @GlobalVPtr to i8*) ; @@ -84,7 +84,7 @@ entry: define internal i8* @buz(i8* %arg) { ; CHECK-LABEL: define {{[^@]+}}@buz -; CHECK-SAME: (i8* nofree nonnull readnone returned align 8 dereferenceable(1) [[ARG:%.*]]) +; CHECK-SAME: (i8* noalias nofree nonnull readnone returned align 8 dereferenceable(1) [[ARG:%.*]]) ; CHECK-NEXT: entry: ; CHECK-NEXT: ret i8* [[ARG]] ; diff --git a/llvm/test/Transforms/Attributor/align.ll b/llvm/test/Transforms/Attributor/align.ll index d961a18f642a2e..9bfd8f72e957cc 100644 --- a/llvm/test/Transforms/Attributor/align.ll +++ b/llvm/test/Transforms/Attributor/align.ll @@ -147,11 +147,11 @@ define align 4 i32* @test7(i32* align 32 %p) #0 { ; Function Attrs: nounwind readnone ssp uwtable define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 { ; ATTRIBUTOR-LABEL: define {{[^@]+}}@f1b -; ATTRIBUTOR-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr +; ATTRIBUTOR-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr ; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* [[TMP0]], null ; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] ; ATTRIBUTOR: 3: -; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b(i8* nofree nonnull readnone align 8 dereferenceable(1) @a1) +; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call align 8 i8* @f2b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1) ; ATTRIBUTOR-NEXT: [[L:%.*]] = load i8, i8* [[TMP4]], align 8 ; ATTRIBUTOR-NEXT: store i8 [[L]], i8* @a1, align 8 ; ATTRIBUTOR-NEXT: br label [[TMP5]] @@ -177,14 +177,14 @@ define internal i8* @f1b(i8* readnone %0) local_unnamed_addr #0 { define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 { ; ; ATTRIBUTOR-LABEL: define {{[^@]+}}@f2b -; ATTRIBUTOR-SAME: (i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr +; ATTRIBUTOR-SAME: (i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" [[TMP0:%.*]]) local_unnamed_addr ; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* @a1, null ; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP5:%.*]], label [[TMP3:%.*]] ; ATTRIBUTOR: 3: -; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1) +; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) "no-capture-maybe-returned" @a1) ; ATTRIBUTOR-NEXT: br label [[TMP7:%.*]] ; ATTRIBUTOR: 5: -; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = tail call i8* @f3b(i8* nofree nonnull readnone align 16 dereferenceable(1) @a2) +; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = tail call i8* @f3b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2) ; ATTRIBUTOR-NEXT: br label [[TMP7]] ; ATTRIBUTOR: 7: ; ATTRIBUTOR-NEXT: [[TMP8:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ [[TMP6]], [[TMP5]] ] @@ -211,11 +211,11 @@ define internal i8* @f2b(i8* readnone %0) local_unnamed_addr #0 { define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 { ; ; ATTRIBUTOR-LABEL: define {{[^@]+}}@f3b -; ATTRIBUTOR-SAME: (i8* nocapture nofree nonnull readnone align 16 dereferenceable(1) [[TMP0:%.*]]) local_unnamed_addr +; ATTRIBUTOR-SAME: (i8* noalias nocapture nofree nonnull readnone align 16 dereferenceable(1) [[TMP0:%.*]]) local_unnamed_addr ; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = icmp eq i8* @a2, null ; ATTRIBUTOR-NEXT: br i1 [[TMP2]], label [[TMP3:%.*]], label [[TMP5:%.*]] ; ATTRIBUTOR: 3: -; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* nofree nonnull readnone align 16 dereferenceable(1) @a2) +; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 16 dereferenceable(1) @a2) ; ATTRIBUTOR-NEXT: br label [[TMP5]] ; ATTRIBUTOR: 5: ; ATTRIBUTOR-NEXT: [[TMP6:%.*]] = phi i8* [ [[TMP4]], [[TMP3]] ], [ @a1, [[TMP1:%.*]] ] @@ -236,7 +236,7 @@ define internal i8* @f3b(i8* readnone %0) local_unnamed_addr #0 { define align 4 i32* @test7b(i32* align 32 %p) #0 { ; ATTRIBUTOR-LABEL: define {{[^@]+}}@test7b ; ATTRIBUTOR-SAME: (i32* nofree readnone returned align 32 "no-capture-maybe-returned" [[P:%.*]]) -; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = tail call i8* @f1b(i8* nofree nonnull readnone align 8 dereferenceable(1) @a1) +; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = tail call i8* @f1b(i8* noalias nofree nonnull readnone align 8 dereferenceable(1) @a1) ; ATTRIBUTOR-NEXT: ret i32* [[P]] ; tail call i8* @f1b(i8* align 8 dereferenceable(1) @a1) @@ -252,17 +252,17 @@ define void @test8_helper() { %ptr2 = tail call align 8 i32* @unknown() tail call void @test8(i32* %ptr1, i32* %ptr1, i32* %ptr0) -; ATTRIBUTOR: tail call void @test8(i32* readnone align 4 %ptr1, i32* readnone align 4 %ptr1, i32* readnone %ptr0) +; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1, i32* noalias readnone %ptr0) tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1) -; ATTRIBUTOR: tail call void @test8(i32* readnone align 8 %ptr2, i32* readnone align 4 %ptr1, i32* readnone align 4 %ptr1) +; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 8 %ptr2, i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1) tail call void @test8(i32* %ptr2, i32* %ptr1, i32* %ptr1) -; ATTRIBUTOR: tail call void @test8(i32* readnone align 8 %ptr2, i32* readnone align 4 %ptr1, i32* readnone align 4 %ptr1) +; ATTRIBUTOR: tail call void @test8(i32* noalias readnone align 8 %ptr2, i32* noalias readnone align 4 %ptr1, i32* noalias readnone align 4 %ptr1) ret void } declare void @user_i32_ptr(i32*) readnone nounwind define internal void @test8(i32* %a, i32* %b, i32* %c) { -; ATTRIBUTOR: define internal void @test8(i32* nocapture readnone align 4 %a, i32* nocapture readnone align 4 %b, i32* nocapture readnone %c) +; ATTRIBUTOR: define internal void @test8(i32* noalias nocapture readnone align 4 %a, i32* noalias nocapture readnone align 4 %b, i32* noalias nocapture readnone %c) call void @user_i32_ptr(i32* %a) call void @user_i32_ptr(i32* %b) call void @user_i32_ptr(i32* %c) diff --git a/llvm/test/Transforms/Attributor/internal-noalias.ll b/llvm/test/Transforms/Attributor/internal-noalias.ll index fd6e17bc77f791..6c380b514ce31d 100644 --- a/llvm/test/Transforms/Attributor/internal-noalias.ll +++ b/llvm/test/Transforms/Attributor/internal-noalias.ll @@ -21,11 +21,7 @@ entry: } -; FIXME: Should be something like this. -; define internal i32 @noalias_args_argmem(i32* noalias nocapture readonly %A, i32* noalias nocapture readonly %B) -; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %A, i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) %B) - -; +; 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) define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 { entry: %0 = load i32, i32* %A, align 4 @@ -44,5 +40,34 @@ entry: ret i32 %add } +; CHECK: define internal i32 @noalias_args_argmem_ro(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_ro(i32* %A, i32* %B) #1 { + %t0 = load i32, i32* %A, align 4 + %t1 = load i32, i32* %B, align 4 + %add = add nsw i32 %t0, %t1 + ret i32 %add +} + +define i32 @visible_local_2() { + %B = alloca i32, align 4 + store i32 5, i32* %B, align 4 + %call = call i32 @noalias_args_argmem_ro(i32* %B, i32* %B) + ret i32 %call +} + +; CHECK: define internal i32 @noalias_args_argmem_rn(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) %B) +define internal i32 @noalias_args_argmem_rn(i32* %A, i32* %B) #1 { + %t0 = load i32, i32* %B, align 4 + store i32 0, i32* %B + ret i32 %t0 +} + +define i32 @visible_local_3() { + %B = alloca i32, align 4 + store i32 5, i32* %B, align 4 + %call = call i32 @noalias_args_argmem_rn(i32* %B, i32* %B) + ret i32 %call +} + attributes #0 = { noinline nounwind uwtable willreturn } attributes #1 = { argmemonly noinline nounwind uwtable willreturn} diff --git a/llvm/test/Transforms/Attributor/misc.ll b/llvm/test/Transforms/Attributor/misc.ll index 3ca99c0c23bb6b..4fdb0bc280d31d 100644 --- a/llvm/test/Transforms/Attributor/misc.ll +++ b/llvm/test/Transforms/Attributor/misc.ll @@ -10,7 +10,7 @@ define internal void @internal(void (i8*)* %fp) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) +; CHECK-NEXT: call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef) ; 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*)*)) @@ -24,7 +24,7 @@ define internal void @internal(void (i8*)* %fp) { ; DECL_CS-NEXT: entry: ; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4 ; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) +; DECL_CS-NEXT: call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef) ; 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*)*)) @@ -52,7 +52,7 @@ define void @external(void (i8*)* %fp) { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 ; CHECK-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; CHECK-NEXT: call void @foo(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) +; CHECK-NEXT: call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef) ; 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]]) @@ -67,7 +67,7 @@ define void @external(void (i8*)* %fp) { ; DECL_CS-NEXT: entry: ; DECL_CS-NEXT: [[A:%.*]] = alloca i32, align 4 ; DECL_CS-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8* -; DECL_CS-NEXT: call void @foo(i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) undef) +; DECL_CS-NEXT: call void @foo(i32* noalias nofree nonnull readnone align 4 dereferenceable(4) undef) ; 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 index f7f6297f639f92..f22b66a12d1ff2 100644 --- 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=3 < %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=4 < %s | FileCheck %s ; TEST 1 - negative. @@ -152,27 +152,39 @@ define i8* @test8(i32* %0) nounwind uwtable { ; TEST 9 ; Simple Argument Test -declare void @use_i8(i8* nocapture) readnone +declare void @use_i8(i8* nocapture) define internal void @test9a(i8* %a, i8* %b) { ; CHECK: define internal void @test9a() ret void } define internal void @test9b(i8* %a, i8* %b) { -; CHECK: define internal void @test9b(i8* noalias nocapture readnone %a, i8* nocapture readnone %b) +; FIXME: %b should be noalias +; CHECK: define internal void @test9b(i8* noalias nocapture %a, i8* nocapture %b) call void @use_i8(i8* %a) call void @use_i8(i8* %b) ret void } +define internal void @test9c(i8* %a, i8* %b, i8* %c) { +; CHECK: define internal void @test9c(i8* noalias nocapture %a, i8* nocapture %b, i8* nocapture %c) + call void @use_i8(i8* %a) + call void @use_i8(i8* %b) + call void @use_i8(i8* %c) + ret void +} define void @test9_helper(i8* %a, i8* %b) { -; CHECK: define void @test9_helper(i8* nocapture readnone %a, i8* nocapture readnone %b) +; CHECK: define void @test9_helper(i8* nocapture %a, i8* nocapture %b) ; CHECK: tail call void @test9a() ; CHECK: tail call void @test9a() -; CHECK: tail call void @test9b(i8* noalias nocapture readnone %a, i8* nocapture readnone %b) -; CHECK: tail call void @test9b(i8* noalias nocapture readnone %b, i8* noalias nocapture readnone %a) +; CHECK: tail call void @test9b(i8* noalias nocapture %a, i8* nocapture %b) +; CHECK: tail call void @test9b(i8* noalias nocapture %b, i8* noalias nocapture %a) +; CHECK: tail call void @test9c(i8* noalias nocapture %a, i8* nocapture %b, i8* nocapture %b) +; CHECK: tail call void @test9c(i8* noalias nocapture %b, i8* noalias nocapture %a, i8* noalias nocapture %a) tail call void @test9a(i8* noalias %a, i8* %b) tail call void @test9a(i8* noalias %b, i8* noalias %a) tail call void @test9b(i8* noalias %a, i8* %b) tail call void @test9b(i8* noalias %b, i8* noalias %a) + tail call void @test9c(i8* noalias %a, i8* %b, i8* %b) + tail call void @test9c(i8* noalias %b, i8* noalias %a, i8* noalias %a) ret void } diff --git a/llvm/test/Transforms/Attributor/nonnull.ll b/llvm/test/Transforms/Attributor/nonnull.ll index bf366708c61a18..7420a39b8907ef 100644 --- a/llvm/test/Transforms/Attributor/nonnull.ll +++ b/llvm/test/Transforms/Attributor/nonnull.ll @@ -167,7 +167,7 @@ define void @test13_helper() { } declare void @use_i8_ptr(i8* nofree) readnone nounwind define internal void @test13(i8* %a, i8* %b, i8* %c) { -; ATTRIBUTOR: define internal void @test13(i8* nocapture nofree nonnull readnone %a, i8* nocapture nofree readnone %b, i8* nocapture nofree readnone %c) +; ATTRIBUTOR: define internal void @test13(i8* noalias nocapture nofree nonnull readnone %a, i8* noalias nocapture nofree readnone %b, i8* noalias nocapture nofree readnone %c) call void @use_i8_ptr(i8* %a) call void @use_i8_ptr(i8* %b) call void @use_i8_ptr(i8* %c) @@ -536,7 +536,7 @@ define i32* @g1() { } declare void @use_i32_ptr(i32*) readnone nounwind -; ATTRIBUTOR: define internal void @called_by_weak(i32* nocapture nonnull readnone %a) +; ATTRIBUTOR: define internal void @called_by_weak(i32* noalias nocapture nonnull readnone %a) define internal void @called_by_weak(i32* %a) { call void @use_i32_ptr(i32* %a) ret void @@ -550,7 +550,7 @@ define weak_odr void @weak_caller(i32* nonnull %a) { } ; Expect nonnull -; ATTRIBUTOR: define internal void @control(i32* nocapture nonnull readnone align 16 dereferenceable(8) %a) +; ATTRIBUTOR: define internal void @control(i32* noalias nocapture nonnull readnone align 16 dereferenceable(8) %a) define internal void @control(i32* dereferenceable(4) %a) { call void @use_i32_ptr(i32* %a) ret void