summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Doerfert <johannes@jdoerfert.de>2022-02-16 11:05:09 -0600
committerTom Stellard <tstellar@redhat.com>2022-03-01 14:13:33 -0800
commitf58ab32850211621d5986da2d687be0d550e7140 (patch)
tree35f9d37c9fdefbdf43d98dc55c98f794e0d02df9
parent4327d39b15b22b9ee23582e5455df5b2a093fe8d (diff)
[Attributor][FIX] Pipe UsedAssumedInformation through more interfaces
`UsedAssumedInformation` is a return argument utilized to determine what information is known. Most APIs used it already but `genericValueTraversal` did not. This adds it to `genericValueTraversal` and replaces `AllCallSitesKnown` of `checkForAllCallSites` with the commonly used `UsedAssumedInformation`. This was supposed to be a NFC commit, then the test change appeared. Turns out, we had one user of `AllCallSitesKnown` (AANoReturn) and the way we set `AllCallSitesKnown` was wrong as we ignored the fact some call sites were optimistically assumed dead. Included a dedicated test for this as well now. Fixes https://github.com/llvm/llvm-project/issues/53884
-rw-r--r--llvm/include/llvm/Transforms/IPO/Attributor.h14
-rw-r--r--llvm/lib/Transforms/IPO/Attributor.cpp32
-rw-r--r--llvm/lib/Transforms/IPO/AttributorAttributes.cpp91
-rw-r--r--llvm/test/Transforms/Attributor/norecurse.ll50
-rw-r--r--llvm/test/Transforms/OpenMP/custom_state_machines.ll40
5 files changed, 143 insertions, 84 deletions
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 7eee16f71d64..8677a0ba62f2 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -192,6 +192,7 @@ bool getAssumedUnderlyingObjects(Attributor &A, const Value &Ptr,
SmallVectorImpl<Value *> &Objects,
const AbstractAttribute &QueryingAA,
const Instruction *CtxI,
+ bool &UsedAssumedInformation,
bool Intraprocedural = false);
/// Collect all potential values of the one stored by \p SI into
@@ -1824,23 +1825,24 @@ public:
/// This method will evaluate \p Pred on call sites and return
/// true if \p Pred holds in every call sites. However, this is only possible
/// all call sites are known, hence the function has internal linkage.
- /// If true is returned, \p AllCallSitesKnown is set if all possible call
- /// sites of the function have been visited.
+ /// If true is returned, \p UsedAssumedInformation is set if assumed
+ /// information was used to skip or simplify potential call sites.
bool checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
const AbstractAttribute &QueryingAA,
- bool RequireAllCallSites, bool &AllCallSitesKnown);
+ bool RequireAllCallSites,
+ bool &UsedAssumedInformation);
/// Check \p Pred on all call sites of \p Fn.
///
/// This method will evaluate \p Pred on call sites and return
/// true if \p Pred holds in every call sites. However, this is only possible
/// all call sites are known, hence the function has internal linkage.
- /// If true is returned, \p AllCallSitesKnown is set if all possible call
- /// sites of the function have been visited.
+ /// If true is returned, \p UsedAssumedInformation is set if assumed
+ /// information was used to skip or simplify potential call sites.
bool checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
const Function &Fn, bool RequireAllCallSites,
const AbstractAttribute *QueryingAA,
- bool &AllCallSitesKnown);
+ bool &UsedAssumedInformation);
/// Check \p Pred on all values potentially returned by \p F.
///
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index d66140a726f6..7bca2084c448 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -320,7 +320,8 @@ bool AA::getPotentialCopiesOfStoredValue(
Value &Ptr = *SI.getPointerOperand();
SmallVector<Value *, 8> Objects;
- if (!AA::getAssumedUnderlyingObjects(A, Ptr, Objects, QueryingAA, &SI)) {
+ if (!AA::getAssumedUnderlyingObjects(A, Ptr, Objects, QueryingAA, &SI,
+ UsedAssumedInformation)) {
LLVM_DEBUG(
dbgs() << "Underlying objects stored into could not be determined\n";);
return false;
@@ -514,10 +515,10 @@ isPotentiallyReachable(Attributor &A, const Instruction &FromI,
return true;
};
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
Result = !A.checkForAllCallSites(CheckCallSite, *FromFn,
/* RequireAllCallSites */ true,
- &QueryingAA, AllCallSitesKnown);
+ &QueryingAA, UsedAssumedInformation);
if (Result) {
LLVM_DEBUG(dbgs() << "[AA] stepping back to call sites from " << *CurFromI
<< " in @" << FromFn->getName()
@@ -1277,7 +1278,7 @@ bool Attributor::checkForAllUses(
bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
const AbstractAttribute &QueryingAA,
bool RequireAllCallSites,
- bool &AllCallSitesKnown) {
+ bool &UsedAssumedInformation) {
// 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.
@@ -1286,31 +1287,26 @@ bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
if (!AssociatedFunction) {
LLVM_DEBUG(dbgs() << "[Attributor] No function associated with " << IRP
<< "\n");
- AllCallSitesKnown = false;
return false;
}
return checkForAllCallSites(Pred, *AssociatedFunction, RequireAllCallSites,
- &QueryingAA, AllCallSitesKnown);
+ &QueryingAA, UsedAssumedInformation);
}
bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
const Function &Fn,
bool RequireAllCallSites,
const AbstractAttribute *QueryingAA,
- bool &AllCallSitesKnown) {
+ bool &UsedAssumedInformation) {
if (RequireAllCallSites && !Fn.hasLocalLinkage()) {
LLVM_DEBUG(
dbgs()
<< "[Attributor] Function " << Fn.getName()
<< " has no internal linkage, hence not all call sites are known\n");
- AllCallSitesKnown = false;
return false;
}
- // If we do not require all call sites we might not see all.
- AllCallSitesKnown = RequireAllCallSites;
-
SmallVector<const Use *, 8> Uses(make_pointer_range(Fn.uses()));
for (unsigned u = 0; u < Uses.size(); ++u) {
const Use &U = *Uses[u];
@@ -1322,7 +1318,6 @@ bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
dbgs() << "[Attributor] Check use: " << *U << " in " << *U.getUser()
<< "\n";
});
- bool UsedAssumedInformation = false;
if (isAssumedDead(U, QueryingAA, nullptr, UsedAssumedInformation,
/* CheckBBLivenessOnly */ true)) {
LLVM_DEBUG(dbgs() << "[Attributor] Dead use, skip!\n");
@@ -1795,7 +1790,7 @@ void Attributor::identifyDeadInternalFunctions() {
if (!F)
continue;
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
if (checkForAllCallSites(
[&](AbstractCallSite ACS) {
Function *Callee = ACS.getInstruction()->getFunction();
@@ -1803,7 +1798,7 @@ void Attributor::identifyDeadInternalFunctions() {
(Functions.count(Callee) && Callee->hasLocalLinkage() &&
!LiveInternalFns.count(Callee));
},
- *F, true, nullptr, AllCallSitesKnown)) {
+ *F, true, nullptr, UsedAssumedInformation)) {
continue;
}
@@ -2290,9 +2285,9 @@ bool Attributor::isValidFunctionSignatureRewrite(
}
// Avoid callbacks for now.
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
if (!checkForAllCallSites(CallSiteCanBeChanged, *Fn, true, nullptr,
- AllCallSitesKnown)) {
+ UsedAssumedInformation)) {
LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite all call sites\n");
return false;
}
@@ -2305,7 +2300,6 @@ bool Attributor::isValidFunctionSignatureRewrite(
// Forbid must-tail calls for now.
// TODO:
- bool UsedAssumedInformation = false;
auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(*Fn);
if (!checkForAllInstructionsImpl(nullptr, OpcodeInstMap, InstPred, nullptr,
nullptr, {Instruction::Call},
@@ -2514,9 +2508,9 @@ ChangeStatus Attributor::rewriteFunctionSignatures(
};
// Use the CallSiteReplacementCreator to create replacement call sites.
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
bool Success = checkForAllCallSites(CallSiteReplacementCreator, *OldFn,
- true, nullptr, AllCallSitesKnown);
+ true, nullptr, UsedAssumedInformation);
(void)Success;
assert(Success && "Assumed call site replacement to succeed!");
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 6dadfebae038..5593a297d2d8 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -261,7 +261,8 @@ static bool genericValueTraversal(
StateTy &State,
function_ref<bool(Value &, const Instruction *, StateTy &, bool)>
VisitValueCB,
- const Instruction *CtxI, bool UseValueSimplify = true, int MaxValues = 16,
+ const Instruction *CtxI, bool &UsedAssumedInformation,
+ bool UseValueSimplify = true, int MaxValues = 16,
function_ref<Value *(Value *)> StripCB = nullptr,
bool Intraprocedural = false) {
@@ -321,7 +322,6 @@ static bool genericValueTraversal(
// Look through select instructions, visit assumed potential values.
if (auto *SI = dyn_cast<SelectInst>(V)) {
- bool UsedAssumedInformation = false;
Optional<Constant *> C = A.getAssumedConstant(
*SI->getCondition(), QueryingAA, UsedAssumedInformation);
bool NoValueYet = !C.hasValue();
@@ -348,6 +348,7 @@ static bool genericValueTraversal(
BasicBlock *IncomingBB = PHI->getIncomingBlock(u);
if (LivenessAA->isEdgeDead(IncomingBB, PHI->getParent())) {
AnyDead = true;
+ UsedAssumedInformation |= !LivenessAA->isAtFixpoint();
continue;
}
Worklist.push_back(
@@ -359,7 +360,7 @@ static bool genericValueTraversal(
if (auto *Arg = dyn_cast<Argument>(V)) {
if (!Intraprocedural && !Arg->hasPassPointeeByValueCopyAttr()) {
SmallVector<Item> CallSiteValues;
- bool AllCallSitesKnown = true;
+ bool UsedAssumedInformation = false;
if (A.checkForAllCallSites(
[&](AbstractCallSite ACS) {
// Callbacks might not have a corresponding call site operand,
@@ -370,7 +371,7 @@ static bool genericValueTraversal(
CallSiteValues.push_back({CSOp, ACS.getInstruction()});
return true;
},
- *Arg->getParent(), true, &QueryingAA, AllCallSitesKnown)) {
+ *Arg->getParent(), true, &QueryingAA, UsedAssumedInformation)) {
Worklist.append(CallSiteValues);
continue;
}
@@ -378,7 +379,6 @@ static bool genericValueTraversal(
}
if (UseValueSimplify && !isa<Constant>(V)) {
- bool UsedAssumedInformation = false;
Optional<Value *> SimpleV =
A.getAssumedSimplified(*V, QueryingAA, UsedAssumedInformation);
if (!SimpleV.hasValue())
@@ -413,6 +413,7 @@ bool AA::getAssumedUnderlyingObjects(Attributor &A, const Value &Ptr,
SmallVectorImpl<Value *> &Objects,
const AbstractAttribute &QueryingAA,
const Instruction *CtxI,
+ bool &UsedAssumedInformation,
bool Intraprocedural) {
auto StripCB = [&](Value *V) { return getUnderlyingObject(V); };
SmallPtrSet<Value *, 8> SeenObjects;
@@ -425,7 +426,7 @@ bool AA::getAssumedUnderlyingObjects(Attributor &A, const Value &Ptr,
};
if (!genericValueTraversal<decltype(Objects)>(
A, IRPosition::value(Ptr), QueryingAA, Objects, VisitValueCB, CtxI,
- true, 32, StripCB, Intraprocedural))
+ UsedAssumedInformation, true, 32, StripCB, Intraprocedural))
return false;
return true;
}
@@ -571,9 +572,9 @@ static void clampCallSiteArgumentStates(Attributor &A, const AAType &QueryingAA,
return T->isValidState();
};
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
if (!A.checkForAllCallSites(CallSiteCheck, QueryingAA, true,
- AllCallSitesKnown))
+ UsedAssumedInformation))
S.indicatePessimisticFixpoint();
else if (T.hasValue())
S ^= *T;
@@ -1895,17 +1896,18 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) {
return true;
};
+ bool UsedAssumedInformation = false;
auto ReturnInstCB = [&](Instruction &I) {
ReturnInst &Ret = cast<ReturnInst>(I);
return genericValueTraversal<ReturnInst>(
A, IRPosition::value(*Ret.getReturnValue()), *this, Ret, ReturnValueCB,
- &I, /* UseValueSimplify */ true, /* MaxValues */ 16,
+ &I, UsedAssumedInformation, /* UseValueSimplify */ true,
+ /* MaxValues */ 16,
/* StripCB */ nullptr, /* Intraprocedural */ true);
};
// Discover returned values from all live returned instructions in the
// associated function.
- bool UsedAssumedInformation = false;
if (!A.checkForAllInstructions(ReturnInstCB, *this, {Instruction::Ret},
UsedAssumedInformation))
return indicatePessimisticFixpoint();
@@ -2421,8 +2423,10 @@ struct AANonNullFloating : public AANonNullImpl {
};
StateType T;
+ bool UsedAssumedInformation = false;
if (!genericValueTraversal<StateType>(A, getIRPosition(), *this, T,
- VisitValueCB, getCtxI()))
+ VisitValueCB, getCtxI(),
+ UsedAssumedInformation))
return indicatePessimisticFixpoint();
return clampStateAndIndicateChange(getState(), T);
@@ -2500,14 +2504,15 @@ struct AANoRecurseFunction final : AANoRecurseImpl {
DepClassTy::NONE);
return NoRecurseAA.isKnownNoRecurse();
};
- bool AllCallSitesKnown;
- if (A.checkForAllCallSites(CallSitePred, *this, true, AllCallSitesKnown)) {
+ bool UsedAssumedInformation = false;
+ if (A.checkForAllCallSites(CallSitePred, *this, true,
+ UsedAssumedInformation)) {
// If we know all call sites and all are known no-recurse, we are done.
// If all known call sites, which might not be all that exist, are known
// to be no-recurse, we are not done but we can continue to assume
// no-recurse. If one of the call sites we have not visited will become
// live, another update is triggered.
- if (AllCallSitesKnown)
+ if (!UsedAssumedInformation)
indicateOptimisticFixpoint();
return ChangeStatus::UNCHANGED;
}
@@ -3147,10 +3152,10 @@ struct AANoAliasArgument final
// If the argument is never passed through callbacks, no-alias cannot break
// synchronization.
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
if (A.checkForAllCallSites(
[](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *this,
- true, AllCallSitesKnown))
+ true, UsedAssumedInformation))
return Base::updateImpl(A);
// TODO: add no-alias but make sure it doesn't break synchronization by
@@ -3728,9 +3733,8 @@ struct AAIsDeadReturned : public AAIsDeadValueImpl {
return areAllUsesAssumedDead(A, *ACS.getInstruction());
};
- bool AllCallSitesKnown;
if (!A.checkForAllCallSites(PredForCallSite, *this, true,
- AllCallSitesKnown))
+ UsedAssumedInformation))
return indicatePessimisticFixpoint();
return ChangeStatus::UNCHANGED;
@@ -4313,8 +4317,10 @@ struct AADereferenceableFloating : AADereferenceableImpl {
};
DerefState T;
+ bool UsedAssumedInformation = false;
if (!genericValueTraversal<DerefState>(A, getIRPosition(), *this, T,
- VisitValueCB, getCtxI()))
+ VisitValueCB, getCtxI(),
+ UsedAssumedInformation))
return indicatePessimisticFixpoint();
return clampStateAndIndicateChange(getState(), T);
@@ -4579,8 +4585,10 @@ struct AAAlignFloating : AAAlignImpl {
};
StateType T;
+ bool UsedAssumedInformation = false;
if (!genericValueTraversal<StateType>(A, getIRPosition(), *this, T,
- VisitValueCB, getCtxI()))
+ VisitValueCB, getCtxI(),
+ UsedAssumedInformation))
return indicatePessimisticFixpoint();
// TODO: If we know we visited all incoming values, thus no are assumed
@@ -5360,7 +5368,9 @@ struct AAValueSimplifyImpl : AAValueSimplify {
Value &Ptr = *L.getPointerOperand();
SmallVector<Value *, 8> Objects;
- if (!AA::getAssumedUnderlyingObjects(A, Ptr, Objects, AA, &L))
+ bool UsedAssumedInformation = false;
+ if (!AA::getAssumedUnderlyingObjects(A, Ptr, Objects, AA, &L,
+ UsedAssumedInformation))
return false;
const auto *TLI =
@@ -5372,7 +5382,6 @@ struct AAValueSimplifyImpl : AAValueSimplify {
if (isa<ConstantPointerNull>(Obj)) {
// A null pointer access can be undefined but any offset from null may
// be OK. We do not try to optimize the latter.
- bool UsedAssumedInformation = false;
if (!NullPointerIsDefined(L.getFunction(),
Ptr.getType()->getPointerAddressSpace()) &&
A.getAssumedSimplified(Ptr, AA, UsedAssumedInformation) == Obj)
@@ -5478,14 +5487,14 @@ struct AAValueSimplifyArgument final : AAValueSimplifyImpl {
// Generate a answer specific to a call site context.
bool Success;
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
if (hasCallBaseContext() &&
getCallBaseContext()->getCalledFunction() == Arg->getParent())
Success = PredForCallSite(
AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));
else
Success = A.checkForAllCallSites(PredForCallSite, *this, true,
- AllCallSitesKnown);
+ UsedAssumedInformation);
if (!Success)
if (!askSimplifiedValueForOtherAAs(A))
@@ -5755,8 +5764,10 @@ struct AAValueSimplifyFloating : AAValueSimplifyImpl {
};
bool Dummy = false;
+ bool UsedAssumedInformation = false;
if (!genericValueTraversal<bool>(A, getIRPosition(), *this, Dummy,
VisitValueCB, getCtxI(),
+ UsedAssumedInformation,
/* UseValueSimplify */ false))
if (!askSimplifiedValueForOtherAAs(A))
return indicatePessimisticFixpoint();
@@ -6168,7 +6179,8 @@ ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &A) {
// branches etc.
SmallVector<Value *, 8> Objects;
if (!AA::getAssumedUnderlyingObjects(A, *DI.CB->getArgOperand(0), Objects,
- *this, DI.CB)) {
+ *this, DI.CB,
+ UsedAssumedInformation)) {
LLVM_DEBUG(
dbgs()
<< "[H2S] Unexpected failure in getAssumedUnderlyingObjects!\n");
@@ -6446,10 +6458,10 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {
Optional<Type *> identifyPrivatizableType(Attributor &A) override {
// If this is a byval argument and we know all the call sites (so we can
// rewrite them), there is no need to check them explicitly.
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
if (getIRPosition().hasAttr(Attribute::ByVal) &&
A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *this,
- true, AllCallSitesKnown))
+ true, UsedAssumedInformation))
return getAssociatedValue().getType()->getPointerElementType();
Optional<Type *> Ty;
@@ -6499,7 +6511,8 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {
return !Ty.hasValue() || Ty.getValue();
};
- if (!A.checkForAllCallSites(CallSiteCheck, *this, true, AllCallSitesKnown))
+ if (!A.checkForAllCallSites(CallSiteCheck, *this, true,
+ UsedAssumedInformation))
return nullptr;
return Ty;
}
@@ -6546,9 +6559,9 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {
return TTI->areTypesABICompatible(
CB->getCaller(), CB->getCalledFunction(), ReplacementTypes);
};
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
if (!A.checkForAllCallSites(CallSiteCheck, *this, true,
- AllCallSitesKnown)) {
+ UsedAssumedInformation)) {
LLVM_DEBUG(
dbgs() << "[AAPrivatizablePtr] ABI incompatibility detected for "
<< Fn.getName() << "\n");
@@ -6675,7 +6688,7 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {
};
if (!A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *this, true,
- AllCallSitesKnown))
+ UsedAssumedInformation))
return indicatePessimisticFixpoint();
return ChangeStatus::UNCHANGED;
@@ -7775,7 +7788,9 @@ void AAMemoryLocationImpl::categorizePtrValue(
<< getMemoryLocationsAsStr(State.getAssumed()) << "]\n");
SmallVector<Value *, 8> Objects;
+ bool UsedAssumedInformation = false;
if (!AA::getAssumedUnderlyingObjects(A, Ptr, Objects, *this, &I,
+ UsedAssumedInformation,
/* Intraprocedural */ true)) {
LLVM_DEBUG(
dbgs() << "[AAMemoryLocation] Pointer locations not categorized\n");
@@ -8591,8 +8606,10 @@ struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
IntegerRangeState T(getBitWidth());
+ bool UsedAssumedInformation = false;
if (!genericValueTraversal<IntegerRangeState>(A, getIRPosition(), *this, T,
VisitValueCB, getCtxI(),
+ UsedAssumedInformation,
/* UseValueSimplify */ false))
return indicatePessimisticFixpoint();
@@ -9403,8 +9420,10 @@ struct AANoUndefFloating : public AANoUndefImpl {
};
StateType T;
+ bool UsedAssumedInformation = false;
if (!genericValueTraversal<StateType>(A, getIRPosition(), *this, T,
- VisitValueCB, getCtxI()))
+ VisitValueCB, getCtxI(),
+ UsedAssumedInformation))
return indicatePessimisticFixpoint();
return clampStateAndIndicateChange(getState(), T);
@@ -9521,9 +9540,10 @@ struct AACallEdgesCallSite : public AACallEdgesImpl {
// Process any value that we might call.
auto ProcessCalledOperand = [&](Value *V) {
bool DummyValue = false;
+ bool UsedAssumedInformation = false;
if (!genericValueTraversal<bool>(A, IRPosition::value(*V), *this,
DummyValue, VisitValue, nullptr,
- false)) {
+ UsedAssumedInformation, false)) {
// If we haven't gone through all values, assume that there are unknown
// callees.
setHasUnknownCallee(true, Change);
@@ -9942,12 +9962,13 @@ struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {
return !getAssumed().empty() || !getKnown().empty();
};
- bool AllCallSitesKnown;
+ bool UsedAssumedInformation = false;
// Get the intersection of all assumptions held by this node's predecessors.
// If we don't know all the call sites then this is either an entry into the
// call graph or an empty node. This node is known to only contain its own
// assumptions and can be propagated to its successors.
- if (!A.checkForAllCallSites(CallSitePred, *this, true, AllCallSitesKnown))
+ if (!A.checkForAllCallSites(CallSitePred, *this, true,
+ UsedAssumedInformation))
return indicatePessimisticFixpoint();
return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;
diff --git a/llvm/test/Transforms/Attributor/norecurse.ll b/llvm/test/Transforms/Attributor/norecurse.ll
index 61bba0a6044e..dd096a32c147 100644
--- a/llvm/test/Transforms/Attributor/norecurse.ll
+++ b/llvm/test/Transforms/Attributor/norecurse.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
+; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=7 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
@@ -71,7 +71,7 @@ define void @intrinsic(i8* %dest, i8* %src, i32 %len) {
; CHECK: Function Attrs: argmemonly nofree nosync nounwind willreturn
; CHECK-LABEL: define {{[^@]+}}@intrinsic
; CHECK-SAME: (i8* nocapture nofree writeonly [[DEST:%.*]], i8* nocapture nofree readonly [[SRC:%.*]], i32 [[LEN:%.*]]) #[[ATTR4:[0-9]+]] {
-; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[DEST]], i8* noalias nocapture nofree readonly [[SRC]], i32 [[LEN]], i1 noundef false) #[[ATTR8:[0-9]+]]
+; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree writeonly [[DEST]], i8* noalias nocapture nofree readonly [[SRC]], i32 [[LEN]], i1 noundef false) #[[ATTR9:[0-9]+]]
; CHECK-NEXT: ret void
;
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 false)
@@ -250,6 +250,47 @@ Dead:
ret i32 1
}
+define i1 @test_rec_neg(i1 %c) norecurse {
+; CHECK: Function Attrs: norecurse
+; CHECK-LABEL: define {{[^@]+}}@test_rec_neg
+; CHECK-SAME: (i1 [[C:%.*]]) #[[ATTR8:[0-9]+]] {
+; CHECK-NEXT: [[RC1:%.*]] = call noundef i1 @rec(i1 noundef true)
+; CHECK-NEXT: br i1 [[RC1]], label [[T:%.*]], label [[F:%.*]]
+; CHECK: t:
+; CHECK-NEXT: [[RC2:%.*]] = call noundef i1 @rec(i1 [[C]])
+; CHECK-NEXT: ret i1 [[RC2]]
+; CHECK: f:
+; CHECK-NEXT: ret i1 [[RC1]]
+;
+ %rc1 = call i1 @rec(i1 true)
+ br i1 %rc1, label %t, label %f
+t:
+ %rc2 = call i1 @rec(i1 %c)
+ ret i1 %rc2
+f:
+ ret i1 %rc1
+}
+
+define internal i1 @rec(i1 %c1) {
+; CHECK-LABEL: define {{[^@]+}}@rec
+; CHECK-SAME: (i1 [[C1:%.*]]) {
+; CHECK-NEXT: br i1 [[C1]], label [[T:%.*]], label [[F:%.*]]
+; CHECK: t:
+; CHECK-NEXT: ret i1 true
+; CHECK: f:
+; CHECK-NEXT: [[R:%.*]] = call i1 @rec(i1 noundef true)
+; CHECK-NEXT: call void @unknown()
+; CHECK-NEXT: ret i1 false
+;
+ br i1 %c1, label %t, label %f
+t:
+ ret i1 true
+f:
+ %r = call i1 @rec(i1 true)
+ call void @unknown()
+ ret i1 false
+}
+
;.
; CHECK: attributes #[[ATTR0]] = { nofree norecurse nosync nounwind readnone willreturn }
; CHECK: attributes #[[ATTR1]] = { nofree nosync nounwind readnone willreturn }
@@ -259,5 +300,6 @@ Dead:
; CHECK: attributes #[[ATTR5:[0-9]+]] = { argmemonly nofree nounwind willreturn }
; CHECK: attributes #[[ATTR6]] = { norecurse nosync readnone }
; CHECK: attributes #[[ATTR7]] = { null_pointer_is_valid }
-; CHECK: attributes #[[ATTR8]] = { willreturn }
+; CHECK: attributes #[[ATTR8]] = { norecurse }
+; CHECK: attributes #[[ATTR9]] = { willreturn }
;.
diff --git a/llvm/test/Transforms/OpenMP/custom_state_machines.ll b/llvm/test/Transforms/OpenMP/custom_state_machines.ll
index e17679b2a896..c0f51d3bbcf6 100644
--- a/llvm/test/Transforms/OpenMP/custom_state_machines.ll
+++ b/llvm/test/Transforms/OpenMP/custom_state_machines.ll
@@ -1620,9 +1620,9 @@ attributes #9 = { convergent nounwind readonly willreturn }
; AMDGPU-NEXT: ret void
;
;
-; AMDGPU: Function Attrs: convergent noinline norecurse nounwind
+; AMDGPU: Function Attrs: convergent noinline nounwind
; AMDGPU-LABEL: define {{[^@]+}}@simple_state_machine_interprocedural_nested_recursive_after.internalized
-; AMDGPU-SAME: (i32 [[A:%.*]]) #[[ATTR0]] {
+; AMDGPU-SAME: (i32 [[A:%.*]]) #[[ATTR1]] {
; AMDGPU-NEXT: entry:
; AMDGPU-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
; AMDGPU-NEXT: store i32 [[A]], i32* [[A_ADDR]], align 4
@@ -1632,7 +1632,7 @@ attributes #9 = { convergent nounwind readonly willreturn }
; AMDGPU-NEXT: br label [[RETURN:%.*]]
; AMDGPU: if.end:
; AMDGPU-NEXT: [[SUB:%.*]] = sub nsw i32 [[A]], 1
-; AMDGPU-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after.internalized(i32 [[SUB]]) #[[ATTR11:[0-9]+]]
+; AMDGPU-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after.internalized(i32 [[SUB]]) #[[ATTR8]]
; AMDGPU-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after_after.internalized() #[[ATTR8]]
; AMDGPU-NEXT: br label [[RETURN]]
; AMDGPU: return:
@@ -1772,9 +1772,9 @@ attributes #9 = { convergent nounwind readonly willreturn }
; AMDGPU-NEXT: ret void
;
;
-; AMDGPU: Function Attrs: convergent noinline norecurse nounwind
+; AMDGPU: Function Attrs: convergent noinline nounwind
; AMDGPU-LABEL: define {{[^@]+}}@simple_state_machine_interprocedural_nested_recursive_after_after.internalized
-; AMDGPU-SAME: () #[[ATTR0]] {
+; AMDGPU-SAME: () #[[ATTR1]] {
; AMDGPU-NEXT: entry:
; AMDGPU-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [0 x i8*], align 8
; AMDGPU-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef @[[GLOB2]]) #[[ATTR3]]
@@ -2590,9 +2590,9 @@ attributes #9 = { convergent nounwind readonly willreturn }
; NVPTX-NEXT: ret void
;
;
-; NVPTX: Function Attrs: convergent noinline norecurse nounwind
+; NVPTX: Function Attrs: convergent noinline nounwind
; NVPTX-LABEL: define {{[^@]+}}@simple_state_machine_interprocedural_nested_recursive_after.internalized
-; NVPTX-SAME: (i32 [[A:%.*]]) #[[ATTR0]] {
+; NVPTX-SAME: (i32 [[A:%.*]]) #[[ATTR1]] {
; NVPTX-NEXT: entry:
; NVPTX-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
; NVPTX-NEXT: store i32 [[A]], i32* [[A_ADDR]], align 4
@@ -2602,7 +2602,7 @@ attributes #9 = { convergent nounwind readonly willreturn }
; NVPTX-NEXT: br label [[RETURN:%.*]]
; NVPTX: if.end:
; NVPTX-NEXT: [[SUB:%.*]] = sub nsw i32 [[A]], 1
-; NVPTX-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after.internalized(i32 [[SUB]]) #[[ATTR11:[0-9]+]]
+; NVPTX-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after.internalized(i32 [[SUB]]) #[[ATTR8]]
; NVPTX-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after_after.internalized() #[[ATTR8]]
; NVPTX-NEXT: br label [[RETURN]]
; NVPTX: return:
@@ -2741,9 +2741,9 @@ attributes #9 = { convergent nounwind readonly willreturn }
; NVPTX-NEXT: ret void
;
;
-; NVPTX: Function Attrs: convergent noinline norecurse nounwind
+; NVPTX: Function Attrs: convergent noinline nounwind
; NVPTX-LABEL: define {{[^@]+}}@simple_state_machine_interprocedural_nested_recursive_after_after.internalized
-; NVPTX-SAME: () #[[ATTR0]] {
+; NVPTX-SAME: () #[[ATTR1]] {
; NVPTX-NEXT: entry:
; NVPTX-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [0 x i8*], align 8
; NVPTX-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef @[[GLOB2]]) #[[ATTR3]]
@@ -3315,9 +3315,9 @@ attributes #9 = { convergent nounwind readonly willreturn }
; AMDGPU-DISABLED-NEXT: ret void
;
;
-; AMDGPU-DISABLED: Function Attrs: convergent noinline norecurse nounwind
+; AMDGPU-DISABLED: Function Attrs: convergent noinline nounwind
; AMDGPU-DISABLED-LABEL: define {{[^@]+}}@simple_state_machine_interprocedural_nested_recursive_after.internalized
-; AMDGPU-DISABLED-SAME: (i32 [[A:%.*]]) #[[ATTR0]] {
+; AMDGPU-DISABLED-SAME: (i32 [[A:%.*]]) #[[ATTR1]] {
; AMDGPU-DISABLED-NEXT: entry:
; AMDGPU-DISABLED-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
; AMDGPU-DISABLED-NEXT: store i32 [[A]], i32* [[A_ADDR]], align 4
@@ -3327,7 +3327,7 @@ attributes #9 = { convergent nounwind readonly willreturn }
; AMDGPU-DISABLED-NEXT: br label [[RETURN:%.*]]
; AMDGPU-DISABLED: if.end:
; AMDGPU-DISABLED-NEXT: [[SUB:%.*]] = sub nsw i32 [[A]], 1
-; AMDGPU-DISABLED-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after.internalized(i32 [[SUB]]) #[[ATTR11:[0-9]+]]
+; AMDGPU-DISABLED-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after.internalized(i32 [[SUB]]) #[[ATTR8]]
; AMDGPU-DISABLED-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after_after.internalized() #[[ATTR8]]
; AMDGPU-DISABLED-NEXT: br label [[RETURN]]
; AMDGPU-DISABLED: return:
@@ -3436,9 +3436,9 @@ attributes #9 = { convergent nounwind readonly willreturn }
; AMDGPU-DISABLED-NEXT: ret void
;
;
-; AMDGPU-DISABLED: Function Attrs: convergent noinline norecurse nounwind
+; AMDGPU-DISABLED: Function Attrs: convergent noinline nounwind
; AMDGPU-DISABLED-LABEL: define {{[^@]+}}@simple_state_machine_interprocedural_nested_recursive_after_after.internalized
-; AMDGPU-DISABLED-SAME: () #[[ATTR0]] {
+; AMDGPU-DISABLED-SAME: () #[[ATTR1]] {
; AMDGPU-DISABLED-NEXT: entry:
; AMDGPU-DISABLED-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [0 x i8*], align 8
; AMDGPU-DISABLED-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef @[[GLOB2]]) #[[ATTR3]]
@@ -4010,9 +4010,9 @@ attributes #9 = { convergent nounwind readonly willreturn }
; NVPTX-DISABLED-NEXT: ret void
;
;
-; NVPTX-DISABLED: Function Attrs: convergent noinline norecurse nounwind
+; NVPTX-DISABLED: Function Attrs: convergent noinline nounwind
; NVPTX-DISABLED-LABEL: define {{[^@]+}}@simple_state_machine_interprocedural_nested_recursive_after.internalized
-; NVPTX-DISABLED-SAME: (i32 [[A:%.*]]) #[[ATTR0]] {
+; NVPTX-DISABLED-SAME: (i32 [[A:%.*]]) #[[ATTR1]] {
; NVPTX-DISABLED-NEXT: entry:
; NVPTX-DISABLED-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
; NVPTX-DISABLED-NEXT: store i32 [[A]], i32* [[A_ADDR]], align 4
@@ -4022,7 +4022,7 @@ attributes #9 = { convergent nounwind readonly willreturn }
; NVPTX-DISABLED-NEXT: br label [[RETURN:%.*]]
; NVPTX-DISABLED: if.end:
; NVPTX-DISABLED-NEXT: [[SUB:%.*]] = sub nsw i32 [[A]], 1
-; NVPTX-DISABLED-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after.internalized(i32 [[SUB]]) #[[ATTR11:[0-9]+]]
+; NVPTX-DISABLED-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after.internalized(i32 [[SUB]]) #[[ATTR8]]
; NVPTX-DISABLED-NEXT: call void @simple_state_machine_interprocedural_nested_recursive_after_after.internalized() #[[ATTR8]]
; NVPTX-DISABLED-NEXT: br label [[RETURN]]
; NVPTX-DISABLED: return:
@@ -4131,9 +4131,9 @@ attributes #9 = { convergent nounwind readonly willreturn }
; NVPTX-DISABLED-NEXT: ret void
;
;
-; NVPTX-DISABLED: Function Attrs: convergent noinline norecurse nounwind
+; NVPTX-DISABLED: Function Attrs: convergent noinline nounwind
; NVPTX-DISABLED-LABEL: define {{[^@]+}}@simple_state_machine_interprocedural_nested_recursive_after_after.internalized
-; NVPTX-DISABLED-SAME: () #[[ATTR0]] {
+; NVPTX-DISABLED-SAME: () #[[ATTR1]] {
; NVPTX-DISABLED-NEXT: entry:
; NVPTX-DISABLED-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [0 x i8*], align 8
; NVPTX-DISABLED-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(%struct.ident_t* noundef @[[GLOB2]]) #[[ATTR3]]