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 @@ -294,7 +294,8 @@ struct AANoCapture : public AbstractAttribute { /// See AbstractAttribute::AbstractAttribute(...). - AANoCapture(Value &V) : AbstractAttribute(V) {} + AANoCapture(Value &AssociatedValue, Value &AnchoredValue) + : AbstractAttribute(&AssociatedValue, AnchoredValue) {} /// Return true if we know that the underlying value is not captured in its /// respective scope. 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 @@ -61,6 +61,8 @@ STATISTIC(NumFnArgumentNoCapture, "Number of function arguments marked no-capture"); +STATISTIC(NumCSArgumentNoCapture, + "Number of call site arguments marked no-capture"); STATISTIC(NumFnArgumentReadNone, "Number of function arguments marked read-none"); @@ -193,6 +195,66 @@ BooleanState() : IntegerState(1){}; }; +/// Helper to simplify the handling of call site arguments. +template +struct AbstractCallSiteArgument : public AAImplType { + + AbstractCallSiteArgument(CallSite CS, Value &ArgOp, unsigned ArgNo) + : AAImplType(ArgOp, *CS.getInstruction()), ArgNo(ArgNo) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + if (hasAttribute(AAImplType::getAttrKind())) + AAImplType::indicateFixpoint(/* Optimistic */ true); + } + + const Argument *getArgument() const { + ImmutableCallSite ICS(&AAImplType::getAnchoredValue()); + const Function *Callee = ICS.getCalledFunction(); + if (Callee && Callee->arg_size() > ArgNo) + return Callee->arg_begin() + ArgNo; + return nullptr; + } + + /// Return true if the call site or the callee have the attribute \p Kind. + bool hasAttribute(Attribute::AttrKind Kind) const { + ImmutableCallSite ICS(&AAImplType::getAnchoredValue()); + return ICS.paramHasAttr(ArgNo, Kind); + } + + /// Return the argument number of the underlying associated value. + unsigned getArgumentNo() const { return ArgNo; } + + /// See AbstractAttribute::getManifestPosition(). + virtual AbstractAttribute::ManifestPosition + getManifestPosition() const override { + return AbstractAttribute::MP_CALL_SITE_ARGUMENT; + } + +protected: + /// Propagate information from an argument to the call site operand. + void transferInfoFromCorrespondingArgument(Attributor &A, + IntegerState &State) { + const Argument *Arg = getArgument(); + if (!Arg) { + State.indicateFixpoint(/* Optimistic */ false); + return; + } + + const AAImplType *ArgAA = A.getAAFor(*this, *Arg, ArgNo); + if (!ArgAA || !ArgAA->getState().isValidState()) { + State.indicateFixpoint(/* Optimistic */ false); + return; + } + + State.addKnownBits(ArgAA->getKnown()); + State.intersectAssumedBits(ArgAA->getAssumed()); + } + + /// The argument operand number of the associated + unsigned ArgNo; +}; + /// Helper to adjust the statistics. static void bookkeeping(AbstractAttribute::ManifestPosition MP, const Attribute &Attr) { @@ -206,7 +268,8 @@ NumFnArgumentReturned++; return; case Attribute::NoCapture: - NumFnArgumentNoCapture++; + MP == AbstractAttribute::MP_ARGUMENT ? NumFnArgumentNoCapture++ + : NumCSArgumentNoCapture++; return; case Attribute::NoReturn: NumFnNoReturn++; @@ -1009,12 +1072,18 @@ NOT_CAPTURED_IN_MEM | NOT_CAPTURED_IN_INT | NOT_CAPTURED_IN_RET, }; - /// Constructor that takes the value this attribute is associated with (\p V) - /// as well as the function this attribute is related to. - AANoCaptureImpl(Value &V) : AANoCapture(V), IntegerState(NO_CAPTURE) { + /// Constructor that takes the value this attribute is associated with and the + /// one it is anchored with as \p AnchoredValue and \p AssociatedValue, + /// respectively. + AANoCaptureImpl(Value &AssociatedValue, Value &AnchoredValue) + : AANoCapture(AssociatedValue, AnchoredValue), IntegerState(NO_CAPTURE) { assert(getAssumed() == NO_CAPTURE); } + /// Constructor that takes the single value \p V this attribute is associated + /// with and anchored at. + AANoCaptureImpl(Value &V) : AANoCaptureImpl(V, V) {} + /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { Value &V = *getAssociatedValue(); @@ -1360,6 +1429,58 @@ : ChangeStatus::CHANGED; } +/// An AA to represent the no-capture call site argument attribute. +struct AANoCaptureCallSiteArgument final + : public AbstractCallSiteArgument { + + /// Create a no-capture abstract attribute for the \p ArgNo argument at the + /// call site \p CS (which is \p ArgOp). The attribute is anchored at the + /// call site but associated with the argument operand. + AANoCaptureCallSiteArgument(CallSite CS, Value &ArgOp, unsigned ArgNo) + : AbstractCallSiteArgument(CS, ArgOp, ArgNo) {} + + /// See AbstractAttribute::updateImpl(Attributor &A). + virtual ChangeStatus updateImpl(Attributor &A) override; +}; + +ChangeStatus AANoCaptureCallSiteArgument::updateImpl(Attributor &A) { + // The current assumed state used to determine a change. + auto AssumedState = getAssumed(); + + // 1) Use the generic function argument -> call site argument information + // transfer implemented in AbstractCallSiteArgument. + IntegerState ArgumentState; + transferInfoFromCorrespondingArgument(A, ArgumentState); + + // Early exit. + if (isKnownNoCapture()) { + assert(isAtFixpoint()); + return ChangeStatus::UNCHANGED; + } + + // 2) Use the CaptureTracker interface and logic with the specialized tracker, + // defined in AACaptureUseTracker, that can look at in-flight abstract + // attributes and directly updates the assumed state. + SmallVector PotentialCopies; + unsigned RemainingUsesToExplore = DefaultMaxUsesToExplore; + IntegerState TrackerState; + AACaptureUseTracker Tracker(A, *this, TrackerState, PotentialCopies, + RemainingUsesToExplore); + + ImmutableCallSite ICS(&getAnchoredValue()); + if (!Tracker.captured(ICS.arg_begin() + getArgumentNo())) { + addKnownBits(TrackerState.getKnown()); + intersectAssumedBits(TrackerState.getAssumed()); + } + + // Combine information from 1) and 2). + addKnownBits(ArgumentState.getKnown() | TrackerState.getKnown()); + intersectAssumedBits(ArgumentState.getAssumed() | TrackerState.getAssumed()); + + return (AssumedState == getAssumed()) ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; +} + /// -------------------- Memory Behavior Attributes ---------------------------- /// Includes read-none, read-only, and write-only, as well as their combination /// with inaccessible-mem-only, arg-mem-only, and inaccessible-or-arg-mem-only. @@ -2223,10 +2344,19 @@ break; case Instruction::Invoke: case Instruction::CallBr: - case Instruction::Call: + case Instruction::Call: { // Call-like instructions are interesting for AANoRecurseFunction. + CallSite CS(&I); + for (unsigned u = 0, e = CS.getNumArgOperands(); u != e; u++) { + Value *ArgOp = CS.getArgOperand(u); + if (!ArgOp->getType()->isPointerTy()) + continue; + + registerAA(*new AANoCaptureCallSiteArgument(CS, *ArgOp, u)); + } IsInterestingOpcode = true; break; + } case Instruction::Ret: // ReturnInst are interesting for AAReturnedValues. IsInterestingOpcode = true; }