diff options
Diffstat (limited to 'llvm/lib/Transforms/IPO/Attributor.cpp')
-rw-r--r-- | llvm/lib/Transforms/IPO/Attributor.cpp | 601 |
1 files changed, 367 insertions, 234 deletions
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index ba7626276c8..33a49a5f954 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -265,13 +265,9 @@ ChangeStatus AbstractAttribute::update(Attributor &A) { ChangeStatus IRAttributeManifest::manifestAttrs(Attributor &A, IRPosition &IRP, const ArrayRef<Attribute> &DeducedAttrs) { - assert(IRP.getAssociatedValue() && - "Attempted to manifest an attribute without associated value!"); - ChangeStatus HasChanged = ChangeStatus::UNCHANGED; - Function &ScopeFn = IRP.getAnchorScope(); - LLVMContext &Ctx = ScopeFn.getContext(); + Function *ScopeFn = IRP.getAssociatedFunction(); IRPosition::Kind PK = IRP.getPositionKind(); // In the following some generic code that will manifest attributes in @@ -280,16 +276,22 @@ IRAttributeManifest::manifestAttrs(Attributor &A, IRPosition &IRP, AttributeList Attrs; switch (PK) { + case IRPosition::IRP_INVALID: + case IRPosition::IRP_FLOAT: + llvm_unreachable("Cannot manifest at a floating or invalid position!"); case IRPosition::IRP_ARGUMENT: case IRPosition::IRP_FUNCTION: case IRPosition::IRP_RETURNED: - Attrs = ScopeFn.getAttributes(); + Attrs = ScopeFn->getAttributes(); break; + case IRPosition::IRP_CALL_SITE: + case IRPosition::IRP_CALL_SITE_RETURNED: case IRPosition::IRP_CALL_SITE_ARGUMENT: Attrs = ImmutableCallSite(&IRP.getAnchorValue()).getAttributes(); break; } + LLVMContext &Ctx = IRP.getAnchorValue().getContext(); for (const Attribute &Attr : DeducedAttrs) { if (!addIfNotExistent(Ctx, Attr, Attrs, IRP.getAttrIdx())) continue; @@ -304,19 +306,147 @@ IRAttributeManifest::manifestAttrs(Attributor &A, IRPosition &IRP, case IRPosition::IRP_ARGUMENT: case IRPosition::IRP_FUNCTION: case IRPosition::IRP_RETURNED: - ScopeFn.setAttributes(Attrs); + ScopeFn->setAttributes(Attrs); break; + case IRPosition::IRP_CALL_SITE: + case IRPosition::IRP_CALL_SITE_RETURNED: case IRPosition::IRP_CALL_SITE_ARGUMENT: CallSite(&IRP.getAnchorValue()).setAttributes(Attrs); + case IRPosition::IRP_FLOAT: + case IRPosition::IRP_INVALID: + break; } return HasChanged; } +const IRPosition IRPosition::EmptyKey(255); +const IRPosition IRPosition::TombstoneKey(256); + +SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { + IRPositions.emplace_back(IRP); + + ImmutableCallSite ICS(&IRP.getAnchorValue()); + switch (IRP.getPositionKind()) { + case IRPosition::IRP_INVALID: + case IRPosition::IRP_FLOAT: + case IRPosition::IRP_FUNCTION: + return; + case IRPosition::IRP_ARGUMENT: + case IRPosition::IRP_RETURNED: + IRPositions.emplace_back( + IRPosition::function(*IRP.getAssociatedFunction())); + return; + case IRPosition::IRP_CALL_SITE: + assert(ICS && "Expected call site!"); + // TODO: We need to look at the operand bundles similar to the redirection + // in CallBase. + if (!ICS.hasOperandBundles()) + if (const Function *Callee = ICS.getCalledFunction()) + IRPositions.emplace_back(IRPosition::function(*Callee)); + return; + case IRPosition::IRP_CALL_SITE_RETURNED: + assert(ICS && "Expected call site!"); + // TODO: We need to look at the operand bundles similar to the redirection + // in CallBase. + if (!ICS.hasOperandBundles()) { + if (const Function *Callee = ICS.getCalledFunction()) { + IRPositions.emplace_back(IRPosition::returned(*Callee)); + IRPositions.emplace_back(IRPosition::function(*Callee)); + } + } + IRPositions.emplace_back( + IRPosition::callsite_function(cast<CallBase>(*ICS.getInstruction()))); + return; + case IRPosition::IRP_CALL_SITE_ARGUMENT: { + int ArgNo = IRP.getArgNo(); + assert(ICS && ArgNo >= 0 && "Expected call site!"); + // TODO: We need to look at the operand bundles similar to the redirection + // in CallBase. + if (!ICS.hasOperandBundles()) { + const Function *Callee = ICS.getCalledFunction(); + if (Callee && Callee->arg_size() > unsigned(ArgNo)) + IRPositions.emplace_back(IRPosition::argument(*Callee->getArg(ArgNo))); + if (Callee) + IRPositions.emplace_back(IRPosition::function(*Callee)); + } + IRPositions.emplace_back(IRPosition::value(IRP.getAssociatedValue())); + return; + } + } +} + +bool IRPosition::hasAttr(ArrayRef<Attribute::AttrKind> AKs) const { + for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this)) + for (Attribute::AttrKind AK : AKs) + if (EquivIRP.getAttr(AK).getKindAsEnum() == AK) + return true; + return false; +} + +void IRPosition::getAttrs(ArrayRef<Attribute::AttrKind> AKs, + SmallVectorImpl<Attribute> &Attrs) const { + for (const IRPosition &EquivIRP : SubsumingPositionIterator(*this)) + for (Attribute::AttrKind AK : AKs) { + const Attribute &Attr = EquivIRP.getAttr(AK); + if (Attr.getKindAsEnum() == AK) + Attrs.push_back(Attr); + } +} + +void IRPosition::verify() { + switch (KindOrArgNo) { + default: + assert(KindOrArgNo >= 0 && "Expected argument or call site argument!"); + assert((isa<CallBase>(AnchorVal) || isa<Argument>(AnchorVal)) && + "Expected call base or argument for positive attribute index!"); + if (auto *Arg = dyn_cast<Argument>(AnchorVal)) { + assert(Arg->getArgNo() == unsigned(getArgNo()) && + "Argument number mismatch!"); + assert(Arg == &getAssociatedValue() && "Associated value mismatch!"); + } else { + auto &CB = cast<CallBase>(*AnchorVal); + assert(CB.arg_size() > unsigned(getArgNo()) && + "Call site argument number mismatch!"); + assert(CB.getArgOperand(getArgNo()) == &getAssociatedValue() && + "Associated value mismatch!"); + } + break; + case IRP_INVALID: + assert(!AnchorVal && "Expected no value for an invalid position!"); + break; + case IRP_FLOAT: + assert((!isa<CallBase>(&getAssociatedValue()) && + !isa<Argument>(&getAssociatedValue())) && + "Expected specialized kind for call base and argument values!"); + break; + case IRP_RETURNED: + assert(isa<Function>(AnchorVal) && + "Expected function for a 'returned' position!"); + assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); + break; + case IRP_CALL_SITE_RETURNED: + assert((isa<CallBase>(AnchorVal)) && + "Expected call base for 'call site returned' position!"); + assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); + break; + case IRP_CALL_SITE: + assert((isa<CallBase>(AnchorVal)) && + "Expected call base for 'call site function' position!"); + assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); + break; + case IRP_FUNCTION: + assert(isa<Function>(AnchorVal) && + "Expected function for a 'function' position!"); + assert(AnchorVal == &getAssociatedValue() && "Associated value mismatch!"); + break; + } +} + /// -----------------------NoUnwind Function Attribute-------------------------- struct AANoUnwindImpl : AANoUnwind { - IRPositionConstructorForward(AANoUnwindImpl, AANoUnwind); + AANoUnwindImpl(const IRPosition &IRP) : AANoUnwind(IRP) {} const std::string getAsStr() const override { return getAssumed() ? "nounwind" : "may-unwind"; @@ -327,7 +457,7 @@ struct AANoUnwindImpl : AANoUnwind { }; struct AANoUnwindFunction final : public AANoUnwindImpl { - AANoUnwindFunction(Function &F) : AANoUnwindImpl(F, IRP_FUNCTION) {} + AANoUnwindFunction(const IRPosition &IRP) : AANoUnwindImpl(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { @@ -336,7 +466,6 @@ struct AANoUnwindFunction final : public AANoUnwindImpl { }; ChangeStatus AANoUnwindImpl::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); // The map from instruction opcodes to those instructions in the function. auto Opcodes = { @@ -348,11 +477,11 @@ ChangeStatus AANoUnwindImpl::updateImpl(Attributor &A) { if (!I.mayThrow()) return true; - auto *NoUnwindAA = A.getAAFor<AANoUnwind>(*this, I); + auto *NoUnwindAA = A.getAAFor<AANoUnwind>(*this, IRPosition::value(I)); return NoUnwindAA && NoUnwindAA->isAssumedNoUnwind(); }; - if (!A.checkForAllInstructions(F, CheckForNoUnwind, *this, Opcodes)) + if (!A.checkForAllInstructions(CheckForNoUnwind, *this, Opcodes)) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; @@ -405,12 +534,11 @@ class AAReturnedValuesImpl : public AAReturnedValues, public AbstractState { } public: - IRPositionConstructorForward(AAReturnedValuesImpl, AAReturnedValues); + AAReturnedValuesImpl(const IRPosition &IRP) : AAReturnedValues(IRP) {} /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { // Reset the state. - setAssociatedValue(nullptr); IsFixed = false; IsValidState = true; HasOverdefinedReturnedCalls = false; @@ -494,8 +622,7 @@ public: }; struct AAReturnedValuesFunction final : public AAReturnedValuesImpl { - AAReturnedValuesFunction(Function &F) - : AAReturnedValuesImpl(F, IRP_FUNCTION) {} + AAReturnedValuesFunction(const IRPosition &IRP) : AAReturnedValuesImpl(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { @@ -523,8 +650,7 @@ ChangeStatus AAReturnedValuesImpl::manifest(Attributor &A) { // If the assumed unique return value is an argument, annotate it. if (auto *UniqueRVArg = dyn_cast<Argument>(UniqueRV.getValue())) { - setAssociatedValue(UniqueRVArg); - setAttributeIdx(UniqueRVArg->getArgNo() + AttributeList::FirstArgIndex); + getIRPosition() = IRPosition::argument(*UniqueRVArg); Changed = IRAttribute::manifest(A) | Changed; } @@ -563,7 +689,7 @@ AAReturnedValuesImpl::getAssumedUniqueReturnValue(Attributor &A) const { return true; }; - if (!A.checkForAllReturnedValues(getAnchorScope(), Pred, *this)) + if (!A.checkForAllReturnedValues(Pred, *this)) UniqueRV = nullptr; return UniqueRV; @@ -608,7 +734,7 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) { // Keep track of any change to trigger updates on dependent attributes. ChangeStatus Changed = ChangeStatus::UNCHANGED; - auto *LivenessAA = A.getAAFor<AAIsDead>(*this, getAnchorScope()); + auto *LivenessAA = A.getAAFor<AAIsDead>(*this, getIRPosition()); // Look at all returned call sites. for (auto &It : ReturnedValues) { @@ -637,7 +763,8 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) { } // Try to find a assumed unique return value for the called function. - auto *RetCSAA = A.getAAFor<AAReturnedValuesImpl>(*this, *RV); + auto *RetCSAA = A.getAAFor<AAReturnedValuesImpl>( + *this, IRPosition::callsite_returned(RetCS)); if (!RetCSAA) { if (!HasOverdefinedReturnedCalls) Changed = ChangeStatus::CHANGED; @@ -653,9 +780,9 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) { // If no assumed unique return value was found due to the lack of // candidates, we may need to resolve more calls (through more update - // iterations) or the called function will not return. Either way, we simply - // stick with the call sites as return values. Because there were not - // multiple possibilities, we do not treat it as overdefined. + // iterations) or the called function will not return. Either way, we + // simply stick with the call sites as return values. Because there were + // not multiple possibilities, we do not treat it as overdefined. if (!AssumedUniqueRV.hasValue()) continue; @@ -682,8 +809,9 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) { // If the assumed unique return value is an argument, lookup the matching // call site operand and recursively collect new returned values. - // If it is not an argument, it is just put into the set of returned values - // as we would have already looked through casts, phis, and similar values. + // If it is not an argument, it is just put into the set of returned + // values as we would have already looked through casts, phis, and similar + // values. if (Argument *AssumedRetArg = dyn_cast<Argument>(AssumedRetVal)) collectValuesRecursively(A, RetCS.getArgOperand(AssumedRetArg->getArgNo()), @@ -715,7 +843,7 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) { /// ------------------------ NoSync Function Attribute ------------------------- struct AANoSyncImpl : AANoSync { - IRPositionConstructorForward(AANoSyncImpl, AANoSync); + AANoSyncImpl(const IRPosition &IRP) : AANoSync(IRP) {} const std::string getAsStr() const override { return getAssumed() ? "nosync" : "may-sync"; @@ -738,7 +866,7 @@ struct AANoSyncImpl : AANoSync { }; struct AANoSyncFunction final : public AANoSyncImpl { - AANoSyncFunction(Function &F) : AANoSyncImpl(F, IRP_FUNCTION) {} + AANoSyncFunction(const IRPosition &IRP) : AANoSyncImpl(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECL_AND_TRACK_FN_ATTR(nosync) } @@ -834,24 +962,24 @@ bool AANoSyncImpl::isVolatile(Instruction *I) { } ChangeStatus AANoSyncImpl::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); auto CheckRWInstForNoSync = [&](Instruction &I) { /// We are looking for volatile instructions or Non-Relaxed atomics. /// FIXME: We should ipmrove the handling of intrinsics. - ImmutableCallSite ICS(&I); - auto *NoSyncAA = A.getAAFor<AANoSyncImpl>(*this, I); - if (isa<IntrinsicInst>(&I) && isNoSyncIntrinsic(&I)) return true; - if (ICS && (!NoSyncAA || !NoSyncAA->isAssumedNoSync()) && - !ICS.hasFnAttr(Attribute::NoSync)) - return false; + if (ImmutableCallSite ICS = ImmutableCallSite(&I)) { + if (ICS.hasFnAttr(Attribute::NoSync)) + return true; - if (ICS) - return true; + auto *NoSyncAA = + A.getAAFor<AANoSyncImpl>(*this, IRPosition::callsite_function(ICS)); + if (NoSyncAA && NoSyncAA->isAssumedNoSync()) + return true; + return false; + } if (!isVolatile(&I) && !isNonRelaxedAtomic(&I)) return true; @@ -869,8 +997,8 @@ ChangeStatus AANoSyncImpl::updateImpl(Attributor &A) { return !ImmutableCallSite(&I).isConvergent(); }; - if (!A.checkForAllReadWriteInstructions(F, CheckRWInstForNoSync, *this) || - !A.checkForAllCallLikeInstructions(F, CheckForNoSync, *this)) + if (!A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *this) || + !A.checkForAllCallLikeInstructions(CheckForNoSync, *this)) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; @@ -879,7 +1007,7 @@ ChangeStatus AANoSyncImpl::updateImpl(Attributor &A) { /// ------------------------ No-Free Attributes ---------------------------- struct AANoFreeImpl : public AANoFree { - IRPositionConstructorForward(AANoFreeImpl, AANoFree); + AANoFreeImpl(const IRPosition &IRP) : AANoFree(IRP) {} /// See AbstractAttribute::getAsStr(). const std::string getAsStr() const override { @@ -891,37 +1019,44 @@ struct AANoFreeImpl : public AANoFree { }; struct AANoFreeFunction final : public AANoFreeImpl { - AANoFreeFunction(Function &F) : AANoFreeImpl(F, IRP_FUNCTION) {} + AANoFreeFunction(const IRPosition &IRP) : AANoFreeImpl(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECL_AND_TRACK_FN_ATTR(nofree) } }; ChangeStatus AANoFreeImpl::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); auto CheckForNoFree = [&](Instruction &I) { - if (ImmutableCallSite(&I).hasFnAttr(Attribute::NoFree)) + ImmutableCallSite ICS(&I); + if (ICS.hasFnAttr(Attribute::NoFree)) return true; - auto *NoFreeAA = A.getAAFor<AANoFreeImpl>(*this, I); + auto *NoFreeAA = + A.getAAFor<AANoFreeImpl>(*this, IRPosition::callsite_function(ICS)); return NoFreeAA && NoFreeAA->isAssumedNoFree(); }; - if (!A.checkForAllCallLikeInstructions(F, CheckForNoFree, *this)) + if (!A.checkForAllCallLikeInstructions(CheckForNoFree, *this)) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; } /// ------------------------ NonNull Argument Attribute ------------------------ struct AANonNullImpl : AANonNull { - IRPositionConstructorForward(AANonNullImpl, AANonNull); + AANonNullImpl(const IRPosition &IRP) : AANonNull(IRP) {} /// See AbstractAttribute::getAsStr(). const std::string getAsStr() const override { return getAssumed() ? "nonnull" : "may-null"; } + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + if (hasAttr({Attribute::NonNull, Attribute::Dereferenceable})) + indicateOptimisticFixpoint(); + } + /// Generate a predicate that checks if a given value is assumed nonnull. /// The generated function returns true if a value satisfies any of /// following conditions. @@ -945,15 +1080,12 @@ AANonNullImpl::generatePredicate(Attributor &A) { if (isKnownNonZero(&RV, A.getDataLayout())) return true; - auto *NonNullAA = A.getAAFor<AANonNull>(*this, RV); - - ImmutableCallSite ICS(&RV); - - if ((!NonNullAA || !NonNullAA->isAssumedNonNull()) && - (!ICS || !ICS.hasRetAttr(Attribute::NonNull))) - return false; + if (ImmutableCallSite ICS = ImmutableCallSite(&RV)) + if (ICS.hasRetAttr(Attribute::NonNull)) + return true; - return true; + auto *NonNullAA = A.getAAFor<AANonNull>(*this, IRPosition::value(RV)); + return (NonNullAA && NonNullAA->isAssumedNonNull()); }; return Pred; @@ -961,19 +1093,7 @@ AANonNullImpl::generatePredicate(Attributor &A) { /// NonNull attribute for function return value. struct AANonNullReturned final : AANonNullImpl { - AANonNullReturned(Function &F) : AANonNullImpl(F, IRP_RETURNED) {} - - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - Function &F = getAnchorScope(); - - // Already nonnull. - if (F.getAttributes().hasAttribute(AttributeList::ReturnIndex, - Attribute::NonNull) || - F.getAttributes().hasAttribute(AttributeList::ReturnIndex, - Attribute::Dereferenceable)) - indicateOptimisticFixpoint(); - } + AANonNullReturned(const IRPosition &IRP) : AANonNullImpl(IRP) {} /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; @@ -985,26 +1105,18 @@ struct AANonNullReturned final : AANonNullImpl { }; ChangeStatus AANonNullReturned::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); std::function<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> Pred = this->generatePredicate(A); - if (!A.checkForAllReturnedValuesAndReturnInsts(F, Pred, *this)) + if (!A.checkForAllReturnedValuesAndReturnInsts(Pred, *this)) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; } /// NonNull attribute for function argument. struct AANonNullArgument final : AANonNullImpl { - AANonNullArgument(Argument &A) : AANonNullImpl(A) {} - - /// See AbstractAttriubute::initialize(...). - void initialize(Attributor &A) override { - Argument *Arg = cast<Argument>(getAssociatedValue()); - if (Arg->hasNonNullAttr()) - indicateOptimisticFixpoint(); - } + AANonNullArgument(const IRPosition &IRP) : AANonNullImpl(IRP) {} /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; @@ -1017,15 +1129,13 @@ struct AANonNullArgument final : AANonNullImpl { /// NonNull attribute for a call site argument. struct AANonNullCallSiteArgument final : AANonNullImpl { - AANonNullCallSiteArgument(Instruction &I, unsigned ArgNo) - : AANonNullImpl(CallSite(&I).getArgOperand(ArgNo), I, ArgNo) {} + AANonNullCallSiteArgument(const IRPosition &IRP) : AANonNullImpl(IRP) {} /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - CallSite CS(&getAnchorValue()); - if (CS.paramHasAttr(getArgNo(), getAttrKind()) || - CS.paramHasAttr(getArgNo(), Attribute::Dereferenceable) || - isKnownNonZero(getAssociatedValue(), A.getDataLayout())) + AANonNullImpl::initialize(A); + if (!isKnownNonNull() && + isKnownNonZero(&getAssociatedValue(), A.getDataLayout())) indicateOptimisticFixpoint(); } @@ -1039,34 +1149,31 @@ struct AANonNullCallSiteArgument final : AANonNullImpl { }; ChangeStatus AANonNullArgument::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); unsigned ArgNo = getArgNo(); // Callback function std::function<bool(CallSite)> CallSiteCheck = [&](CallSite CS) { assert(CS && "Sanity check: Call site was not initialized properly!"); - auto *NonNullAA = - A.getAAFor<AANonNullImpl>(*this, *CS.getInstruction(), ArgNo); + IRPosition CSArgPos = IRPosition::callsite_argument(CS, ArgNo); + if (CSArgPos.hasAttr({Attribute::NonNull, Attribute::Dereferenceable})) + return true; // Check that NonNullAA is AANonNullCallSiteArgument. - if (NonNullAA) { + if (auto *NonNullAA = A.getAAFor<AANonNullImpl>(*this, CSArgPos)) { ImmutableCallSite ICS(&NonNullAA->getAnchorValue()); if (ICS && CS.getInstruction() == ICS.getInstruction()) return NonNullAA->isAssumedNonNull(); return false; } - if (CS.paramHasAttr(ArgNo, Attribute::NonNull)) - return true; - Value *V = CS.getArgOperand(ArgNo); if (isKnownNonZero(V, A.getDataLayout())) return true; return false; }; - if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true)) + if (!A.checkForAllCallSites(CallSiteCheck, *this, true)) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; } @@ -1075,9 +1182,8 @@ ChangeStatus AANonNullCallSiteArgument::updateImpl(Attributor &A) { // NOTE: Never look at the argument of the callee in this method. // If we do this, "nonnull" is always deduced because of the assumption. - Value &V = *getAssociatedValue(); - - auto *NonNullAA = A.getAAFor<AANonNull>(*this, V); + Value &V = getAssociatedValue(); + auto *NonNullAA = A.getAAFor<AANonNull>(*this, IRPosition::value(V)); if (!NonNullAA || !NonNullAA->isAssumedNonNull()) return indicatePessimisticFixpoint(); @@ -1088,7 +1194,7 @@ ChangeStatus AANonNullCallSiteArgument::updateImpl(Attributor &A) { /// ------------------------ Will-Return Attributes ---------------------------- struct AAWillReturnImpl : public AAWillReturn { - IRPositionConstructorForward(AAWillReturnImpl, AAWillReturn); + AAWillReturnImpl(const IRPosition &IRP) : AAWillReturn(IRP) {} /// See AbstractAttribute::getAsStr() const std::string getAsStr() const override { @@ -1097,7 +1203,7 @@ struct AAWillReturnImpl : public AAWillReturn { }; struct AAWillReturnFunction final : AAWillReturnImpl { - AAWillReturnFunction(Function &F) : AAWillReturnImpl(F, IRP_FUNCTION) {} + AAWillReturnFunction(const IRPosition &IRP) : AAWillReturnImpl(IRP) {} /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override; @@ -1141,7 +1247,6 @@ void AAWillReturnFunction::initialize(Attributor &A) { } ChangeStatus AAWillReturnFunction::updateImpl(Attributor &A) { - const Function &F = getAnchorScope(); // The map from instruction opcodes to those instructions in the function. auto CheckForWillReturn = [&](Instruction &I) { @@ -1149,7 +1254,8 @@ ChangeStatus AAWillReturnFunction::updateImpl(Attributor &A) { if (ICS.hasFnAttr(Attribute::WillReturn)) return true; - auto *WillReturnAA = A.getAAFor<AAWillReturn>(*this, I); + IRPosition IPos = IRPosition::callsite_function(ICS); + auto *WillReturnAA = A.getAAFor<AAWillReturn>(*this, IPos); if (!WillReturnAA || !WillReturnAA->isAssumedWillReturn()) return false; @@ -1157,11 +1263,11 @@ ChangeStatus AAWillReturnFunction::updateImpl(Attributor &A) { if (ICS.hasFnAttr(Attribute::NoRecurse)) return true; - auto *NoRecurseAA = A.getAAFor<AANoRecurse>(*this, I); + auto *NoRecurseAA = A.getAAFor<AANoRecurse>(*this, IPos); return NoRecurseAA && NoRecurseAA->isAssumedNoRecurse(); }; - if (!A.checkForAllCallLikeInstructions(F, CheckForWillReturn, *this)) + if (!A.checkForAllCallLikeInstructions(CheckForWillReturn, *this)) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; @@ -1170,7 +1276,7 @@ ChangeStatus AAWillReturnFunction::updateImpl(Attributor &A) { /// ------------------------ NoAlias Argument Attribute ------------------------ struct AANoAliasImpl : AANoAlias { - IRPositionConstructorForward(AANoAliasImpl, AANoAlias); + AANoAliasImpl(const IRPosition &IRP) : AANoAlias(IRP) {} const std::string getAsStr() const override { return getAssumed() ? "noalias" : "may-alias"; @@ -1179,7 +1285,7 @@ struct AANoAliasImpl : AANoAlias { /// NoAlias attribute for function return value. struct AANoAliasReturned final : AANoAliasImpl { - AANoAliasReturned(Function &F) : AANoAliasImpl(F, IRP_RETURNED) {} + AANoAliasReturned(const IRPosition &IRP) : AANoAliasImpl(IRP) {} /// See AbstractAttriubute::initialize(...). void initialize(Attributor &A) override { @@ -1202,7 +1308,6 @@ struct AANoAliasReturned final : AANoAliasImpl { }; ChangeStatus AANoAliasReturned::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); auto CheckReturnValue = [&](Value &RV) -> bool { if (Constant *C = dyn_cast<Constant>(&RV)) @@ -1216,7 +1321,8 @@ ChangeStatus AANoAliasReturned::updateImpl(Attributor &A) { return false; if (!ICS.returnDoesNotAlias()) { - auto *NoAliasAA = A.getAAFor<AANoAlias>(*this, RV); + auto *NoAliasAA = + A.getAAFor<AANoAlias>(*this, IRPosition::callsite_returned(ICS)); if (!NoAliasAA || !NoAliasAA->isAssumedNoAlias()) return false; } @@ -1231,7 +1337,7 @@ ChangeStatus AANoAliasReturned::updateImpl(Attributor &A) { return true; }; - if (!A.checkForAllReturnedValues(F, CheckReturnValue, *this)) + if (!A.checkForAllReturnedValues(CheckReturnValue, *this)) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; @@ -1240,7 +1346,7 @@ ChangeStatus AANoAliasReturned::updateImpl(Attributor &A) { /// -------------------AAIsDead Function Attribute----------------------- struct AAIsDeadImpl : public AAIsDead { - IRPositionConstructorForward(AAIsDeadImpl, AAIsDead); + AAIsDeadImpl(const IRPosition &IRP) : AAIsDead(IRP) {} void initialize(Attributor &A) override { const Function &F = getAnchorScope(); @@ -1299,7 +1405,8 @@ struct AAIsDeadImpl : public AAIsDead { /// and only place an unreachable in the normal successor. if (Invoke2CallAllowed) { if (Function *Callee = II->getCalledFunction()) { - auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, *Callee); + auto *AANoUnw = + A.getAAFor<AANoUnwind>(*this, IRPosition::function(*Callee)); if (Callee->hasFnAttribute(Attribute::NoUnwind) || (AANoUnw && AANoUnw->isAssumedNoUnwind())) { LLVM_DEBUG(dbgs() @@ -1391,7 +1498,7 @@ struct AAIsDeadImpl : public AAIsDead { }; struct AAIsDeadFunction final : public AAIsDeadImpl { - AAIsDeadFunction(Function &F) : AAIsDeadImpl(F, IRP_FUNCTION) {} + AAIsDeadFunction(const IRPosition &IRP) : AAIsDeadImpl(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { @@ -1434,12 +1541,13 @@ const Instruction *AAIsDeadImpl::findNextNoReturn(Attributor &A, ImmutableCallSite ICS(I); if (ICS) { + const IRPosition &IPos = IRPosition::callsite_function(ICS); // Regarless of the no-return property of an invoke instruction we only // learn that the regular successor is not reachable through this // instruction but the unwind block might still be. if (auto *Invoke = dyn_cast<InvokeInst>(I)) { // Use nounwind to justify the unwind block is dead as well. - auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, *Invoke); + auto *AANoUnw = A.getAAFor<AANoUnwind>(*this, IPos); if (!Invoke2CallAllowed || (!AANoUnw || !AANoUnw->isAssumedNoUnwind())) { AssumedLiveBlocks.insert(Invoke->getUnwindDest()); @@ -1447,7 +1555,7 @@ const Instruction *AAIsDeadImpl::findNextNoReturn(Attributor &A, } } - auto *NoReturnAA = A.getAAFor<AANoReturn>(*this, *I); + auto *NoReturnAA = A.getAAFor<AANoReturn>(*this, IPos); if (ICS.hasFnAttr(Attribute::NoReturn) || (NoReturnAA && NoReturnAA->isAssumedNoReturn())) return I; @@ -1577,7 +1685,7 @@ struct DerefState : AbstractState { }; struct AADereferenceableImpl : AADereferenceable, DerefState { - IRPositionConstructorForward(AADereferenceableImpl, AADereferenceable); + AADereferenceableImpl(const IRPosition &IRP) : AADereferenceable(IRP) {} using StateType = DerefState; /// See AbstractAttribute::getState() @@ -1644,13 +1752,11 @@ struct AADereferenceableImpl : AADereferenceable, DerefState { bool &IsNonNull, bool &IsGlobal); void initialize(Attributor &A) override { - Function &F = getAnchorScope(); - unsigned AttrIdx = getIRPosition().getAttrIdx(); - - for (Attribute::AttrKind AK : - {Attribute::Dereferenceable, Attribute::DereferenceableOrNull}) - if (F.getAttributes().hasAttribute(AttrIdx, AK)) - takeKnownDerefBytesMaximum(F.getAttribute(AttrIdx, AK).getValueAsInt()); + SmallVector<Attribute, 4> Attrs; + getAttrs({Attribute::Dereferenceable, Attribute::DereferenceableOrNull}, + Attrs); + for (const Attribute &Attr : Attrs) + takeKnownDerefBytesMaximum(Attr.getValueAsInt()); } /// See AbstractAttribute::getAsStr(). @@ -1666,8 +1772,8 @@ struct AADereferenceableImpl : AADereferenceable, DerefState { }; struct AADereferenceableReturned final : AADereferenceableImpl { - AADereferenceableReturned(Function &F) - : AADereferenceableImpl(F, IRP_RETURNED) {} + AADereferenceableReturned(const IRPosition &IRP) + : AADereferenceableImpl(IRP) {} /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; @@ -1692,7 +1798,8 @@ uint64_t AADereferenceableImpl::computeAssumedDerefenceableBytes( IsGlobal = false; // First, we try to get information about V from Attributor. - if (auto *DerefAA = A.getAAFor<AADereferenceable>(*this, V)) { + if (auto *DerefAA = + A.getAAFor<AADereferenceable>(*this, IRPosition::value(V))) { IsNonNull &= DerefAA->isAssumedNonNull(); return DerefAA->getAssumedDereferenceableBytes(); } @@ -1704,7 +1811,8 @@ uint64_t AADereferenceableImpl::computeAssumedDerefenceableBytes( APInt Offset(IdxWidth, 0); Value *Base = V.stripAndAccumulateInBoundsConstantOffsets(DL, Offset); - if (auto *BaseDerefAA = A.getAAFor<AADereferenceable>(*this, *Base)) { + if (auto *BaseDerefAA = + A.getAAFor<AADereferenceable>(*this, IRPosition::value(*Base))) { IsNonNull &= Offset != 0; return calcDifferenceIfBaseIsNonNull( BaseDerefAA->getAssumedDereferenceableBytes(), Offset.getSExtValue(), @@ -1725,10 +1833,9 @@ uint64_t AADereferenceableImpl::computeAssumedDerefenceableBytes( } ChangeStatus AADereferenceableReturned::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); auto BeforeState = static_cast<DerefState>(*this); - syncNonNull(A.getAAFor<AANonNull>(*this, F)); + syncNonNull(A.getAAFor<AANonNull>(*this, getIRPosition())); bool IsNonNull = isAssumedNonNull(); bool IsGlobal = isAssumedGlobal(); @@ -1739,7 +1846,7 @@ ChangeStatus AADereferenceableReturned::updateImpl(Attributor &A) { return isValidState(); }; - if (A.checkForAllReturnedValues(F, CheckReturnValue, *this)) { + if (A.checkForAllReturnedValues(CheckReturnValue, *this)) { updateAssumedNonNullGlobalState(IsNonNull, IsGlobal); return BeforeState == static_cast<DerefState>(*this) ? ChangeStatus::UNCHANGED @@ -1749,7 +1856,8 @@ ChangeStatus AADereferenceableReturned::updateImpl(Attributor &A) { } struct AADereferenceableArgument final : AADereferenceableImpl { - AADereferenceableArgument(Argument &A) : AADereferenceableImpl(A) {} + AADereferenceableArgument(const IRPosition &IRP) + : AADereferenceableImpl(IRP) {} /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; @@ -1761,14 +1869,13 @@ struct AADereferenceableArgument final : AADereferenceableImpl { }; ChangeStatus AADereferenceableArgument::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); Argument &Arg = cast<Argument>(getAnchorValue()); auto BeforeState = static_cast<DerefState>(*this); unsigned ArgNo = Arg.getArgNo(); - syncNonNull(A.getAAFor<AANonNull>(*this, F, ArgNo)); + syncNonNull(A.getAAFor<AANonNull>(*this, getIRPosition())); bool IsNonNull = isAssumedNonNull(); bool IsGlobal = isAssumedGlobal(); @@ -1778,8 +1885,8 @@ ChangeStatus AADereferenceableArgument::updateImpl(Attributor &A) { assert(CS && "Sanity check: Call site was not initialized properly!"); // Check that DereferenceableAA is AADereferenceableCallSiteArgument. - if (auto *DereferenceableAA = - A.getAAFor<AADereferenceable>(*this, *CS.getInstruction(), ArgNo)) { + if (auto *DereferenceableAA = A.getAAFor<AADereferenceable>( + *this, IRPosition::callsite_argument(CS, ArgNo))) { ImmutableCallSite ICS( &DereferenceableAA->getIRPosition().getAnchorValue()); if (ICS && CS.getInstruction() == ICS.getInstruction()) { @@ -1797,7 +1904,7 @@ ChangeStatus AADereferenceableArgument::updateImpl(Attributor &A) { return isValidState(); }; - if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true)) + if (!A.checkForAllCallSites(CallSiteCheck, *this, true)) return indicatePessimisticFixpoint(); updateAssumedNonNullGlobalState(IsNonNull, IsGlobal); @@ -1808,18 +1915,8 @@ ChangeStatus AADereferenceableArgument::updateImpl(Attributor &A) { /// Dereferenceable attribute for a call site argument. struct AADereferenceableCallSiteArgument final : AADereferenceableImpl { - AADereferenceableCallSiteArgument(Instruction &I, unsigned ArgNo) - : AADereferenceableImpl(CallSite(&I).getArgOperand(ArgNo), I, ArgNo) {} - - /// See AbstractAttribute::initialize(...). - void initialize(Attributor &A) override { - CallSite CS(&getAnchorValue()); - if (CS.paramHasAttr(getArgNo(), Attribute::Dereferenceable)) - takeKnownDerefBytesMaximum(CS.getDereferenceableBytes(getArgNo())); - - if (CS.paramHasAttr(getArgNo(), Attribute::DereferenceableOrNull)) - takeKnownDerefBytesMaximum(CS.getDereferenceableOrNullBytes(getArgNo())); - } + AADereferenceableCallSiteArgument(const IRPosition &IRP) + : AADereferenceableImpl(IRP) {} /// See AbstractAttribute::updateImpl(Attributor &A). ChangeStatus updateImpl(Attributor &A) override; @@ -1835,11 +1932,11 @@ ChangeStatus AADereferenceableCallSiteArgument::updateImpl(Attributor &A) { // If we do this, "dereferenceable" is always deduced because of the // assumption. - Value &V = *getAssociatedValue(); + Value &V = getAssociatedValue(); auto BeforeState = static_cast<DerefState>(*this); - syncNonNull(A.getAAFor<AANonNull>(*this, getAnchorValue(), getArgNo())); + syncNonNull(A.getAAFor<AANonNull>(*this, getIRPosition())); bool IsNonNull = isAssumedNonNull(); bool IsGlobal = isKnownGlobal(); @@ -1854,7 +1951,7 @@ ChangeStatus AADereferenceableCallSiteArgument::updateImpl(Attributor &A) { // ------------------------ Align Argument Attribute ------------------------ struct AAAlignImpl : AAAlign { - IRPositionConstructorForward(AAAlignImpl, AAAlign); + AAAlignImpl(const IRPosition &IRP) : AAAlign(IRP) {} // Max alignemnt value allowed in IR static const unsigned MAX_ALIGN = 1U << 29; @@ -1869,13 +1966,10 @@ struct AAAlignImpl : AAAlign { void initialize(Attributor &A) override { takeAssumedMinimum(MAX_ALIGN); - Function &F = getAnchorScope(); - - unsigned AttrIdx = getAttrIdx(); - // Already the function has align attribute on return value or argument. - if (F.getAttributes().hasAttribute(AttrIdx, Attribute::Alignment)) - addKnownBits( - F.getAttribute(AttrIdx, Attribute::Alignment).getAlignment()); + SmallVector<Attribute, 4> Attrs; + getAttrs({Attribute::Alignment}, Attrs); + for (const Attribute &Attr : Attrs) + takeKnownMaximum(Attr.getValueAsInt()); } /// See AbstractAttribute::getDeducedAttributes @@ -1888,7 +1982,7 @@ struct AAAlignImpl : AAAlign { /// Align attribute for function return value. struct AAAlignReturned final : AAAlignImpl { - AAAlignReturned(Function &F) : AAAlignImpl(F, IRP_RETURNED) {} + AAAlignReturned(const IRPosition &IRP) : AAAlignImpl(IRP) {} /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; @@ -1900,7 +1994,6 @@ struct AAAlignReturned final : AAAlignImpl { }; ChangeStatus AAAlignReturned::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); // Currently, align<n> is deduced if alignments in return values are assumed // as greater than n. We reach pessimistic fixpoint if any of the return value @@ -1910,7 +2003,7 @@ ChangeStatus AAAlignReturned::updateImpl(Attributor &A) { base_t BeforeState = getAssumed(); auto CheckReturnValue = [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &RetInsts) -> bool { - auto *AlignAA = A.getAAFor<AAAlign>(*this, RV); + auto *AlignAA = A.getAAFor<AAAlign>(*this, IRPosition::value(RV)); if (AlignAA) takeAssumedMinimum(AlignAA->getAssumedAlign()); @@ -1921,7 +2014,7 @@ ChangeStatus AAAlignReturned::updateImpl(Attributor &A) { return isValidState(); }; - if (!A.checkForAllReturnedValuesAndReturnInsts(F, CheckReturnValue, *this)) + if (!A.checkForAllReturnedValuesAndReturnInsts(CheckReturnValue, *this)) return indicatePessimisticFixpoint(); return (getAssumed() != BeforeState) ? ChangeStatus::CHANGED @@ -1930,7 +2023,7 @@ ChangeStatus AAAlignReturned::updateImpl(Attributor &A) { /// Align attribute for function argument. struct AAAlignArgument final : AAAlignImpl { - AAAlignArgument(Argument &A) : AAAlignImpl(A) {} + AAAlignArgument(const IRPosition &IRP) : AAAlignImpl(IRP) {} /// See AbstractAttribute::updateImpl(...). virtual ChangeStatus updateImpl(Attributor &A) override; @@ -1941,7 +2034,6 @@ struct AAAlignArgument final : AAAlignImpl { ChangeStatus AAAlignArgument::updateImpl(Attributor &A) { - Function &F = getAnchorScope(); Argument &Arg = cast<Argument>(getAnchorValue()); unsigned ArgNo = Arg.getArgNo(); @@ -1953,7 +2045,8 @@ ChangeStatus AAAlignArgument::updateImpl(Attributor &A) { std::function<bool(CallSite)> CallSiteCheck = [&](CallSite CS) { assert(CS && "Sanity check: Call site was not initialized properly!"); - auto *AlignAA = A.getAAFor<AAAlign>(*this, *CS.getInstruction(), ArgNo); + auto *AlignAA = + A.getAAFor<AAAlign>(*this, IRPosition::callsite_argument(CS, ArgNo)); // Check that AlignAA is AAAlignCallSiteArgument. if (AlignAA) { @@ -1969,7 +2062,7 @@ ChangeStatus AAAlignArgument::updateImpl(Attributor &A) { return isValidState(); }; - if (!A.checkForAllCallSites(F, CallSiteCheck, *this, true)) + if (!A.checkForAllCallSites(CallSiteCheck, *this, true)) indicatePessimisticFixpoint(); return BeforeState == getAssumed() ? ChangeStatus::UNCHANGED @@ -1977,14 +2070,12 @@ ChangeStatus AAAlignArgument::updateImpl(Attributor &A) { } struct AAAlignCallSiteArgument final : AAAlignImpl { - AAAlignCallSiteArgument(Instruction &I, unsigned ArgNo) - : AAAlignImpl(CallSite(&I).getArgOperand(ArgNo), I, ArgNo) {} + AAAlignCallSiteArgument(const IRPosition &IRP) : AAAlignImpl(IRP) {} /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - CallSite CS(&getAnchorValue()); takeKnownMaximum( - getAssociatedValue()->getPointerAlignment(A.getDataLayout())); + getAssociatedValue().getPointerAlignment(A.getDataLayout())); } /// See AbstractAttribute::updateImpl(Attributor &A). @@ -2002,9 +2093,8 @@ ChangeStatus AAAlignCallSiteArgument::updateImpl(Attributor &A) { auto BeforeState = getAssumed(); - Value &V = *getAssociatedValue(); - - auto *AlignAA = A.getAAFor<AAAlign>(*this, V); + Value &V = getAssociatedValue(); + auto *AlignAA = A.getAAFor<AAAlign>(*this, IRPosition::value(V)); if (AlignAA) takeAssumedMinimum(AlignAA->getAssumedAlign()); @@ -2017,7 +2107,7 @@ ChangeStatus AAAlignCallSiteArgument::updateImpl(Attributor &A) { /// ------------------ Function No-Return Attribute ---------------------------- struct AANoReturnImpl : public AANoReturn { - IRPositionConstructorForward(AANoReturnImpl, AANoReturn); + AANoReturnImpl(const IRPosition &IRP) : AANoReturn(IRP) {} /// See AbstractAttribute::getAsStr(). const std::string getAsStr() const override { @@ -2026,16 +2116,14 @@ struct AANoReturnImpl : public AANoReturn { /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - Function &F = getAnchorScope(); - if (F.hasFnAttribute(getAttrKind())) + if (hasAttr({getAttrKind()})) indicateOptimisticFixpoint(); } /// See AbstractAttribute::updateImpl(Attributor &A). virtual ChangeStatus updateImpl(Attributor &A) override { - const Function &F = getAnchorScope(); auto CheckForNoReturn = [](Instruction &) { return false; }; - if (!A.checkForAllInstructions(F, CheckForNoReturn, *this, + if (!A.checkForAllInstructions(CheckForNoReturn, *this, {(unsigned)Instruction::Ret})) return indicatePessimisticFixpoint(); return ChangeStatus::UNCHANGED; @@ -2043,7 +2131,7 @@ struct AANoReturnImpl : public AANoReturn { }; struct AANoReturnFunction final : AANoReturnImpl { - AANoReturnFunction(Function &F) : AANoReturnImpl(F, IRP_FUNCTION) {} + AANoReturnFunction(const IRPosition &IRP) : AANoReturnImpl(IRP) {} /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { @@ -2055,26 +2143,31 @@ struct AANoReturnFunction final : AANoReturnImpl { /// Attributor /// ---------------------------------------------------------------------------- -bool Attributor::checkForAllCallSites(Function &F, - std::function<bool(CallSite)> &Pred, +bool Attributor::checkForAllCallSites(const function_ref<bool(CallSite)> &Pred, const AbstractAttribute &QueryingAA, bool RequireAllCallSites) { // We can try to determine information from // the call sites. However, this is only possible all call sites are known, // hence the function has internal linkage. - if (RequireAllCallSites && !F.hasInternalLinkage()) { + const IRPosition &IRP = QueryingAA.getIRPosition(); + const Function *AssociatedFunction = IRP.getAssociatedFunction(); + if (!AssociatedFunction) + return false; + + if (RequireAllCallSites && !AssociatedFunction->hasInternalLinkage()) { LLVM_DEBUG( dbgs() - << "Attributor: Function " << F.getName() + << "Attributor: Function " << AssociatedFunction->getName() << " has no internal linkage, hence not all call sites are known\n"); return false; } - for (const Use &U : F.uses()) { + for (const Use &U : AssociatedFunction->uses()) { Instruction *I = cast<Instruction>(U.getUser()); - Function *AnchorValue = I->getParent()->getParent(); + Function *Caller = I->getFunction(); - auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, *AnchorValue); + auto *LivenessAA = + getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*Caller)); // Skip dead calls. if (LivenessAA && LivenessAA->isAssumedDead(I)) @@ -2086,7 +2179,8 @@ bool Attributor::checkForAllCallSites(Function &F, continue; LLVM_DEBUG(dbgs() << "Attributor: User " << *U.getUser() - << " is an invalid use of " << F.getName() << "\n"); + << " is an invalid use of " + << AssociatedFunction->getName() << "\n"); return false; } @@ -2102,16 +2196,26 @@ bool Attributor::checkForAllCallSites(Function &F, } bool Attributor::checkForAllReturnedValuesAndReturnInsts( - const Function &F, const function_ref<bool(Value &, const SmallPtrSetImpl<ReturnInst *> &)> &Pred, const AbstractAttribute &QueryingAA) { - auto *AARetVal = getAAFor<AAReturnedValues>(QueryingAA, F); - if (!AARetVal) + const IRPosition &IRP = QueryingAA.getIRPosition(); + // Since we need to provide return instructions we have to have an exact + // definition. + const Function *AssociatedFunction = IRP.getAssociatedFunction(); + if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition()) return false; - auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F); + // If this is a call site query we use the call site specific return values + // and liveness information. + const IRPosition &QueryIRP = IRPosition::function_scope(IRP); + const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP); + if (!AARetVal || !AARetVal->getState().isValidState()) + return false; + + auto *LivenessAA = + getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*AssociatedFunction)); if (!LivenessAA) return AARetVal->checkForAllReturnedValuesAndReturnInsts(Pred); @@ -2130,14 +2234,21 @@ bool Attributor::checkForAllReturnedValuesAndReturnInsts( } bool Attributor::checkForAllReturnedValues( - const Function &F, const function_ref<bool(Value &)> &Pred, + const function_ref<bool(Value &)> &Pred, const AbstractAttribute &QueryingAA) { - auto *AARetVal = getAAFor<AAReturnedValues>(QueryingAA, F); - if (!AARetVal) + const IRPosition &IRP = QueryingAA.getIRPosition(); + const Function *AssociatedFunction = IRP.getAssociatedFunction(); + if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition()) + return false; + + const IRPosition &QueryIRP = IRPosition::function_scope(IRP); + const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP); + if (!AARetVal || !AARetVal->getState().isValidState()) return false; - auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F); + auto *LivenessAA = + getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*AssociatedFunction)); if (!LivenessAA) return AARetVal->checkForAllReturnedValuesAndReturnInsts( [&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &) { @@ -2155,12 +2266,20 @@ bool Attributor::checkForAllReturnedValues( } bool Attributor::checkForAllInstructions( - const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred, + const llvm::function_ref<bool(Instruction &)> &Pred, const AbstractAttribute &QueryingAA, const ArrayRef<unsigned> &Opcodes) { - auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F); + const IRPosition &IRP = QueryingAA.getIRPosition(); + // Since we need to provide instructions we have to have an exact definition. + const Function *AssociatedFunction = IRP.getAssociatedFunction(); + if (!AssociatedFunction || !AssociatedFunction->hasExactDefinition()) + return false; + + const IRPosition &QueryIRP = IRPosition::function_scope(IRP); + const auto &LivenessAA = getAAFor<AAIsDead>(QueryingAA, QueryIRP); - auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F); + auto &OpcodeInstMap = + InfoCache.getOpcodeInstMapForFunction(*AssociatedFunction); for (unsigned Opcode : Opcodes) { for (Instruction *I : OpcodeInstMap[Opcode]) { // Skip dead instructions. @@ -2176,12 +2295,19 @@ bool Attributor::checkForAllInstructions( } bool Attributor::checkForAllReadWriteInstructions( - const Function &F, const llvm::function_ref<bool(Instruction &)> &Pred, + const llvm::function_ref<bool(Instruction &)> &Pred, AbstractAttribute &QueryingAA) { - auto *LivenessAA = getAAFor<AAIsDead>(QueryingAA, F); + const Function *AssociatedFunction = + QueryingAA.getIRPosition().getAssociatedFunction(); + if (!AssociatedFunction) + return false; + + const auto &LivenessAA = + getAAFor<AAIsDead>(QueryingAA, QueryingAA.getIRPosition()); - for (Instruction *I : InfoCache.getReadOrWriteInstsForFunction(F)) { + for (Instruction *I : + InfoCache.getReadOrWriteInstsForFunction(*AssociatedFunction)) { // Skip dead instructions. if (LivenessAA && LivenessAA->isAssumedDead(I)) continue; @@ -2331,83 +2457,83 @@ ChangeStatus Attributor::run() { } /// Helper function that checks if an abstract attribute of type \p AAType -/// should be created for \p V (with argument number \p ArgNo) and if so creates -/// and registers it with the Attributor \p A. +/// should be created for IR position \p IRP and if so creates and registers it +/// with the Attributor \p A. /// /// This method will look at the provided whitelist. If one is given and the /// kind \p AAType::ID is not contained, no abstract attribute is created. /// /// \returns The created abstract argument, or nullptr if none was created. -template <typename AAType, typename ValueType, typename... ArgsTy> -static AAType *checkAndRegisterAA(const Function &F, Attributor &A, - DenseSet<const char *> *Whitelist, - ValueType &V, int ArgNo, ArgsTy... Args) { +template <typename AAType> +static AAType *checkAndRegisterAA(IRPosition &IRP, Attributor &A, + DenseSet<const char *> *Whitelist) { if (Whitelist && !Whitelist->count(&AAType::ID)) return nullptr; - return &A.registerAA<AAType>(*new AAType(V, Args...), ArgNo); + return &A.registerAA<AAType>(*new AAType(IRP)); } void Attributor::identifyDefaultAbstractAttributes( Function &F, DenseSet<const char *> *Whitelist) { + IRPosition FPos = IRPosition::function(F); + // Check for dead BasicBlocks in every function. // We need dead instruction detection because we do not want to deal with // broken IR in which SSA rules do not apply. - checkAndRegisterAA<AAIsDeadFunction>(F, *this, /* Whitelist */ nullptr, F, - -1); + checkAndRegisterAA<AAIsDeadFunction>(FPos, *this, /* Whitelist */ nullptr); // Every function might be "will-return". - checkAndRegisterAA<AAWillReturnFunction>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AAWillReturnFunction>(FPos, *this, Whitelist); // Every function can be nounwind. - checkAndRegisterAA<AANoUnwindFunction>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AANoUnwindFunction>(FPos, *this, Whitelist); // Every function might be marked "nosync" - checkAndRegisterAA<AANoSyncFunction>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AANoSyncFunction>(FPos, *this, Whitelist); // Every function might be "no-free". - checkAndRegisterAA<AANoFreeFunction>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AANoFreeFunction>(FPos, *this, Whitelist); // Every function might be "no-return". - checkAndRegisterAA<AANoReturnFunction>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AANoReturnFunction>(FPos, *this, Whitelist); // Return attributes are only appropriate if the return type is non void. Type *ReturnType = F.getReturnType(); if (!ReturnType->isVoidTy()) { // Argument attribute "returned" --- Create only one per function even // though it is an argument attribute. - checkAndRegisterAA<AAReturnedValuesFunction>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AAReturnedValuesFunction>(FPos, *this, Whitelist); if (ReturnType->isPointerTy()) { + IRPosition RetPos = IRPosition::returned(F); + // Every function with pointer return type might be marked align. - checkAndRegisterAA<AAAlignReturned>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AAAlignReturned>(RetPos, *this, Whitelist); // Every function with pointer return type might be marked nonnull. - checkAndRegisterAA<AANonNullReturned>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AANonNullReturned>(RetPos, *this, Whitelist); // Every function with pointer return type might be marked noalias. - checkAndRegisterAA<AANoAliasReturned>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AANoAliasReturned>(RetPos, *this, Whitelist); // Every function with pointer return type might be marked // dereferenceable. - checkAndRegisterAA<AADereferenceableReturned>(F, *this, Whitelist, F, -1); + checkAndRegisterAA<AADereferenceableReturned>(RetPos, *this, Whitelist); } } for (Argument &Arg : F.args()) { if (Arg.getType()->isPointerTy()) { + IRPosition ArgPos = IRPosition::argument(Arg); // Every argument with pointer type might be marked nonnull. - checkAndRegisterAA<AANonNullArgument>(F, *this, Whitelist, Arg, - Arg.getArgNo()); + checkAndRegisterAA<AANonNullArgument>(ArgPos, *this, Whitelist); // Every argument with pointer type might be marked dereferenceable. - checkAndRegisterAA<AADereferenceableArgument>(F, *this, Whitelist, Arg, - Arg.getArgNo()); + checkAndRegisterAA<AADereferenceableArgument>(ArgPos, *this, Whitelist); // Every argument with pointer type might be marked align. - checkAndRegisterAA<AAAlignArgument>(F, *this, Whitelist, Arg, - Arg.getArgNo()); + checkAndRegisterAA<AAAlignArgument>(ArgPos, *this, Whitelist); } } @@ -2450,18 +2576,18 @@ void Attributor::identifyDefaultAbstractAttributes( for (int i = 0, e = CS.getCalledFunction()->arg_size(); i < e; i++) { if (!CS.getArgument(i)->getType()->isPointerTy()) continue; + IRPosition CSArgPos = IRPosition::callsite_argument(CS, i); // Call site argument attribute "non-null". - checkAndRegisterAA<AANonNullCallSiteArgument>(F, *this, Whitelist, I, i, - i); + checkAndRegisterAA<AANonNullCallSiteArgument>(CSArgPos, *this, + Whitelist); // Call site argument attribute "dereferenceable". - checkAndRegisterAA<AADereferenceableCallSiteArgument>( - F, *this, Whitelist, I, i, i); + checkAndRegisterAA<AADereferenceableCallSiteArgument>(CSArgPos, *this, + Whitelist); // Call site argument attribute "align". - checkAndRegisterAA<AAAlignCallSiteArgument>(F, *this, Whitelist, I, i, - i); + checkAndRegisterAA<AAAlignCallSiteArgument>(CSArgPos, *this, Whitelist); } } } @@ -2476,22 +2602,29 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, ChangeStatus S) { raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) { switch (AP) { + case IRPosition::IRP_INVALID: + return OS << "inv"; + case IRPosition::IRP_FLOAT: + return OS << "flt"; + case IRPosition::IRP_RETURNED: + return OS << "fn_ret"; + case IRPosition::IRP_CALL_SITE_RETURNED: + return OS << "cs_ret"; + case IRPosition::IRP_FUNCTION: + return OS << "fn"; + case IRPosition::IRP_CALL_SITE: + return OS << "cs"; case IRPosition::IRP_ARGUMENT: return OS << "arg"; case IRPosition::IRP_CALL_SITE_ARGUMENT: return OS << "cs_arg"; - case IRPosition::IRP_FUNCTION: - return OS << "fn"; - case IRPosition::IRP_RETURNED: - return OS << "fn_ret"; } llvm_unreachable("Unknown attribute position!"); } raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) { - const Value *AV = Pos.getAssociatedValue(); - return OS << "{" << Pos.getPositionKind() << ":" - << (AV ? AV->getName() : "n/a") << " [" + const Value &AV = Pos.getAssociatedValue(); + return OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " [" << Pos.getAnchorValue().getName() << "@" << Pos.getArgNo() << "]}"; } |