Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -1672,8 +1672,8 @@ /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - // TODO: It isn't sound to initialize as the same with `AANoAliasImpl` - // because `noalias` may not be valid in the current position. + if (hasAttr({Attribute::NoAlias}) || isa(getAssociatedValue())) + indicateOptimisticFixpoint(); } /// See AbstractAttribute::updateImpl(...). @@ -1711,8 +1711,49 @@ /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { - // TODO: Implement this. - return indicatePessimisticFixpoint(); + // 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 + // possibly executed before this callsite. + // (iii) There is no other pointer argument which could alias with the + // value. + + const IRPosition IRP = IRPosition::value(getAssociatedValue()); + + // (i) Check whether noalias holds in the definition. + + auto &NoAliasAA = A.getAAFor(*this, IRP); + + if (!NoAliasAA.isAssumedNoAlias()) + return indicatePessimisticFixpoint(); + + // (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. + + auto &NoCaptureAA = A.getAAFor(*this, IRP); + if (!NoCaptureAA.isAssumedNoCapture()) + return indicatePessimisticFixpoint(); + + // (iii) Check there is no other pointer argument which could alias with the + // value. + ImmutableCallSite ICS(&getAnchorValue()); + for (unsigned i = 0; i < ICS.getNumArgOperands(); i++) { + if (getArgNo() == i) + continue; + const Value *ArgOp = ICS.getArgOperand(i); + if (!ArgOp->getType()->isPointerTy()) + continue; + + // TODO: Use AliasAnalysis + // AAResults& AAR = ..; + // if(AAR.isNoAlias(&getAssociatedValue(), ArgOp)) + // return indicatePessimitisicFixpoint(); + + return indicatePessimisticFixpoint(); + } + + return ChangeStatus::UNCHANGED; } /// See AbstractAttribute::trackStatistics() @@ -2594,10 +2635,12 @@ if (!isAssumedNoCaptureMaybeReturned()) return; - if (isAssumedNoCapture()) + if (isAssumedNoCapture() && getArgNo() >= 0) Attrs.emplace_back(Attribute::get(Ctx, Attribute::NoCapture)); else if (ManifestInternal) - Attrs.emplace_back(Attribute::get(Ctx, "no-capture-maybe-returned")); + Attrs.emplace_back(Attribute::get( + Ctx, isAssumedNoCapture() ? "no-capture-in-the-scope" + : "no-capture-maybe-returned")); } /// Set the NOT_CAPTURED_IN_MEM and NOT_CAPTURED_IN_RET bits in \p Known @@ -2864,6 +2907,12 @@ struct AANoCaptureFloating final : AANoCaptureImpl { AANoCaptureFloating(const IRPosition &IRP) : AANoCaptureImpl(IRP) {} + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + if (!isa(getAnchorValue())) + indicatePessimisticFixpoint(); + } + /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_FLOATING_ATTR(nocapture) Index: llvm/test/Transforms/FunctionAttrs/internal-noalias.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/internal-noalias.ll +++ llvm/test/Transforms/FunctionAttrs/internal-noalias.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 < %s | FileCheck %s +; RUN: opt -S -attributor -attributor-manifest-internal -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 < %s | FileCheck %s define dso_local i32 @visible(i32* noalias %A, i32* noalias %B) #0 { entry: @@ -10,7 +10,7 @@ ; FIXME: Should be something like this. ; define internal i32 @noalias_args(i32* nocapture readonly %A, i32* noalias nocapture readonly %B) -; CHECK: define internal i32 @noalias_args(i32* nocapture %A, i32* nocapture %B) +; CHECK: define internal i32 @noalias_args(i32* nocapture %A, i32* noalias nocapture %B) define internal i32 @noalias_args(i32* %A, i32* %B) #0 { entry: @@ -25,7 +25,7 @@ ; 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 %A, i32* nocapture %B) +; CHECK: define internal i32 @noalias_args_argmem(i32* nocapture %A, i32* noalias nocapture %B) ; define internal i32 @noalias_args_argmem(i32* %A, i32* %B) #1 { entry: Index: llvm/test/Transforms/FunctionAttrs/noalias_returned.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/noalias_returned.ll +++ llvm/test/Transforms/FunctionAttrs/noalias_returned.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -attributor -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=5 < %s | FileCheck %s +; RUN: opt -S -attributor -attributor-disable=false -attributor-manifest-internal -attributor-max-iterations-verify -attributor-max-iterations=5 < %s | FileCheck %s ; TEST 1 - negative. @@ -191,3 +191,71 @@ tail call void @test11_helper(i8* %a, i8* %a) ret void } + + +; TEST 12 +; CallSite Argument +declare void @use_nocapture(i8* nocapture) +declare void @use(i8*) +define void @test12_1() { +; CHECK-LABEL: @test12_1( +; CHECK-NEXT: [[A:%.*]] = alloca i8, align 4 +; CHECK-NEXT: [[B:%.*]] = tail call noalias "no-capture-in-the-scope" i8* @malloc(i64 4) +; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture nonnull align 4 dereferenceable(1) [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture nonnull align 4 dereferenceable(1) [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* noalias nocapture [[B]]) +; CHECK-NEXT: ret void +; + %A = alloca i8, align 4 + %B = tail call noalias i8* @malloc(i64 4) + tail call void @use_nocapture(i8* %A) + tail call void @use_nocapture(i8* %A) + tail call void @use_nocapture(i8* %B) + tail call void @use_nocapture(i8* %B) + ret void +} + +define void @test12_2(){ +; CHECK-LABEL: @test12_2( +; CHECK-NEXT: [[A:%.*]] = tail call noalias i8* @malloc(i64 4) +; FIXME: This should be @use_nocapture(i8* noalias nocapture [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) +; FIXME: This should be @use_nocapture(i8* noalias nocapture [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) +; CHECK-NEXT: tail call void @use(i8* [[A]]) +; CHECK-NEXT: tail call void @use_nocapture(i8* nocapture [[A]]) +; CHECK-NEXT: ret void +; + %A = tail call noalias i8* @malloc(i64 4) + tail call void @use_nocapture(i8* %A) + tail call void @use_nocapture(i8* %A) + tail call void @use(i8* %A) + tail call void @use_nocapture(i8* %A) + ret void +} + +declare void @two_args(i8* nocapture , i8* nocapture) +define void @test12_3(){ +; CHECK-LABEL: @test12_3( + %A = tail call noalias i8* @malloc(i64 4) +; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A) + tail call void @two_args(i8* %A, i8* %A) + ret void +} + +define void @test12_4(){ +; CHECK-LABEL: @test12_4( + %A = tail call noalias i8* @malloc(i64 4) + %B = tail call noalias i8* @malloc(i64 4) + %A_0 = getelementptr i8, i8* %A, i64 0 + %A_1 = getelementptr i8, i8* %A, i64 1 +; FIXME: This should be @two_args(i8* noalias nocapture %A, i8* noalias nocapture %B) +; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %B) + tail call void @two_args(i8* %A, i8* %B) +; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A_0) + tail call void @two_args(i8* %A, i8* %A_0) +; CHECK: tail call void @two_args(i8* nocapture %A, i8* nocapture %A_1) + tail call void @two_args(i8* %A, i8* %A_1) + ret void +}