summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Transforms/IPO/Attributor.h76
-rw-r--r--llvm/lib/Transforms/IPO/Attributor.cpp334
-rw-r--r--llvm/test/Transforms/FunctionAttrs/align.ll25
-rw-r--r--llvm/test/Transforms/FunctionAttrs/arg_returned.ll3
-rw-r--r--llvm/test/Transforms/FunctionAttrs/dereferenceable.ll9
-rw-r--r--llvm/test/Transforms/FunctionAttrs/noalias_returned.ll10
-rw-r--r--llvm/test/Transforms/FunctionAttrs/nonnull.ll40
-rw-r--r--llvm/test/Transforms/FunctionAttrs/nosync.ll5
-rw-r--r--llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll1
9 files changed, 275 insertions, 228 deletions
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 7e03e54fde5..9795922427c 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -589,32 +589,30 @@ struct Attributor {
/// the one reasoning about the "captured" state for the argument or the one
/// reasoning on the memory access behavior of the function as a whole.
template <typename AAType>
- const AAType *getAAFor(const AbstractAttribute &QueryingAA,
+ const AAType &getAAFor(const AbstractAttribute &QueryingAA,
const IRPosition &IRP) {
static_assert(std::is_base_of<AbstractAttribute, AAType>::value,
"Cannot query an attribute with a type not derived from "
"'AbstractAttribute'!");
- // Let's try an equivalent position if available, see
- // SubsumingPositionIterator for more information.
- for (const IRPosition &EquivIRP : SubsumingPositionIterator(IRP)) {
- // Lookup the abstract attribute of type AAType. If found, return it after
- // registering a dependence of QueryingAA on the one returned attribute.
- const auto &KindToAbstractAttributeMap =
- AAMap.lookup(const_cast<IRPosition &>(EquivIRP));
- if (AAType *AA = static_cast<AAType *>(
- KindToAbstractAttributeMap.lookup(&AAType::ID))) {
- // Do not return an attribute with an invalid state. This minimizes
- // checks at the calls sites and allows the fallback below to kick in.
- if (AA->getState().isValidState()) {
- QueryMap[AA].insert(const_cast<AbstractAttribute *>(&QueryingAA));
- return AA;
- }
- }
+ // Lookup the abstract attribute of type AAType. If found, return it after
+ // registering a dependence of QueryingAA on the one returned attribute.
+ const auto &KindToAbstractAttributeMap =
+ AAMap.lookup(const_cast<IRPosition &>(IRP));
+ if (AAType *AA = static_cast<AAType *>(
+ KindToAbstractAttributeMap.lookup(&AAType::ID))) {
+ // Do not registr a dependence on an attribute with an invalid state.
+ if (AA->getState().isValidState())
+ QueryMap[AA].insert(const_cast<AbstractAttribute *>(&QueryingAA));
+ return *AA;
}
- // No matching attribute found
- return nullptr;
+ // No matching attribute found, create one.
+ auto &AA = AAType::createForPosition(IRP, *this);
+ registerAA(AA);
+ if (AA.getState().isValidState())
+ QueryMap[&AA].insert(const_cast<AbstractAttribute *>(&QueryingAA));
+ return AA;
}
/// Introduce a new abstract attribute into the fixpoint analysis.
@@ -1145,6 +1143,10 @@ struct AAReturnedValues
virtual size_t getNumReturnValues() const = 0;
virtual const SmallPtrSetImpl<CallBase *> &getUnresolvedCalls() const = 0;
+ /// Create an abstract attribute view for the position \p IRP.
+ static AAReturnedValues &createForPosition(const IRPosition &IRP,
+ Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1160,6 +1162,9 @@ struct AANoUnwind
/// Returns true if nounwind is known.
bool isKnownNoUnwind() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AANoUnwind &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1175,6 +1180,9 @@ struct AANoSync
/// Returns true if "nosync" is known.
bool isKnownNoSync() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AANoSync &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1191,6 +1199,9 @@ struct AANonNull
/// Return true if we know that underlying value is nonnull.
bool isKnownNonNull() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AANonNull &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1207,6 +1218,9 @@ struct AANoRecurse
/// Return true if "norecurse" is known.
bool isKnownNoRecurse() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AANoRecurse &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1223,6 +1237,9 @@ struct AAWillReturn
/// Return true if "willreturn" is known.
bool isKnownWillReturn() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AAWillReturn &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1239,6 +1256,9 @@ struct AANoAlias
/// Return true if we know that underlying value is noalias.
bool isKnownNoAlias() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AANoAlias &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1255,6 +1275,9 @@ struct AANoFree
/// Return true if "nofree" is known.
bool isKnownNoFree() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AANoFree &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1271,6 +1294,9 @@ struct AANoReturn
/// Return true if the underlying object is known to never return.
bool isKnownNoReturn() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AANoReturn &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1296,7 +1322,7 @@ struct AAIsDead : public StateWrapper<BooleanState, AbstractAttribute>,
/// of instructions is live.
template <typename T> bool isLiveInstSet(T begin, T end) const {
for (const auto &I : llvm::make_range(begin, end)) {
- assert(I->getFunction() == getIRPosition().getAnchorScope() &&
+ assert(I->getFunction() == getIRPosition().getAssociatedFunction() &&
"Instruction must be in the same anchor scope function.");
if (!isAssumedDead(I))
@@ -1313,6 +1339,9 @@ struct AAIsDead : public StateWrapper<BooleanState, AbstractAttribute>,
const IRPosition &getIRPosition() const { return *this; }
///}
+ /// Create an abstract attribute view for the position \p IRP.
+ static AAIsDead &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1339,6 +1368,10 @@ struct AADereferenceable
/// Return known dereferenceable bytes.
virtual uint32_t getKnownDereferenceableBytes() const = 0;
+ /// Create an abstract attribute view for the position \p IRP.
+ static AADereferenceable &createForPosition(const IRPosition &IRP,
+ Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
@@ -1355,6 +1388,9 @@ struct AAAlign
/// Return known alignemnt.
unsigned getKnownAlign() const { return getKnown(); }
+ /// Create an abstract attribute view for the position \p IRP.
+ static AAAlign &createForPosition(const IRPosition &IRP, Attributor &A);
+
/// Unique ID (due to the unique address)
static const char ID;
};
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 1ae658dbd4f..0e86efd5eab 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -146,7 +146,7 @@ bool genericValueTraversal(
const AAIsDead *LivenessAA = nullptr;
if (IRP.getAnchorScope())
- LivenessAA = A.getAAFor<AAIsDead>(
+ LivenessAA = &A.getAAFor<AAIsDead>(
QueryingAA, IRPosition::function(*IRP.getAnchorScope()));
// TODO: Use Positions here to allow context sensitivity in VisitValueCB
@@ -196,10 +196,11 @@ bool genericValueTraversal(
// Look through phi nodes, visit all live operands.
if (auto *PHI = dyn_cast<PHINode>(V)) {
+ assert(LivenessAA &&
+ "Expected liveness in the presence of instructions!");
for (unsigned u = 0, e = PHI->getNumIncomingValues(); u < e; u++) {
const BasicBlock *IncomingBB = PHI->getIncomingBlock(u);
- if (!LivenessAA ||
- !LivenessAA->isAssumedDead(IncomingBB->getTerminator()))
+ if (!LivenessAA->isAssumedDead(IncomingBB->getTerminator()))
Worklist.push_back(PHI->getIncomingValue(u));
}
continue;
@@ -275,8 +276,6 @@ ChangeStatus AbstractAttribute::update(Attributor &A) {
ChangeStatus
IRAttributeManifest::manifestAttrs(Attributor &A, IRPosition &IRP,
const ArrayRef<Attribute> &DeducedAttrs) {
- ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
-
Function *ScopeFn = IRP.getAssociatedFunction();
IRPosition::Kind PK = IRP.getPositionKind();
@@ -288,7 +287,7 @@ IRAttributeManifest::manifestAttrs(Attributor &A, IRPosition &IRP,
switch (PK) {
case IRPosition::IRP_INVALID:
case IRPosition::IRP_FLOAT:
- llvm_unreachable("Cannot manifest at a floating or invalid position!");
+ return ChangeStatus::UNCHANGED;
case IRPosition::IRP_ARGUMENT:
case IRPosition::IRP_FUNCTION:
case IRPosition::IRP_RETURNED:
@@ -301,6 +300,7 @@ IRAttributeManifest::manifestAttrs(Attributor &A, IRPosition &IRP,
break;
}
+ ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
LLVMContext &Ctx = IRP.getAnchorValue().getContext();
for (const Attribute &Attr : DeducedAttrs) {
if (!addIfNotExistent(Ctx, Attr, Attrs, IRP.getAttrIdx()))
@@ -502,15 +502,10 @@ static void clampReturnedValueStates(Attributor &A, const AAType &QueryingAA,
// Callback for each possibly returned value.
auto CheckReturnValue = [&](Value &RV) -> bool {
const IRPosition &RVPos = IRPosition::value(RV);
- const AAType *AA = A.getAAFor<AAType>(QueryingAA, RVPos);
- LLVM_DEBUG(dbgs() << "[Attributor] RV: " << RV
- << " AA: " << (AA ? AA->getAsStr() : "n/a") << " @ "
- << RVPos << "\n");
- // TODO: We should create abstract attributes on-demand, patches are already
- // prepared, pending approval.
- if (!AA || AA->getIRPosition() != RVPos)
- return false;
- const StateType &AAS = static_cast<const StateType &>(AA->getState());
+ const AAType &AA = A.getAAFor<AAType>(QueryingAA, RVPos);
+ LLVM_DEBUG(dbgs() << "[Attributor] RV: " << RV << " AA: " << AA.getAsStr()
+ << " @ " << RVPos << "\n");
+ const StateType &AAS = static_cast<const StateType &>(AA.getState());
if (T.hasValue())
*T &= AAS;
else
@@ -527,9 +522,10 @@ static void clampReturnedValueStates(Attributor &A, const AAType &QueryingAA,
}
/// Helper class for generic deduction: return value -> returned position.
-template <typename AAType, typename StateType = typename AAType::StateType>
-struct AAReturnedFromReturnedValues : public AAType {
- AAReturnedFromReturnedValues(const IRPosition &IRP) : AAType(IRP) {}
+template <typename AAType, typename Base,
+ typename StateType = typename AAType::StateType>
+struct AAReturnedFromReturnedValues : public Base {
+ AAReturnedFromReturnedValues(const IRPosition &IRP) : Base(IRP) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
@@ -563,15 +559,10 @@ static void clampCallSiteArgumentStates(Attributor &A, const AAType &QueryingAA,
auto CallSiteCheck = [&](CallSite CS) {
const IRPosition &CSArgPos = IRPosition::callsite_argument(CS, ArgNo);
- const AAType *AA = A.getAAFor<AAType>(QueryingAA, CSArgPos);
+ const AAType &AA = A.getAAFor<AAType>(QueryingAA, CSArgPos);
LLVM_DEBUG(dbgs() << "[Attributor] CS: " << *CS.getInstruction()
- << " AA: " << (AA ? AA->getAsStr() : "n/a") << " @"
- << CSArgPos << "\n");
- // TODO: We should create abstract attributes on-demand, patches are already
- // prepared, pending approval.
- if (!AA || AA->getIRPosition() != CSArgPos)
- return false;
- const StateType &AAS = static_cast<const StateType &>(AA->getState());
+ << " AA: " << AA.getAsStr() << " @" << CSArgPos << "\n");
+ const StateType &AAS = static_cast<const StateType &>(AA.getState());
if (T.hasValue())
*T &= AAS;
else
@@ -588,9 +579,10 @@ static void clampCallSiteArgumentStates(Attributor &A, const AAType &QueryingAA,
}
/// Helper class for generic deduction: call site argument -> argument position.
-template <typename AAType, typename StateType = typename AAType::StateType>
-struct AAArgumentFromCallSiteArguments : public AAType {
- AAArgumentFromCallSiteArguments(const IRPosition &IRP) : AAType(IRP) {}
+template <typename AAType, typename Base,
+ typename StateType = typename AAType::StateType>
+struct AAArgumentFromCallSiteArguments : public Base {
+ AAArgumentFromCallSiteArguments(const IRPosition &IRP) : Base(IRP) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
@@ -603,9 +595,9 @@ struct AAArgumentFromCallSiteArguments : public AAType {
};
/// Helper class for generic replication: function returned -> cs returned.
-template <typename AAType>
-struct AACallSiteReturnedFromReturned : public AAType {
- AACallSiteReturnedFromReturned(const IRPosition &IRP) : AAType(IRP) {}
+template <typename AAType, typename Base>
+struct AACallSiteReturnedFromReturned : public Base {
+ AACallSiteReturnedFromReturned(const IRPosition &IRP) : Base(IRP) {}
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
@@ -621,13 +613,9 @@ struct AACallSiteReturnedFromReturned : public AAType {
return S.indicatePessimisticFixpoint();
IRPosition FnPos = IRPosition::returned(*AssociatedFunction);
- // TODO: We should create abstract attributes on-demand, patches are already
- // prepared, pending approval.
- const AAType *AA = A.getAAFor<AAType>(*this, FnPos);
- if (!AA)
- return S.indicatePessimisticFixpoint();
+ const AAType &AA = A.getAAFor<AAType>(*this, FnPos);
return clampStateAndIndicateChange(
- S, static_cast<const typename AAType::StateType &>(AA->getState()));
+ S, static_cast<const typename AAType::StateType &>(AA.getState()));
}
};
@@ -657,8 +645,12 @@ struct AANoUnwindImpl : AANoUnwind {
if (!I.mayThrow())
return true;
- auto *NoUnwindAA = A.getAAFor<AANoUnwind>(*this, IRPosition::value(I));
- return NoUnwindAA && NoUnwindAA->isAssumedNoUnwind();
+ if (ImmutableCallSite ICS = ImmutableCallSite(&I)) {
+ const auto &NoUnwindAA =
+ A.getAAFor<AANoUnwind>(*this, IRPosition::callsite_function(ICS));
+ return NoUnwindAA.isAssumedNoUnwind();
+ }
+ return false;
};
if (!A.checkForAllInstructions(CheckForNoUnwind, *this, Opcodes))
@@ -940,23 +932,21 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) {
if (!CB || UnresolvedCalls.count(CB))
continue;
- const auto *RetValAAPtr =
+ const auto &RetValAA =
A.getAAFor<AAReturnedValues>(*this, IRPosition::callsite_function(*CB));
+ LLVM_DEBUG(dbgs() << "[AAReturnedValues] Found another AAReturnedValues: "
+ << static_cast<const AbstractAttribute &>(RetValAA)
+ << "\n");
// Skip dead ends, thus if we do not know anything about the returned
// call we mark it as unresolved and it will stay that way.
- if (!RetValAAPtr || !RetValAAPtr->getState().isValidState()) {
+ if (!RetValAA.getState().isValidState()) {
LLVM_DEBUG(dbgs() << "[AAReturnedValues] Unresolved call: " << *CB
<< "\n");
UnresolvedCalls.insert(CB);
continue;
}
- const auto &RetValAA = *RetValAAPtr;
- LLVM_DEBUG(dbgs() << "[AAReturnedValues] Found another AAReturnedValues: "
- << static_cast<const AbstractAttribute &>(RetValAA)
- << "\n");
-
// Do not try to learn partial information. If the callee has unresolved
// return values we will treat the call as unresolved/opaque.
auto &RetValAAUnresolvedCalls = RetValAA.getUnresolvedCalls();
@@ -1167,9 +1157,9 @@ ChangeStatus AANoSyncImpl::updateImpl(Attributor &A) {
if (ICS.hasFnAttr(Attribute::NoSync))
return true;
- auto *NoSyncAA =
- A.getAAFor<AANoSyncImpl>(*this, IRPosition::callsite_function(ICS));
- if (NoSyncAA && NoSyncAA->isAssumedNoSync())
+ const auto &NoSyncAA =
+ A.getAAFor<AANoSync>(*this, IRPosition::callsite_function(ICS));
+ if (NoSyncAA.isAssumedNoSync())
return true;
return false;
}
@@ -1225,9 +1215,9 @@ struct AANoFreeImpl : public AANoFree {
if (ICS.hasFnAttr(Attribute::NoFree))
return true;
- auto *NoFreeAA =
- A.getAAFor<AANoFreeImpl>(*this, IRPosition::callsite_function(ICS));
- return NoFreeAA && NoFreeAA->isAssumedNoFree();
+ const auto &NoFreeAA =
+ A.getAAFor<AANoFree>(*this, IRPosition::callsite_function(ICS));
+ return NoFreeAA.isAssumedNoFree();
};
if (!A.checkForAllCallLikeInstructions(CheckForNoFree, *this))
@@ -1295,19 +1285,17 @@ struct AANonNullFloating : AANonNullImpl {
auto VisitValueCB = [&](Value &V, AAAlign::StateType &T,
bool Stripped) -> bool {
- if (isKnownNonZero(&V, DL, 0, /* TODO: AC */ nullptr,
+ const auto &AA = A.getAAFor<AANonNull>(*this, IRPosition::value(V));
+ if (!Stripped && this == &AA) {
+ if (!isKnownNonZero(&V, DL, 0, /* TODO: AC */ nullptr,
/* TODO: CtxI */ nullptr,
- /* TODO: DT */ nullptr)) {
- // Known non-zero, all good.
- } else if (const auto *AA =
- A.getAAFor<AANonNull>(*this, IRPosition::value(V))) {
- // Try to use abstract attribute information.
- if (!AA->isAssumedNonNull())
+ /* TODO: DT */ nullptr))
T.indicatePessimisticFixpoint();
} else {
- // IR information was not sufficient and we did not find an abstract
- // attribute to use. TODO: on-demand attribute creation!
- T.indicatePessimisticFixpoint();
+ // Use abstract attribute information.
+ const AANonNull::StateType &NS =
+ static_cast<const AANonNull::StateType &>(AA.getState());
+ T ^= NS;
}
return T.isValidState();
};
@@ -1325,9 +1313,10 @@ struct AANonNullFloating : AANonNullImpl {
};
/// NonNull attribute for function return value.
-struct AANonNullReturned final : AAReturnedFromReturnedValues<AANonNullImpl> {
+struct AANonNullReturned final
+ : AAReturnedFromReturnedValues<AANonNull, AANonNullImpl> {
AANonNullReturned(const IRPosition &IRP)
- : AAReturnedFromReturnedValues<AANonNullImpl>(IRP) {}
+ : AAReturnedFromReturnedValues<AANonNull, AANonNullImpl>(IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(nonnull) }
@@ -1335,9 +1324,9 @@ struct AANonNullReturned final : AAReturnedFromReturnedValues<AANonNullImpl> {
/// NonNull attribute for function argument.
struct AANonNullArgument final
- : AAArgumentFromCallSiteArguments<AANonNullImpl> {
+ : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {
AANonNullArgument(const IRPosition &IRP)
- : AAArgumentFromCallSiteArguments<AANonNullImpl>(IRP) {}
+ : AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nonnull) }
@@ -1352,9 +1341,9 @@ struct AANonNullCallSiteArgument final : AANonNullFloating {
/// NonNull attribute for a call site return position.
struct AANonNullCallSiteReturned final
- : AACallSiteReturnedFromReturned<AANonNullImpl> {
+ : AACallSiteReturnedFromReturned<AANonNull, AANonNullImpl> {
AANonNullCallSiteReturned(const IRPosition &IRP)
- : AACallSiteReturnedFromReturned<AANonNullImpl>(IRP) {}
+ : AACallSiteReturnedFromReturned<AANonNull, AANonNullImpl>(IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(nonnull) }
@@ -1437,21 +1426,14 @@ struct AAWillReturnImpl : public AAWillReturn {
/// See AbstractAttribute::updateImpl(...).
ChangeStatus updateImpl(Attributor &A) override {
auto CheckForWillReturn = [&](Instruction &I) {
- ImmutableCallSite ICS(&I);
- if (ICS.hasFnAttr(Attribute::WillReturn))
+ IRPosition IPos = IRPosition::callsite_function(ImmutableCallSite(&I));
+ const auto &WillReturnAA = A.getAAFor<AAWillReturn>(*this, IPos);
+ if (WillReturnAA.isKnownWillReturn())
return true;
-
- IRPosition IPos = IRPosition::callsite_function(ICS);
- auto *WillReturnAA = A.getAAFor<AAWillReturn>(*this, IPos);
- if (!WillReturnAA || !WillReturnAA->isAssumedWillReturn())
+ if (!WillReturnAA.isAssumedWillReturn())
return false;
-
- // FIXME: Prohibit any recursion for now.
- if (ICS.hasFnAttr(Attribute::NoRecurse))
- return true;
-
- auto *NoRecurseAA = A.getAAFor<AANoRecurse>(*this, IPos);
- return NoRecurseAA && NoRecurseAA->isAssumedNoRecurse();
+ const auto &NoRecurseAA = A.getAAFor<AANoRecurse>(*this, IPos);
+ return NoRecurseAA.isAssumedNoRecurse();
};
if (!A.checkForAllCallLikeInstructions(CheckForWillReturn, *this))
@@ -1553,12 +1535,10 @@ struct AANoAliasReturned final : AANoAliasImpl {
if (!ICS)
return false;
- if (!ICS.returnDoesNotAlias()) {
- auto *NoAliasAA =
- A.getAAFor<AANoAlias>(*this, IRPosition::callsite_returned(ICS));
- if (!NoAliasAA || !NoAliasAA->isAssumedNoAlias())
- return false;
- }
+ const auto &NoAliasAA =
+ A.getAAFor<AANoAlias>(*this, IRPosition::callsite_returned(ICS));
+ if (!NoAliasAA.isAssumedNoAlias())
+ return false;
/// FIXME: We can improve capture check in two ways:
/// 1. Use the AANoCapture facilities.
@@ -1649,10 +1629,9 @@ 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, IRPosition::function(*Callee));
- if (Callee->hasFnAttribute(Attribute::NoUnwind) ||
- (AANoUnw && AANoUnw->isAssumedNoUnwind())) {
+ const IRPosition &IPos = IRPosition::callsite_function(*II);
+ const auto &AANoUnw = A.getAAFor<AANoUnwind>(*this, IPos);
+ if (AANoUnw.isAssumedNoUnwind()) {
LLVM_DEBUG(dbgs()
<< "[AAIsDead] Replace invoke with call inst\n");
// We do not need an invoke (II) but instead want a call followed
@@ -1791,17 +1770,15 @@ const Instruction *AAIsDeadImpl::findNextNoReturn(Attributor &A,
// 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, IPos);
- if (!Invoke2CallAllowed ||
- (!AANoUnw || !AANoUnw->isAssumedNoUnwind())) {
+ const auto &AANoUnw = A.getAAFor<AANoUnwind>(*this, IPos);
+ if (!Invoke2CallAllowed || !AANoUnw.isAssumedNoUnwind()) {
AssumedLiveBlocks.insert(Invoke->getUnwindDest());
ToBeExploredPaths.insert(&Invoke->getUnwindDest()->front());
}
}
- auto *NoReturnAA = A.getAAFor<AANoReturn>(*this, IPos);
- if (ICS.hasFnAttr(Attribute::NoReturn) ||
- (NoReturnAA && NoReturnAA->isAssumedNoReturn()))
+ const auto &NoReturnAA = A.getAAFor<AANoReturn>(*this, IPos);
+ if (NoReturnAA.isAssumedNoReturn())
return I;
}
@@ -1967,7 +1944,7 @@ struct AADereferenceableImpl : AADereferenceable, DerefState {
for (const Attribute &Attr : Attrs)
takeKnownDerefBytesMaximum(Attr.getValueAsInt());
- NonNullAA = A.getAAFor<AANonNull>(*this, getIRPosition());
+ NonNullAA = &A.getAAFor<AANonNull>(*this, getIRPosition());
}
/// See AbstractAttribute::getState()
@@ -2038,18 +2015,17 @@ struct AADereferenceableFloating : AADereferenceableImpl {
const Value *Base =
V.stripAndAccumulateInBoundsConstantOffsets(DL, Offset);
- const auto *AA =
- A.getAAFor<AADereferenceable>(*this, IRPosition::value(*Base));
+ const auto &AA =
+ A.getAAFor<AADereferenceable>(*this, IRPosition::value(*Base));
int64_t DerefBytes = 0;
- if (!AA || (!Stripped &&
- getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT)) {
+ if (!Stripped && this == &AA) {
// Use IR information if we did not strip anything.
// TODO: track globally.
bool CanBeNull;
DerefBytes = Base->getPointerDereferenceableBytes(DL, CanBeNull);
T.GlobalState.indicatePessimisticFixpoint();
} else {
- const DerefState &DS = static_cast<const DerefState &>(AA->getState());
+ const DerefState &DS = static_cast<const DerefState &>(AA.getState());
DerefBytes = DS.DerefBytesState.getAssumed();
T.GlobalState &= DS.GlobalState;
}
@@ -2057,8 +2033,7 @@ struct AADereferenceableFloating : AADereferenceableImpl {
T.takeAssumedDerefBytesMinimum(
std::max(int64_t(0), DerefBytes - Offset.getSExtValue()));
- if (!Stripped &&
- getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT) {
+ if (!Stripped && this == &AA) {
T.takeKnownDerefBytesMaximum(
std::max(int64_t(0), DerefBytes - Offset.getSExtValue()));
T.indicatePessimisticFixpoint();
@@ -2083,9 +2058,11 @@ struct AADereferenceableFloating : AADereferenceableImpl {
/// Dereferenceable attribute for a return value.
struct AADereferenceableReturned final
- : AAReturnedFromReturnedValues<AADereferenceableImpl> {
+ : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl,
+ DerefState> {
AADereferenceableReturned(const IRPosition &IRP)
- : AAReturnedFromReturnedValues<AADereferenceableImpl>(IRP) {}
+ : AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl,
+ DerefState>(IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override {
@@ -2095,9 +2072,12 @@ struct AADereferenceableReturned final
/// Dereferenceable attribute for an argument
struct AADereferenceableArgument final
- : AAArgumentFromCallSiteArguments<AADereferenceableImpl> {
+ : AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl,
+ DerefState> {
AADereferenceableArgument(const IRPosition &IRP)
- : AAArgumentFromCallSiteArguments<AADereferenceableImpl>(IRP) {}
+ : AAArgumentFromCallSiteArguments<AADereferenceable,
+ AADereferenceableImpl, DerefState>(
+ IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override{
@@ -2163,21 +2143,16 @@ struct AAAlignFloating : AAAlignImpl {
auto VisitValueCB = [&](Value &V, AAAlign::StateType &T,
bool Stripped) -> bool {
- if (!Stripped &&
- getIRPosition().getPositionKind() == IRPosition::IRP_FLOAT) {
+ const auto &AA = A.getAAFor<AAAlign>(*this, IRPosition::value(V));
+ if (!Stripped && this == &AA) {
// Use only IR information if we did not strip anything.
T.takeKnownMaximum(V.getPointerAlignment(DL));
T.indicatePessimisticFixpoint();
- } else if (const auto *AA =
- A.getAAFor<AAAlign>(*this, IRPosition::value(V))) {
- // Try to use abstract attribute information.
- const AAAlign::StateType &DS =
- static_cast<const AAAlign::StateType &>(AA->getState());
- T.takeAssumedMinimum(DS.getAssumed());
} else {
- // Last resort, look into the IR.
- T.takeKnownMaximum(V.getPointerAlignment(DL));
- T.indicatePessimisticFixpoint();
+ // Use abstract attribute information.
+ const AAAlign::StateType &DS =
+ static_cast<const AAAlign::StateType &>(AA.getState());
+ T ^= DS;
}
return T.isValidState();
};
@@ -2197,18 +2172,20 @@ struct AAAlignFloating : AAAlignImpl {
};
/// Align attribute for function return value.
-struct AAAlignReturned final : AAReturnedFromReturnedValues<AAAlignImpl> {
+struct AAAlignReturned final
+ : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {
AAAlignReturned(const IRPosition &IRP)
- : AAReturnedFromReturnedValues<AAAlignImpl>(IRP) {}
+ : AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>(IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(aligned) }
};
/// Align attribute for function argument.
-struct AAAlignArgument final : AAArgumentFromCallSiteArguments<AAAlignImpl> {
+struct AAAlignArgument final
+ : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {
AAAlignArgument(const IRPosition &IRP)
- : AAArgumentFromCallSiteArguments<AAAlignImpl>(IRP) {}
+ : AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>(IRP) {}
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(aligned) }
@@ -2271,8 +2248,8 @@ bool Attributor::isAssumedDead(const AbstractAttribute &AA,
if (!LivenessAA)
LivenessAA =
- getAAFor<AAIsDead>(AA, IRPosition::function(*CtxI->getFunction()));
- if (!LivenessAA || !LivenessAA->isAssumedDead(CtxI))
+ &getAAFor<AAIsDead>(AA, IRPosition::function(*CtxI->getFunction()));
+ if (!LivenessAA->isAssumedDead(CtxI))
return false;
// TODO: Do not track dependences automatically but add it here as only a
@@ -2303,11 +2280,11 @@ bool Attributor::checkForAllCallSites(const function_ref<bool(CallSite)> &Pred,
Instruction *I = cast<Instruction>(U.getUser());
Function *Caller = I->getFunction();
- auto *LivenessAA =
+ const auto &LivenessAA =
getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*Caller));
// Skip dead calls.
- if (LivenessAA && LivenessAA->isAssumedDead(I))
+ if (LivenessAA.isAssumedDead(I))
continue;
CallSite CS(U.getUser());
@@ -2348,10 +2325,10 @@ bool Attributor::checkForAllReturnedValuesAndReturnInsts(
// and liveness information.
const IRPosition &QueryIRP = IRPosition::function_scope(IRP);
const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP);
- if (!AARetVal || !AARetVal->getState().isValidState())
+ if (!AARetVal.getState().isValidState())
return false;
- return AARetVal->checkForAllReturnedValuesAndReturnInsts(Pred);
+ return AARetVal.checkForAllReturnedValuesAndReturnInsts(Pred);
}
bool Attributor::checkForAllReturnedValues(
@@ -2365,10 +2342,10 @@ bool Attributor::checkForAllReturnedValues(
const IRPosition &QueryIRP = IRPosition::function_scope(IRP);
const auto &AARetVal = getAAFor<AAReturnedValues>(QueryingAA, QueryIRP);
- if (!AARetVal || !AARetVal->getState().isValidState())
+ if (!AARetVal.getState().isValidState())
return false;
- return AARetVal->checkForAllReturnedValuesAndReturnInsts(
+ return AARetVal.checkForAllReturnedValuesAndReturnInsts(
[&](Value &RV, const SmallPtrSetImpl<ReturnInst *> &) {
return Pred(RV);
});
@@ -2392,7 +2369,7 @@ bool Attributor::checkForAllInstructions(
for (unsigned Opcode : Opcodes) {
for (Instruction *I : OpcodeInstMap[Opcode]) {
// Skip dead instructions.
- if (LivenessAA && LivenessAA->isAssumedDead(I))
+ if (LivenessAA.isAssumedDead(I))
continue;
if (!Pred(*I))
@@ -2418,7 +2395,7 @@ bool Attributor::checkForAllReadWriteInstructions(
for (Instruction *I :
InfoCache.getReadOrWriteInstsForFunction(*AssociatedFunction)) {
// Skip dead instructions.
- if (LivenessAA && LivenessAA->isAssumedDead(I))
+ if (LivenessAA.isAssumedDead(I))
continue;
if (!Pred(*I))
@@ -2429,9 +2406,9 @@ bool Attributor::checkForAllReadWriteInstructions(
}
ChangeStatus Attributor::run() {
- // Initialize all abstract attributes.
- for (AbstractAttribute *AA : AllAbstractAttributes)
- AA->initialize(*this);
+ // Initialize all abstract attributes, allow new ones to be created.
+ for (unsigned u = 0; u < AllAbstractAttributes.size(); u++)
+ AllAbstractAttributes[u]->initialize(*this);
LLVM_DEBUG(dbgs() << "[Attributor] Identified and initialized "
<< AllAbstractAttributes.size()
@@ -2447,6 +2424,8 @@ ChangeStatus Attributor::run() {
Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end());
do {
+ // Remember the size to determine new attributes.
+ size_t NumAAs = AllAbstractAttributes.size();
LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter
<< ", Worklist size: " << Worklist.size() << "\n");
@@ -2472,8 +2451,15 @@ ChangeStatus Attributor::run() {
Worklist.clear();
Worklist.insert(ChangedAAs.begin(), ChangedAAs.end());
+ // Add attributes to the worklist that have been created in the last
+ // iteration.
+ Worklist.insert(AllAbstractAttributes.begin() + NumAAs,
+ AllAbstractAttributes.end());
+
} while (!Worklist.empty() && ++IterationCounter < MaxFixpointIterations);
+ size_t NumFinalAAs = AllAbstractAttributes.size();
+
LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: "
<< IterationCounter << "/" << MaxFixpointIterations
<< " iterations\n");
@@ -2566,6 +2552,9 @@ ChangeStatus Attributor::run() {
NumAttributesManifested += NumManifested;
NumAttributesValidFixpoint += NumAtFixpoint;
+ assert(
+ NumFinalAAs == AllAbstractAttributes.size() &&
+ "Expected the final number of abstract attributes to remain unchanged!");
return ManifestChange;
}
@@ -2578,8 +2567,8 @@ ChangeStatus Attributor::run() {
///
/// \returns The created abstract argument, or nullptr if none was created.
template <typename AAType>
-static AAType *checkAndRegisterAA(const IRPosition &IRP, Attributor &A,
- DenseSet<const char *> *Whitelist) {
+static const AAType *checkAndRegisterAA(const IRPosition &IRP, Attributor &A,
+ DenseSet<const char *> *Whitelist) {
if (Whitelist && !Whitelist->count(&AAType::ID))
return nullptr;
@@ -2853,6 +2842,71 @@ const char AAIsDead::ID = 0;
const char AADereferenceable::ID = 0;
const char AAAlign::ID = 0;
+// Macro magic to create the static generator function for attributes that
+// follow the naming scheme.
+
+#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \
+ case IRPosition::PK: \
+ llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");
+
+#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \
+ case IRPosition::PK: \
+ AA = new CLASS##SUFFIX(IRP); \
+ break;
+
+#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
+ CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
+ CLASS *AA = nullptr; \
+ switch (IRP.getPositionKind()) { \
+ SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
+ SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \
+ SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \
+ SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \
+ SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \
+ SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \
+ SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \
+ SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \
+ } \
+ AA->initialize(A); \
+ return *AA; \
+ }
+
+#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \
+ CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \
+ CLASS *AA = nullptr; \
+ switch (IRP.getPositionKind()) { \
+ SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \
+ SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \
+ SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \
+ SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \
+ SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \
+ SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \
+ SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \
+ SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \
+ } \
+ AA->initialize(A); \
+ return *AA; \
+ }
+
+CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUnwind)
+CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoSync)
+CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree)
+CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoRecurse)
+CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAWillReturn)
+CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoReturn)
+CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead)
+CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReturnedValues)
+
+CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANonNull)
+CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoAlias)
+CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AADereferenceable)
+CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAlign)
+
+#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION
+#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION
+#undef SWITCH_PK_CREATE
+#undef SWITCH_PK_INV
+
INITIALIZE_PASS_BEGIN(AttributorLegacyPass, "attributor",
"Deduce and propagate attributes", false, false)
INITIALIZE_PASS_END(AttributorLegacyPass, "attributor",
diff --git a/llvm/test/Transforms/FunctionAttrs/align.ll b/llvm/test/Transforms/FunctionAttrs/align.ll
index cac92ef1199..720058fa0b9 100644
--- a/llvm/test/Transforms/FunctionAttrs/align.ll
+++ b/llvm/test/Transforms/FunctionAttrs/align.ll
@@ -37,19 +37,13 @@ declare i32* @unknown()
declare align 8 i32* @align8()
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; alignment for the return value here.
-; define align 8 i32* @test5_1()
-; ATTRIBUTOR: define i32* @test5_1()
+; ATTRIBUTOR: define align 8 i32* @test5_1()
define i32* @test5_1() {
%ret = tail call align 8 i32* @unknown()
ret i32* %ret
}
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; alignment for the return value here.
-; define align 8 i32* @test5_2()
-; ATTRIBUTOR: define i32* @test5_2()
+; ATTRIBUTOR: define align 8 i32* @test5_2()
define i32* @test5_2() {
%ret = tail call i32* @align8()
ret i32* %ret
@@ -89,10 +83,7 @@ define i32* @test6_2() #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 {
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; alignment for the return value here.
-; define internal nonnull align 8 i8* @f1(i8* nonnull readnone align 8 %0)
-; ATTRIBUTOR: define internal i8* @f1(i8* nonnull readnone align 8 dereferenceable(1) %0)
+; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f1(i8* nonnull readnone align 8 dereferenceable(1) %0)
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
@@ -108,10 +99,7 @@ define internal i8* @f1(i8* readnone %0) local_unnamed_addr #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; alignment for the return value here.
-; define internal nonnull align 8 i8* @f2(i8* nonnull readnone align 8 %0)
-; ATTRIBUTOR: define internal i8* @f2(i8* nonnull readnone align 8 dereferenceable(1) %0)
+; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f2(i8* nonnull readnone align 8 dereferenceable(1) %0)
%2 = icmp eq i8* %0, null
br i1 %2, label %5, label %3
@@ -133,10 +121,7 @@ define internal i8* @f2(i8* readnone %0) local_unnamed_addr #0 {
; Function Attrs: nounwind readnone ssp uwtable
define internal i8* @f3(i8* readnone %0) local_unnamed_addr #0 {
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; alignment for the return value here.
-; define internal nonnull align 8 i8* @f3(i8* nonnull readnone align 16 %0)
-; ATTRIBUTOR: define internal i8* @f3(i8* nonnull readnone align 16 dereferenceable(1) %0)
+; ATTRIBUTOR: define internal nonnull align 8 dereferenceable(1) i8* @f3(i8* nonnull readnone align 16 dereferenceable(1) %0)
%2 = icmp eq i8* %0, null
br i1 %2, label %3, label %5
diff --git a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
index 76c8a52d094..fac1fe50e7d 100644
--- a/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
+++ b/llvm/test/Transforms/FunctionAttrs/arg_returned.ll
@@ -806,5 +806,8 @@ attributes #0 = { noinline nounwind uwtable }
; BOTH-DAG: attributes #{{[0-9]*}} = { noinline nounwind uwtable }
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind readnone uwtable willreturn }
; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noinline nosync nounwind uwtable willreturn }
+; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync willreturn }
+; BOTH-DAG: attributes #{{[0-9]*}} = { nofree nosync }
+; BOTH-DAG: attributes #{{[0-9]*}} = { nofree noreturn nosync }
; BOTH-DAG: attributes #{{[0-9]*}} = { noreturn }
; BOTH-NOT: attributes #
diff --git a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll
index d0da030243f..a9a2c26498a 100644
--- a/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll
+++ b/llvm/test/Transforms/FunctionAttrs/dereferenceable.ll
@@ -22,23 +22,20 @@ define i32* @test2(i32* dereferenceable_or_null(4) %0, double* dereferenceable(8
; TEST 3
; GEP inbounds
define i32* @test3_1(i32* dereferenceable(8) %0) local_unnamed_addr {
-; define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull dereferenceable(8) %0)
-; ATTRIBUTOR: define i32* @test3_1(i32* nonnull dereferenceable(8) %0)
+; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_1(i32* nonnull dereferenceable(8) %0)
%ret = getelementptr inbounds i32, i32* %0, i64 1
ret i32* %ret
}
define i32* @test3_2(i32* dereferenceable_or_null(32) %0) local_unnamed_addr {
; FIXME: Argument should be mark dereferenceable because of GEP `inbounds`.
-; define nonnull dereferenceable(16) i32* @test3_2(i32* dereferenceable_or_null(32) %0)
-; ATTRIBUTOR: define i32* @test3_2(i32* dereferenceable_or_null(32) %0)
+; ATTRIBUTOR: define nonnull dereferenceable(16) i32* @test3_2(i32* dereferenceable_or_null(32) %0)
%ret = getelementptr inbounds i32, i32* %0, i64 4
ret i32* %ret
}
define i32* @test3_3(i32* dereferenceable(8) %0, i32* dereferenceable(16) %1, i1 %2) local_unnamed_addr {
-; define nonnull dereferenceable(4) i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr
-; ATTRIBUTOR: define i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr
+; ATTRIBUTOR: define nonnull dereferenceable(4) i32* @test3_3(i32* nonnull dereferenceable(8) %0, i32* nonnull dereferenceable(16) %1, i1 %2) local_unnamed_addr
%ret1 = getelementptr inbounds i32, i32* %0, i64 1
%ret2 = getelementptr inbounds i32, i32* %1, i64 2
%ret = select i1 %2, i32* %ret1, i32* %ret2
diff --git a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll
index 72084c18245..2cffec7f2e7 100644
--- a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll
+++ b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll
@@ -79,19 +79,13 @@ declare i8* @baz(...) nounwind uwtable
; TEST 5
; Returning global pointer. Should not be noalias.
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; alignment for the return value here.
-; define nonnull align 8 dereferenceable(8) i8** @getter()
-; CHECK: define i8** @getter()
+; CHECK: define nonnull align 8 dereferenceable(8) i8** @getter()
define i8** @getter() {
ret i8** @G
}
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; alignment for the return value here.
; Returning global pointer. Should not be noalias.
-; define nonnull align 8 dereferenceable(8) i8** @calle1()
-; CHECK: define i8** @calle1()
+; CHECK: define nonnull align 8 dereferenceable(8) i8** @calle1()
define i8** @calle1(){
%1 = call i8** @getter()
ret i8** %1
diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
index aa0788b92a8..5ea37f5bf99 100644
--- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll
@@ -8,18 +8,13 @@ declare nonnull i8* @ret_nonnull()
; Return a pointer trivially nonnull (call return attribute)
define i8* @test1() {
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; return value properties.
-; FNATTR: define nonnull i8* @test1
-; ATTRIBUTOR: define i8* @test1
+; BOTH: define nonnull i8* @test1
%ret = call i8* @ret_nonnull()
ret i8* %ret
}
; Return a pointer trivially nonnull (argument attribute)
define i8* @test2(i8* nonnull %p) {
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; return value properties.
; BOTH: define nonnull i8* @test2
ret i8* %p
}
@@ -38,10 +33,7 @@ end:
}
define i8* @test3(i1 %c) {
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; return value properties.
-; FNATTR: define nonnull i8* @test3
-; ATTRIBUTOR: define i8* @test3
+; BOTH: define nonnull i8* @test3
call i8* @scc_binder(i1 %c)
%ret = call i8* @ret_nonnull()
ret i8* %ret
@@ -87,10 +79,7 @@ define i8* @test5(i1 %c) {
; Local analysis, but going through a self recursive phi
define i8* @test6() {
entry:
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; return value properties.
-; FNATTR: define nonnull i8* @test6
-; ATTRIBUTOR: define i8* @test6
+; BOTH: define nonnull i8* @test6
%ret = call i8* @ret_nonnull()
br label %loop
loop:
@@ -106,10 +95,7 @@ define i8* @test7(i8* %a) {
ret i8* %b
}
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; return value properties.
-; FNATTR: define nonnull i8* @test8
-; ATTRIBUTOR: define i8* @test8
+; BOTH: define nonnull i8* @test8
define i8* @test8(i8* %a) {
%b = getelementptr inbounds i8, i8* %a, i64 1
ret i8* %b
@@ -193,7 +179,7 @@ declare nonnull i8* @nonnull()
define internal i32* @f1(i32* %arg) {
; FIXME: missing nonnull It should be nonnull @f1(i32* nonnull %arg)
-; ATTRIBUTOR: define internal i32* @f1(i32* %arg)
+; ATTRIBUTOR: define internal nonnull i32* @f1(i32* %arg)
bb:
%tmp = icmp eq i32* %arg, null
@@ -212,7 +198,7 @@ bb4: ; preds = %bb1
bb6: ; preds = %bb1
; FIXME: missing nonnull. It should be @f2(i32* nonnull %arg)
-; ATTRIBUTOR: %tmp7 = tail call i32* @f2(i32* %arg)
+; ATTRIBUTOR: %tmp7 = tail call nonnull i32* @f2(i32* %arg)
%tmp7 = tail call i32* @f2(i32* %arg)
ret i32* %tmp7
@@ -223,11 +209,11 @@ bb9: ; preds = %bb4, %bb
define internal i32* @f2(i32* %arg) {
; FIXME: missing nonnull. It should be nonnull @f2(i32* nonnull %arg)
-; ATTRIBUTOR: define internal i32* @f2(i32* %arg)
+; ATTRIBUTOR: define internal nonnull i32* @f2(i32* %arg)
bb:
; FIXME: missing nonnull. It should be @f1(i32* nonnull %arg)
-; ATTRIBUTOR: %tmp = tail call i32* @f1(i32* %arg)
+; ATTRIBUTOR: %tmp = tail call nonnull i32* @f1(i32* %arg)
%tmp = tail call i32* @f1(i32* %arg)
ret i32* %tmp
}
@@ -443,10 +429,7 @@ exc:
unreachable
}
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; return value properties.
-; FNATTR: define nonnull i32* @gep1(
-; ATTRIBUTOR: define i32* @gep1(
+; BOTH: define nonnull i32* @gep1(
define i32* @gep1(i32* %p) {
%q = getelementptr inbounds i32, i32* %p, i32 1
ret i32* %q
@@ -465,10 +448,7 @@ define i32 addrspace(3)* @gep2(i32 addrspace(3)* %p) {
ret i32 addrspace(3)* %q
}
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; return value properties.
-; FNATTR: define internal nonnull i32* @g2()
-; ATTRIBUTOR: define internal i32* @g2()
+; BOTH: define internal nonnull i32* @g2()
define internal i32* @g2() {
ret i32* inttoptr (i64 4 to i32*)
}
diff --git a/llvm/test/Transforms/FunctionAttrs/nosync.ll b/llvm/test/Transforms/FunctionAttrs/nosync.ll
index 2b6706f3cdc..c86facb8192 100644
--- a/llvm/test/Transforms/FunctionAttrs/nosync.ll
+++ b/llvm/test/Transforms/FunctionAttrs/nosync.ll
@@ -27,11 +27,8 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
; FNATTR: Function Attrs: norecurse nounwind optsize readnone ssp uwtable
; FNATTR-NEXT: define nonnull i32* @foo(%struct.ST* readnone %s)
-; FIXME: Until we have "on-demand" attribute generation we do not determine the
-; return value properties.
; ATTRIBUTOR: Function Attrs: nofree nosync nounwind optsize readnone ssp uwtable
-; define nonnull i32* @foo(%struct.ST* %s)
-; ATTRIBUTOR-NEXT: define i32* @foo(%struct.ST* %s)
+; ATTRIBUTOR-NEXT: define nonnull i32* @foo(%struct.ST* %s)
define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp {
entry:
%arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13
diff --git a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll b/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll
index 4f4f4ee7884..65798d5c793 100644
--- a/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll
+++ b/llvm/test/Transforms/FunctionAttrs/read_write_returned_arguments_scc.ll
@@ -161,4 +161,5 @@ entry:
; CHECK-NOT: attributes #
; CHECK: attributes #{{.*}} = { nofree nosync nounwind }
; CHECK: attributes #{{.*}} = { nofree norecurse nosync nounwind }
+; CHECK: attributes #{{.*}} = { nosync }
; CHECK-NOT: attributes #
OpenPOWER on IntegriCloud