diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -846,6 +846,14 @@ bool checkForAllUses(const function_ref &Pred, const AbstractAttribute &QueryingAA, const Value &V); + /// Check \p Pred on all reachable uses of \p V. + /// + /// This method will evaluate \p Pred on all reachable uses of the + /// associated value and return true if \p Pred holds every time. + bool checkReachableUses(const function_ref &Pred, + const AbstractAttribute &QueryingAA, + const Value &From); + /// Check \p Pred on all function call sites. /// /// This method will evaluate \p Pred on call sites and return @@ -1694,16 +1702,15 @@ /// Returns true if 'From' instruction is assumed to reach, 'To' instruction. /// Users should provide two positions they are interested in, and the class /// determines (and caches) reachability. - bool isAssumedReachable(const Instruction *From, - const Instruction *To) const { - return true; + bool isAssumedReachable(const Value *From, const Value *To) const { + return getAssumed(); } /// Returns true if 'From' instruction is known to reach, 'To' instruction. /// Users should provide two positions they are interested in, and the class /// determines (and caches) reachability. - bool isKnownReachable(const Instruction *From, const Instruction *To) const { - return true; + bool isKnownReachable(const Value *From, const Value *To) const { + return getKnown() && isAssumedReachable(From, To); } /// Return an IR position, see struct IRPosition. 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 @@ -2196,15 +2196,70 @@ << " 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. + // Look at CFG and check only uses possibly executed before this + // callsite. + + auto UsePred = [&](const Value &V) { + Function *CallerF = IRP.getAnchorScope(); + if (CallerF && !CallerF->arg_empty()) { + + // The caller. + ImmutableCallSite ICSCaller(&getAnchorValue()); + const Instruction *CallerInst = ICSCaller.getInstruction(); + + // Propagate caller argument which has noalias. + bool IsArgumentWithNoAlias = false; + for (Function::arg_iterator A = CallerF->arg_begin(), + E = CallerF->arg_end(); + A != E; ++A) { + Value &v = (*A); + if ((&v == &V) && (*A).hasNoAliasAttr() && + V.getType()->isPointerTy()) { + IsArgumentWithNoAlias = true; + } + } + + // Early return if caller doesn't have noalias, so no propagation case. + if (!IsArgumentWithNoAlias) + return false; + + // Check the uses of V. + for (const Use &U : V.uses()) { + + // Simple case: has 1 use and it is the callsite. + ImmutableCallSite ICSUse(U.getUser()); + const Instruction *CallUse = ICSUse.getInstruction(); + if (U->hasOneUse()) { + if (CallUse->isSameOperationAs(CallerInst)) { + return true; + } + } + + // More than 1 use, check if Callsite reached. + if (CallUse->isSameOperationAs(CallerInst)) + break; + + // TODO: Add more cases for noalias deduction to callee. + + // TODO: Not using reachability, yet. + const IRPosition &FnPos = IRPosition::function(*CallerF); + auto &FnAA = A.getAAFor(*this, FnPos); + if (FnAA.isAssumedReachable(&V, U.get())) { + return true; + } + } + } + return false; + }; auto &NoCaptureAA = A.getAAFor(*this, IRP); if (!NoCaptureAA.isAssumedNoCaptureMaybeReturned()) { - LLVM_DEBUG( - dbgs() << "[Attributor][AANoAliasCSArg] " << V - << " cannot be noalias as it is potentially captured\n"); - return indicatePessimisticFixpoint(); + if (!A.checkReachableUses(UsePred, *this, getAssociatedValue())) { + LLVM_DEBUG( + dbgs() << "[Attributor][AANoAliasCSArg] " << V + << " cannot be noalias as it is potentially captured\n"); + return indicatePessimisticFixpoint(); + } } // (iii) Check there is no other pointer argument which could alias with the @@ -4894,6 +4949,17 @@ return true; } +bool Attributor::checkReachableUses( + const function_ref &Pred, + const AbstractAttribute &QueryingAA, const Value &From) { + // TODO: Add more cases. + if (Pred(From)) { + return true; + } else { + return false; + } +} + bool Attributor::checkForAllUses( const function_ref &Pred, const AbstractAttribute &QueryingAA, const Value &V) { 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 @@ -168,7 +168,7 @@ declare void @test10_helper_1(i8* %a) define void @test10_helper_2(i8* noalias %a) { -; CHECK: tail call void @test10_helper_1(i8* %a) +; CHECK: tail call void @test10_helper_1(i8* noalias %a) tail call void @test10_helper_1(i8* %a) ret void }