Index: llvm/lib/Transforms/IPO/Attributor.cpp =================================================================== --- llvm/lib/Transforms/IPO/Attributor.cpp +++ llvm/lib/Transforms/IPO/Attributor.cpp @@ -1278,6 +1278,12 @@ struct AANoAliasImpl : AANoAlias { AANoAliasImpl(const IRPosition &IRP) : AANoAlias(IRP) {} + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + if (hasAttr({Attribute::NoAlias})) + indicateOptimisticFixpoint(); + } + const std::string getAsStr() const override { return getAssumed() ? "noalias" : "may-alias"; } @@ -1287,17 +1293,6 @@ struct AANoAliasReturned final : AANoAliasImpl { AANoAliasReturned(const IRPosition &IRP) : AANoAliasImpl(IRP) {} - /// See AbstractAttriubute::initialize(...). - void initialize(Attributor &A) override { - Function &F = getAnchorScope(); - - // Already noalias. - if (F.returnDoesNotAlias()) { - indicateOptimisticFixpoint(); - return; - } - } - /// See AbstractAttribute::updateImpl(...). virtual ChangeStatus updateImpl(Attributor &A) override; @@ -1343,6 +1338,68 @@ return ChangeStatus::UNCHANGED; } +/// NoAlias attribute for function argument. +struct AANoAliasArgument final : AANoAliasImpl { + AANoAliasArgument(const IRPosition &IRP) : AANoAliasImpl(IRP) {} + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override; + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECL_AND_TRACK_ARG_ATTR(noalias) + } +}; + +ChangeStatus AANoAliasArgument::updateImpl(Attributor &A) { + unsigned ArgNo = getArgNo(); + + // Callback function + std::function CallSiteCheck = [&](CallSite CS) { + assert(CS && "Sanity check: Call site was not initialized properly!"); + + IRPosition CSArgPos = IRPosition::callsite_argument(CS, ArgNo); + if (CSArgPos.hasAttr({Attribute::NoAlias})) + return true; + + // Check that NoAliasAA is AANoAliasCallSiteArgument. + if (auto *NoAliasAA = A.getAAFor(*this, CSArgPos)) { + ImmutableCallSite ICS(&NoAliasAA->getAnchorValue()); + if (ICS && CS.getInstruction() == ICS.getInstruction()) + return NoAliasAA->isAssumedNoAlias(); + return false; + } + + return false; + }; + if (!A.checkForAllCallSites(CallSiteCheck, *this, true)) + return indicatePessimisticFixpoint(); + return ChangeStatus::UNCHANGED; +} + +/// NoAlias attribute for a call site argument. +struct AANoAliasCallSiteArgument final : AANoAliasImpl { + AANoAliasCallSiteArgument(const IRPosition &IRP) : AANoAliasImpl(IRP) {} + + /// See AbstractAttribute::updateImpl(Attributor &A). + ChangeStatus updateImpl(Attributor &A) override; + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECL_AND_TRACK_CSARG_ATTR(noalias) + } +}; + +ChangeStatus AANoAliasCallSiteArgument::updateImpl(Attributor &A) { + Value &V = getAssociatedValue(); + auto *NoAliasAA = A.getAAFor(*this, IRPosition::value(V)); + + if (!NoAliasAA || !NoAliasAA->isAssumedNoAlias()) + return indicatePessimisticFixpoint(); + + return ChangeStatus::UNCHANGED; +} + /// -------------------AAIsDead Function Attribute----------------------- struct AAIsDeadImpl : public AAIsDead { @@ -2509,6 +2566,9 @@ // Every argument with pointer type might be marked nonnull. checkAndRegisterAA(ArgPos, *this, Whitelist); + // Every argument with pointer type might be marked noalias. + checkAndRegisterAA(ArgPos, *this, Whitelist); + // Every argument with pointer type might be marked dereferenceable. checkAndRegisterAA(ArgPos, *this, Whitelist); @@ -2562,6 +2622,10 @@ checkAndRegisterAA(CSArgPos, *this, Whitelist); + // Call site argument attribute "noalias". + checkAndRegisterAA(CSArgPos, *this, + Whitelist); + // Call site argument attribute "dereferenceable". checkAndRegisterAA(CSArgPos, *this, Whitelist); Index: llvm/test/Transforms/FunctionAttrs/noalias.ll =================================================================== --- llvm/test/Transforms/FunctionAttrs/noalias.ll +++ llvm/test/Transforms/FunctionAttrs/noalias.ll @@ -138,3 +138,27 @@ 5: ; preds = %1, %4 ret i8* %2 } + +; TEST 9 +; Simple Argument Test +define internal void @test9(i8* %a, i8* %b) { +; CHECK: define internal void @test9(i8* noalias %a, i8* %b) + ret void +} +define void @test9_helper(i8* %a, i8* %b) { + tail call void @test9(i8* noalias %a, i8* %b) + tail call void @test9(i8* noalias %b, i8* noalias %a) + ret void +} + + +; TEST 10 +; Simple CallSite Test + +declare void @test10_helper(i8* %a) +define void @test10(i8* noalias %a) { +; CHECK: define void @test10(i8* noalias %a) +; CHECK-NEXT: tail call void @test10_helper(i8* noalias %a) + tail call void @test10_helper(i8* %a) + ret void +}