forked from OSchip/llvm-project
[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
This commit is contained in:
parent
67ab4c010b
commit
6ed1ef0643
llvm
include/llvm/Transforms/IPO
lib/Transforms/IPO
test/Transforms
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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!");
|
||||
|
||||
|
|
|
@ -260,7 +260,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) {
|
||||
|
||||
|
@ -320,7 +321,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();
|
||||
|
@ -347,6 +347,7 @@ static bool genericValueTraversal(
|
|||
BasicBlock *IncomingBB = PHI->getIncomingBlock(u);
|
||||
if (LivenessAA->isEdgeDead(IncomingBB, PHI->getParent())) {
|
||||
AnyDead = true;
|
||||
UsedAssumedInformation |= !LivenessAA->isAtFixpoint();
|
||||
continue;
|
||||
}
|
||||
Worklist.push_back(
|
||||
|
@ -358,7 +359,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,
|
||||
|
@ -369,7 +370,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;
|
||||
}
|
||||
|
@ -377,7 +378,6 @@ static bool genericValueTraversal(
|
|||
}
|
||||
|
||||
if (UseValueSimplify && !isa<Constant>(V)) {
|
||||
bool UsedAssumedInformation = false;
|
||||
Optional<Value *> SimpleV =
|
||||
A.getAssumedSimplified(*V, QueryingAA, UsedAssumedInformation);
|
||||
if (!SimpleV.hasValue())
|
||||
|
@ -412,6 +412,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;
|
||||
|
@ -424,7 +425,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;
|
||||
}
|
||||
|
@ -570,9 +571,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;
|
||||
|
@ -1877,17 +1878,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();
|
||||
|
@ -2403,8 +2405,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);
|
||||
|
@ -2482,14 +2486,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;
|
||||
}
|
||||
|
@ -3129,10 +3134,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
|
||||
|
@ -3710,9 +3715,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;
|
||||
|
@ -4295,8 +4299,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);
|
||||
|
@ -4561,8 +4567,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
|
||||
|
@ -5342,7 +5350,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 =
|
||||
|
@ -5354,7 +5364,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)
|
||||
|
@ -5460,14 +5469,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))
|
||||
|
@ -5737,8 +5746,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();
|
||||
|
@ -6150,7 +6161,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");
|
||||
|
@ -6428,10 +6440,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;
|
||||
|
@ -6481,7 +6493,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;
|
||||
}
|
||||
|
@ -6528,9 +6541,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");
|
||||
|
@ -6657,7 +6670,7 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {
|
|||
};
|
||||
|
||||
if (!A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *this, true,
|
||||
AllCallSitesKnown))
|
||||
UsedAssumedInformation))
|
||||
return indicatePessimisticFixpoint();
|
||||
|
||||
return ChangeStatus::UNCHANGED;
|
||||
|
@ -7757,7 +7770,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");
|
||||
|
@ -8573,8 +8588,10 @@ struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {
|
|||
|
||||
IntegerRangeState T(getBitWidth());
|
||||
|
||||
bool UsedAssumedInformation = false;
|
||||
if (!genericValueTraversal<IntegerRangeState>(A, getIRPosition(), *this, T,
|
||||
VisitValueCB, getCtxI(),
|
||||
UsedAssumedInformation,
|
||||
/* UseValueSimplify */ false))
|
||||
return indicatePessimisticFixpoint();
|
||||
|
||||
|
@ -9385,8 +9402,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);
|
||||
|
@ -9503,9 +9522,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);
|
||||
|
@ -9924,12 +9944,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;
|
||||
|
|
|
@ -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 }
|
||||
;.
|
||||
|
|
|
@ -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]]
|
||||
|
|
Loading…
Reference in New Issue