[llvm] 31ad4db - Reapply "[Attributor] Introduce AA[Intra/Inter]Reachability"
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 10 12:30:25 PST 2023
Author: Johannes Doerfert
Date: 2023-01-10T12:29:24-08:00
New Revision: 31ad4dbcb91c419254670585aa51088aeeec79cf
URL: https://github.com/llvm/llvm-project/commit/31ad4dbcb91c419254670585aa51088aeeec79cf
DIFF: https://github.com/llvm/llvm-project/commit/31ad4dbcb91c419254670585aa51088aeeec79cf.diff
LOG: Reapply "[Attributor] Introduce AA[Intra/Inter]Reachability"
This reverts commit e425a4c45618fcfa8ffb13be4ddfaa5d28aa38f1 after the
memory leak has been fixed.
Added:
Modified:
llvm/include/llvm/Transforms/IPO/Attributor.h
llvm/lib/Transforms/IPO/Attributor.cpp
llvm/lib/Transforms/IPO/AttributorAttributes.cpp
llvm/test/Transforms/Attributor/ArgumentPromotion/alloca-as.ll
llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll
llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll
llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll
llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll
llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll
llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll
llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll
llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll
llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll
llvm/test/Transforms/Attributor/cgscc_bugs.ll
llvm/test/Transforms/Attributor/depgraph.ll
llvm/test/Transforms/Attributor/internal-noalias.ll
llvm/test/Transforms/Attributor/liveness_chains.ll
llvm/test/Transforms/Attributor/lowerheap.ll
llvm/test/Transforms/Attributor/misc.ll
llvm/test/Transforms/Attributor/noalias.ll
llvm/test/Transforms/Attributor/noundef.ll
llvm/test/Transforms/Attributor/value-simplify-assume.ll
llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
llvm/test/Transforms/Attributor/value-simplify-reachability.ll
llvm/unittests/Transforms/IPO/AttributorTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h
index 29231c6c9f27f..dbf289242c5d8 100644
--- a/llvm/include/llvm/Transforms/IPO/Attributor.h
+++ b/llvm/include/llvm/Transforms/IPO/Attributor.h
@@ -152,6 +152,7 @@ class Function;
/// Abstract Attribute helper functions.
namespace AA {
+using InstExclusionSetTy = SmallPtrSet<Instruction *, 4>;
enum class GPUAddressSpace : unsigned {
Generic = 0,
@@ -350,23 +351,26 @@ bool isAssumedReadOnly(Attributor &A, const IRPosition &IRP,
bool isAssumedReadNone(Attributor &A, const IRPosition &IRP,
const AbstractAttribute &QueryingAA, bool &IsKnown);
-/// Return true if \p ToI is potentially reachable from \p FromI. The two
-/// instructions do not need to be in the same function. \p GoBackwardsCB
-/// can be provided to convey domain knowledge about the "lifespan" the user is
-/// interested in. By default, the callers of \p FromI are checked as well to
-/// determine if \p ToI can be reached. If the query is not interested in
-/// callers beyond a certain point, e.g., a GPU kernel entry or the function
-/// containing an alloca, the \p GoBackwardsCB should return false.
+/// Return true if \p ToI is potentially reachable from \p FromI without running
+/// into any instruction in \p ExclusionSet The two instructions do not need to
+/// be in the same function. \p GoBackwardsCB can be provided to convey domain
+/// knowledge about the "lifespan" the user is interested in. By default, the
+/// callers of \p FromI are checked as well to determine if \p ToI can be
+/// reached. If the query is not interested in callers beyond a certain point,
+/// e.g., a GPU kernel entry or the function containing an alloca, the
+/// \p GoBackwardsCB should return false.
bool isPotentiallyReachable(
Attributor &A, const Instruction &FromI, const Instruction &ToI,
const AbstractAttribute &QueryingAA,
+ const AA::InstExclusionSetTy *ExclusionSet = nullptr,
std::function<bool(const Function &F)> GoBackwardsCB = nullptr);
/// Same as above but it is sufficient to reach any instruction in \p ToFn.
bool isPotentiallyReachable(
Attributor &A, const Instruction &FromI, const Function &ToFn,
const AbstractAttribute &QueryingAA,
- std::function<bool(const Function &F)> GoBackwardsCB);
+ const AA::InstExclusionSetTy *ExclusionSet = nullptr,
+ std::function<bool(const Function &F)> GoBackwardsCB = nullptr);
/// Return true if \p Obj is assumed to be a thread local object.
bool isAssumedThreadLocalObject(Attributor &A, Value &Obj,
@@ -412,6 +416,39 @@ struct DenseMapInfo<AA::ValueScope> : public DenseMapInfo<unsigned char> {
}
};
+template <>
+struct DenseMapInfo<const AA::InstExclusionSetTy *>
+ : public DenseMapInfo<void *> {
+ using super = DenseMapInfo<void *>;
+ static inline const AA::InstExclusionSetTy *getEmptyKey() {
+ return static_cast<const AA::InstExclusionSetTy *>(super::getEmptyKey());
+ }
+ static inline const AA::InstExclusionSetTy *getTombstoneKey() {
+ return static_cast<const AA::InstExclusionSetTy *>(
+ super::getTombstoneKey());
+ }
+ static unsigned getHashValue(const AA::InstExclusionSetTy *BES) {
+ unsigned H = 0;
+ if (BES)
+ for (const auto *II : *BES)
+ H += DenseMapInfo<const Instruction *>::getHashValue(II);
+ return H;
+ }
+ static bool isEqual(const AA::InstExclusionSetTy *LHS,
+ const AA::InstExclusionSetTy *RHS) {
+ if (LHS == RHS)
+ return true;
+ if (LHS == getEmptyKey() || RHS == getEmptyKey() ||
+ LHS == getTombstoneKey() || RHS == getTombstoneKey())
+ return false;
+ if (!LHS || !RHS)
+ return ((LHS && LHS->empty()) || (RHS && RHS->empty()));
+ if (LHS->size() != RHS->size())
+ return false;
+ return llvm::set_is_subset(*LHS, *RHS);
+ }
+};
+
/// The value passed to the line option that defines the maximal initialization
/// chain length.
extern unsigned MaxInitializationChainLength;
@@ -1132,6 +1169,10 @@ struct InformationCache {
// the destructor manually.
for (auto &It : FuncInfoMap)
It.getSecond()->~FunctionInfo();
+ // Same is true for the instruction exclusions sets.
+ using AA::InstExclusionSetTy;
+ for (auto *BES : BESets)
+ BES->~InstExclusionSetTy();
}
/// Apply \p CB to all uses of \p F. If \p LookThroughConstantExprUses is
@@ -1249,21 +1290,16 @@ struct InformationCache {
/// Return the map conaining all the knowledge we have from `llvm.assume`s.
const RetainedKnowledgeMap &getKnowledgeMap() const { return KnowledgeMap; }
- /// Return if \p To is potentially reachable form \p From or not
- /// If the same query was answered, return cached result
- bool getPotentiallyReachable(const Instruction &From, const Instruction &To) {
- auto KeyPair = std::make_pair(&From, &To);
- auto Iter = PotentiallyReachableMap.find(KeyPair);
- if (Iter != PotentiallyReachableMap.end())
- return Iter->second;
- const Function &F = *From.getFunction();
- bool Result = true;
- if (From.getFunction() == To.getFunction())
- Result = isPotentiallyReachable(&From, &To, nullptr,
- AG.getAnalysis<DominatorTreeAnalysis>(F),
- AG.getAnalysis<LoopAnalysis>(F));
- PotentiallyReachableMap.insert(std::make_pair(KeyPair, Result));
- return Result;
+ /// Given \p BES, return a uniqued version. \p BES is destroyed in the
+ /// process.
+ const AA::InstExclusionSetTy *
+ getOrCreateUniqueBlockExecutionSet(const AA::InstExclusionSetTy *BES) {
+ auto It = BESets.find(BES);
+ if (It != BESets.end())
+ return *It;
+ auto *UniqueBES = new (Allocator) AA::InstExclusionSetTy(*BES);
+ BESets.insert(UniqueBES);
+ return UniqueBES;
}
/// Check whether \p F is part of module slice.
@@ -1332,16 +1368,15 @@ struct InformationCache {
/// A container for all instructions that are only used by `llvm.assume`.
SetVector<const Instruction *> AssumeOnlyValues;
+ /// Cache for block sets to allow reuse.
+ DenseSet<AA::InstExclusionSetTy *> BESets;
+
/// Getters for analysis.
AnalysisGetter &AG;
/// Set of inlineable functions
SmallPtrSet<const Function *, 8> InlineableFunctions;
- /// A map for caching results of queries for isPotentiallyReachable
- DenseMap<std::pair<const Instruction *, const Instruction *>, bool>
- PotentiallyReachableMap;
-
/// The triple describing the target machine.
Triple TargetTriple;
@@ -3421,42 +3456,30 @@ struct AAUndefinedBehavior
};
/// An abstract interface to determine reachability of point A to B.
-struct AAReachability : public StateWrapper<BooleanState, AbstractAttribute> {
+struct AAIntraFnReachability
+ : public StateWrapper<BooleanState, AbstractAttribute> {
using Base = StateWrapper<BooleanState, AbstractAttribute>;
- AAReachability(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
+ AAIntraFnReachability(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
/// Returns true if 'From' instruction is assumed to reach, 'To' instruction.
/// Users should provide two positions they are interested in, and the class
/// determines (and caches) reachability.
- bool isAssumedReachable(Attributor &A, const Instruction &From,
- const Instruction &To) const {
- if (!getState().isValidState())
- return true;
- return A.getInfoCache().getPotentiallyReachable(From, To);
- }
-
- /// Returns true if 'From' instruction is known to reach, 'To' instruction.
- /// Users should provide two positions they are interested in, and the class
- /// determines (and caches) reachability.
- bool isKnownReachable(Attributor &A, const Instruction &From,
- const Instruction &To) const {
- if (!getState().isValidState())
- return false;
- return A.getInfoCache().getPotentiallyReachable(From, To);
- }
+ virtual bool isAssumedReachable(
+ Attributor &A, const Instruction &From, const Instruction &To,
+ const AA::InstExclusionSetTy *ExclusionSet = nullptr) const = 0;
/// Create an abstract attribute view for the position \p IRP.
- static AAReachability &createForPosition(const IRPosition &IRP,
- Attributor &A);
+ static AAIntraFnReachability &createForPosition(const IRPosition &IRP,
+ Attributor &A);
/// See AbstractAttribute::getName()
- const std::string getName() const override { return "AAReachability"; }
+ const std::string getName() const override { return "AAIntraFnReachability"; }
/// See AbstractAttribute::getIdAddr()
const char *getIdAddr() const override { return &ID; }
/// This function should return true if the type of the \p AA is
- /// AAReachability
+ /// AAIntraFnReachability
static bool classof(const AbstractAttribute *AA) {
return (AA->getIdAddr() == &ID);
}
@@ -4977,35 +5000,33 @@ struct AAExecutionDomain
};
/// An abstract Attribute for computing reachability between functions.
-struct AAFunctionReachability
+struct AAInterFnReachability
: public StateWrapper<BooleanState, AbstractAttribute> {
using Base = StateWrapper<BooleanState, AbstractAttribute>;
- AAFunctionReachability(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
-
- /// See AbstractAttribute::isQueryAA.
- bool isQueryAA() const override { return true; }
+ AAInterFnReachability(const IRPosition &IRP, Attributor &A) : Base(IRP) {}
/// If the function represented by this possition can reach \p Fn.
- virtual bool canReach(Attributor &A, const Function &Fn) const = 0;
-
- /// Can \p CB reach \p Fn.
- virtual bool canReach(Attributor &A, CallBase &CB,
- const Function &Fn) const = 0;
+ bool canReach(Attributor &A, const Function &Fn) const {
+ Function *Scope = getAnchorScope();
+ if (!Scope || Scope->isDeclaration())
+ return true;
+ return instructionCanReach(A, Scope->getEntryBlock().front(), Fn);
+ }
/// Can \p Inst reach \p Fn.
/// See also AA::isPotentiallyReachable.
- virtual bool instructionCanReach(Attributor &A, const Instruction &Inst,
- const Function &Fn) const = 0;
+ virtual bool instructionCanReach(
+ Attributor &A, const Instruction &Inst, const Function &Fn,
+ const AA::InstExclusionSetTy *ExclusionSet = nullptr,
+ SmallPtrSet<const Function *, 16> *Visited = nullptr) const = 0;
/// Create an abstract attribute view for the position \p IRP.
- static AAFunctionReachability &createForPosition(const IRPosition &IRP,
- Attributor &A);
+ static AAInterFnReachability &createForPosition(const IRPosition &IRP,
+ Attributor &A);
/// See AbstractAttribute::getName()
- const std::string getName() const override {
- return "AAFunctionReachability";
- }
+ const std::string getName() const override { return "AAInterFnReachability"; }
/// See AbstractAttribute::getIdAddr()
const char *getIdAddr() const override { return &ID; }
@@ -5017,10 +5038,6 @@ struct AAFunctionReachability
/// Unique ID (due to the unique address)
static const char ID;
-
-private:
- /// Can this function reach a call with unknown calee.
- virtual bool canReachUnknownCallee() const = 0;
};
/// An abstract interface for struct information.
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 78f16fae3c1b8..16e12934dde5b 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -572,19 +572,27 @@ static bool
isPotentiallyReachable(Attributor &A, const Instruction &FromI,
const Instruction *ToI, const Function &ToFn,
const AbstractAttribute &QueryingAA,
+ const AA::InstExclusionSetTy *ExclusionSet,
std::function<bool(const Function &F)> GoBackwardsCB) {
- LLVM_DEBUG(dbgs() << "[AA] isPotentiallyReachable @" << ToFn.getName()
- << " from " << FromI << " [GBCB: " << bool(GoBackwardsCB)
- << "]\n");
-
- // TODO: If we can go arbitrarily backwards we will eventually reach an
- // entry point that can reach ToI. Only once this takes a set of blocks
- // through which we cannot go, or once we track internal functions not
- // accessible from the outside, it makes sense to perform backwards analysis
- // in the absence of a GoBackwardsCB.
- if (!GoBackwardsCB) {
+ LLVM_DEBUG({
+ dbgs() << "[AA] isPotentiallyReachable @" << ToFn.getName() << " from "
+ << FromI << " [GBCB: " << bool(GoBackwardsCB) << "][#ExS: "
+ << (ExclusionSet ? std::to_string(ExclusionSet->size()) : "none")
+ << "]\n";
+ if (ExclusionSet)
+ for (auto *ES : *ExclusionSet)
+ dbgs() << *ES << "\n";
+ });
+
+ // If we can go arbitrarily backwards we will eventually reach an entry point
+ // that can reach ToI. Only if a set of blocks through which we cannot go is
+ // provided, or once we track internal functions not accessible from the
+ // outside, it makes sense to perform backwards analysis in the absence of a
+ // GoBackwardsCB.
+ if (!GoBackwardsCB && !ExclusionSet) {
LLVM_DEBUG(dbgs() << "[AA] check @" << ToFn.getName() << " from " << FromI
- << " is not checked backwards, abort\n");
+ << " is not checked backwards and does not have an "
+ "exclusion set, abort\n");
return true;
}
@@ -603,9 +611,10 @@ isPotentiallyReachable(Attributor &A, const Instruction &FromI,
return true;
LLVM_DEBUG(dbgs() << "[AA] check " << *ToI << " from " << *CurFromI
<< " intraprocedurally\n");
- const auto &ReachabilityAA = A.getAAFor<AAReachability>(
+ const auto &ReachabilityAA = A.getAAFor<AAIntraFnReachability>(
QueryingAA, IRPosition::function(ToFn), DepClassTy::OPTIONAL);
- bool Result = ReachabilityAA.isAssumedReachable(A, *CurFromI, *ToI);
+ bool Result =
+ ReachabilityAA.isAssumedReachable(A, *CurFromI, *ToI, ExclusionSet);
LLVM_DEBUG(dbgs() << "[AA] " << *CurFromI << " "
<< (Result ? "can potentially " : "cannot ") << "reach "
<< *ToI << " [Intra]\n");
@@ -613,15 +622,57 @@ isPotentiallyReachable(Attributor &A, const Instruction &FromI,
return true;
}
- // Check if the current instruction is already known to reach the ToFn.
- const auto &FnReachabilityAA = A.getAAFor<AAFunctionReachability>(
+ bool Result = true;
+ if (!ToFn.isDeclaration() && ToI) {
+ const auto &ToReachabilityAA = A.getAAFor<AAIntraFnReachability>(
+ QueryingAA, IRPosition::function(ToFn), DepClassTy::OPTIONAL);
+ const Instruction &EntryI = ToFn.getEntryBlock().front();
+ Result =
+ ToReachabilityAA.isAssumedReachable(A, EntryI, *ToI, ExclusionSet);
+ LLVM_DEBUG(dbgs() << "[AA] Entry " << EntryI << " of @" << ToFn.getName()
+ << " " << (Result ? "can potentially " : "cannot ")
+ << "reach @" << *ToI << " [ToFn]\n");
+ }
+
+ if (Result) {
+ // The entry of the ToFn can reach the instruction ToI. If the current
+ // instruction is already known to reach the ToFn.
+ const auto &FnReachabilityAA = A.getAAFor<AAInterFnReachability>(
+ QueryingAA, IRPosition::function(*FromFn), DepClassTy::OPTIONAL);
+ Result = FnReachabilityAA.instructionCanReach(A, *CurFromI, ToFn,
+ ExclusionSet);
+ LLVM_DEBUG(dbgs() << "[AA] " << *CurFromI << " in @" << FromFn->getName()
+ << " " << (Result ? "can potentially " : "cannot ")
+ << "reach @" << ToFn.getName() << " [FromFn]\n");
+ if (Result)
+ return true;
+ }
+
+ // TODO: Check assumed nounwind.
+ const auto &ReachabilityAA = A.getAAFor<AAIntraFnReachability>(
QueryingAA, IRPosition::function(*FromFn), DepClassTy::OPTIONAL);
- bool Result = FnReachabilityAA.instructionCanReach(A, *CurFromI, ToFn);
- LLVM_DEBUG(dbgs() << "[AA] " << *CurFromI << " in @" << FromFn->getName()
- << " " << (Result ? "can potentially " : "cannot ")
- << "reach @" << ToFn.getName() << " [FromFn]\n");
- if (Result)
+ auto ReturnInstCB = [&](Instruction &Ret) {
+ bool Result =
+ ReachabilityAA.isAssumedReachable(A, *CurFromI, Ret, ExclusionSet);
+ LLVM_DEBUG(dbgs() << "[AA][Ret] " << *CurFromI << " "
+ << (Result ? "can potentially " : "cannot ") << "reach "
+ << Ret << " [Intra]\n");
+ return !Result;
+ };
+
+ // Check if we can reach returns.
+ bool UsedAssumedInformation = false;
+ if (A.checkForAllInstructions(ReturnInstCB, FromFn, QueryingAA,
+ {Instruction::Ret}, UsedAssumedInformation)) {
+ LLVM_DEBUG(dbgs() << "[AA] No return is reachable, done\n");
+ return false;
+ }
+
+ if (!GoBackwardsCB) {
+ LLVM_DEBUG(dbgs() << "[AA] check @" << ToFn.getName() << " from " << FromI
+ << " is not checked backwards, abort\n");
return true;
+ }
// If we do not go backwards from the FromFn we are done here and so far we
// could not find a way to reach ToFn/ToI.
@@ -644,7 +695,6 @@ isPotentiallyReachable(Attributor &A, const Instruction &FromI,
return true;
};
- bool UsedAssumedInformation = false;
Result = !A.checkForAllCallSites(CheckCallSite, *FromFn,
/* RequireAllCallSites */ true,
&QueryingAA, UsedAssumedInformation);
@@ -665,20 +715,20 @@ isPotentiallyReachable(Attributor &A, const Instruction &FromI,
bool AA::isPotentiallyReachable(
Attributor &A, const Instruction &FromI, const Instruction &ToI,
const AbstractAttribute &QueryingAA,
+ const AA::InstExclusionSetTy *ExclusionSet,
std::function<bool(const Function &F)> GoBackwardsCB) {
- LLVM_DEBUG(dbgs() << "[AA] isPotentiallyReachable " << ToI << " from "
- << FromI << " [GBCB: " << bool(GoBackwardsCB) << "]\n");
const Function *ToFn = ToI.getFunction();
return ::isPotentiallyReachable(A, FromI, &ToI, *ToFn, QueryingAA,
- GoBackwardsCB);
+ ExclusionSet, GoBackwardsCB);
}
bool AA::isPotentiallyReachable(
Attributor &A, const Instruction &FromI, const Function &ToFn,
const AbstractAttribute &QueryingAA,
+ const AA::InstExclusionSetTy *ExclusionSet,
std::function<bool(const Function &F)> GoBackwardsCB) {
return ::isPotentiallyReachable(A, FromI, /* ToI */ nullptr, ToFn, QueryingAA,
- GoBackwardsCB);
+ ExclusionSet, GoBackwardsCB);
}
bool AA::isAssumedThreadLocalObject(Attributor &A, Value &Obj,
diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
index 6223f565ee1bc..ba6afa46bc057 100644
--- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
+++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
@@ -172,7 +172,7 @@ PIPE_OPERATOR(AANoCapture)
PIPE_OPERATOR(AAValueSimplify)
PIPE_OPERATOR(AANoFree)
PIPE_OPERATOR(AAHeapToStack)
-PIPE_OPERATOR(AAReachability)
+PIPE_OPERATOR(AAIntraFnReachability)
PIPE_OPERATOR(AAMemoryBehavior)
PIPE_OPERATOR(AAMemoryLocation)
PIPE_OPERATOR(AAValueConstantRange)
@@ -182,7 +182,7 @@ PIPE_OPERATOR(AAPotentialConstantValues)
PIPE_OPERATOR(AAPotentialValues)
PIPE_OPERATOR(AANoUndef)
PIPE_OPERATOR(AACallEdges)
-PIPE_OPERATOR(AAFunctionReachability)
+PIPE_OPERATOR(AAInterFnReachability)
PIPE_OPERATOR(AAPointerInfo)
PIPE_OPERATOR(AAAssumptionInfo)
PIPE_OPERATOR(AAUnderlyingObjects)
@@ -1127,7 +1127,16 @@ struct AAPointerInfoImpl
};
}
+ // Set of accesses/instructions that will overwrite the result and are
+ // therefore blockers in the reachability traversal.
+ AA::InstExclusionSetTy ExclusionSet;
+
auto AccessCB = [&](const Access &Acc, bool Exact) {
+ if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &I) {
+ if (Acc.isWrite() || (isa<LoadInst>(I) && Acc.isWriteOrAssumption()))
+ ExclusionSet.insert(Acc.getRemoteInst());
+ }
+
if ((!FindInterferingWrites || !Acc.isWriteOrAssumption()) &&
(!FindInterferingReads || !Acc.isRead()))
return true;
@@ -1161,11 +1170,11 @@ struct AAPointerInfoImpl
if (!IsSameThreadAsInst(Acc))
return false;
if ((!Acc.isWriteOrAssumption() ||
- !AA::isPotentiallyReachable(A, *Acc.getLocalInst(), I, QueryingAA,
- IsLiveInCalleeCB)) &&
+ !AA::isPotentiallyReachable(A, *Acc.getRemoteInst(), I, QueryingAA,
+ &ExclusionSet, IsLiveInCalleeCB)) &&
(!Acc.isRead() ||
- !AA::isPotentiallyReachable(A, I, *Acc.getLocalInst(), QueryingAA,
- IsLiveInCalleeCB)))
+ !AA::isPotentiallyReachable(A, I, *Acc.getRemoteInst(), QueryingAA,
+ &ExclusionSet, IsLiveInCalleeCB)))
return true;
if (!DT || !UseDominanceReasoning)
@@ -2765,9 +2774,9 @@ struct AANoRecurseFunction final : AANoRecurseImpl {
return ChangeStatus::UNCHANGED;
}
- const AAFunctionReachability &EdgeReachability =
- A.getAAFor<AAFunctionReachability>(*this, getIRPosition(),
- DepClassTy::REQUIRED);
+ const AAInterFnReachability &EdgeReachability =
+ A.getAAFor<AAInterFnReachability>(*this, getIRPosition(),
+ DepClassTy::REQUIRED);
if (EdgeReachability.canReach(A, *getAnchorScope()))
return indicatePessimisticFixpoint();
return ChangeStatus::UNCHANGED;
@@ -3280,30 +3289,245 @@ struct AAWillReturnCallSite final : AAWillReturnImpl {
};
} // namespace
-/// -------------------AAReachability Attribute--------------------------
+/// -------------------AAIntraFnReachability Attribute--------------------------
+
+/// All information associated with a reachability query. This boilerplate code
+/// is used by both AAIntraFnReachability and AAInterFnReachability, with
+///
diff erent \p ToTy values.
+template <typename ToTy> struct ReachabilityQueryInfo {
+ enum class Reachable {
+ No,
+ Yes,
+ };
+
+ /// Start here,
+ const Instruction *From = nullptr;
+ /// reach this place,
+ const ToTy *To = nullptr;
+ /// without going through any of these instructions,
+ const AA::InstExclusionSetTy *ExclusionSet = nullptr;
+ /// and remember if it worked:
+ Reachable Result = Reachable::No;
+
+ ReachabilityQueryInfo(const Instruction *From, const ToTy *To)
+ : From(From), To(To) {}
+
+ /// Constructor replacement to ensure unique and stable sets are used for the
+ /// cache.
+ ReachabilityQueryInfo(Attributor &A, const Instruction &From, const ToTy &To,
+ const AA::InstExclusionSetTy *ES)
+ : From(&From), To(&To), ExclusionSet(ES) {
+
+ if (ExclusionSet && !ExclusionSet->empty()) {
+ ExclusionSet =
+ A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ExclusionSet);
+ } else {
+ ExclusionSet = nullptr;
+ }
+ }
+
+ ReachabilityQueryInfo(const ReachabilityQueryInfo &RQI)
+ : From(RQI.From), To(RQI.To), ExclusionSet(RQI.ExclusionSet) {
+ assert(RQI.Result == Reachable::No &&
+ "Didn't expect to copy an explored RQI!");
+ }
+};
+
+namespace llvm {
+template <typename ToTy> struct DenseMapInfo<ReachabilityQueryInfo<ToTy> *> {
+ using InstSetDMI = DenseMapInfo<const AA::InstExclusionSetTy *>;
+ using PairDMI = DenseMapInfo<std::pair<const Instruction *, const ToTy *>>;
+
+ static ReachabilityQueryInfo<ToTy> EmptyKey;
+ static ReachabilityQueryInfo<ToTy> TombstoneKey;
+
+ static inline ReachabilityQueryInfo<ToTy> *getEmptyKey() { return &EmptyKey; }
+ static inline ReachabilityQueryInfo<ToTy> *getTombstoneKey() {
+ return &TombstoneKey;
+ }
+ static unsigned getHashValue(const ReachabilityQueryInfo<ToTy> *RQI) {
+ unsigned H = PairDMI ::getHashValue({RQI->From, RQI->To});
+ H += InstSetDMI::getHashValue(RQI->ExclusionSet);
+ return H;
+ }
+ static bool isEqual(const ReachabilityQueryInfo<ToTy> *LHS,
+ const ReachabilityQueryInfo<ToTy> *RHS) {
+ if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))
+ return false;
+ return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);
+ }
+};
+
+#define DefineKeys(ToTy) \
+ template <> \
+ ReachabilityQueryInfo<ToTy> \
+ DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::EmptyKey = \
+ ReachabilityQueryInfo<ToTy>( \
+ DenseMapInfo<const Instruction *>::getEmptyKey(), \
+ DenseMapInfo<const ToTy *>::getEmptyKey()); \
+ template <> \
+ ReachabilityQueryInfo<ToTy> \
+ DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::TombstoneKey = \
+ ReachabilityQueryInfo<ToTy>( \
+ DenseMapInfo<const Instruction *>::getTombstoneKey(), \
+ DenseMapInfo<const ToTy *>::getTombstoneKey());
+
+DefineKeys(Instruction) DefineKeys(Function)
+#undef DefineKeys
+
+} // namespace llvm
namespace {
-struct AAReachabilityImpl : AAReachability {
- AAReachabilityImpl(const IRPosition &IRP, Attributor &A)
- : AAReachability(IRP, A) {}
+
+template <typename BaseTy, typename ToTy>
+struct CachedReachabilityAA : public BaseTy {
+ using RQITy = ReachabilityQueryInfo<ToTy>;
+
+ CachedReachabilityAA<BaseTy, ToTy>(const IRPosition &IRP, Attributor &A)
+ : BaseTy(IRP, A) {}
+
+ /// See AbstractAttribute::isQueryAA.
+ bool isQueryAA() const override { return true; }
+
+ /// See AbstractAttribute::updateImpl(...).
+ ChangeStatus updateImpl(Attributor &A) override {
+ ChangeStatus Changed = ChangeStatus::UNCHANGED;
+ InUpdate = true;
+ for (RQITy *RQI : QueryVector) {
+ if (RQI->Result == RQITy::Reachable::No && isReachableImpl(A, *RQI))
+ Changed = ChangeStatus::CHANGED;
+ }
+ InUpdate = false;
+ return Changed;
+ }
+
+ virtual bool isReachableImpl(Attributor &A, RQITy &RQI) = 0;
+
+ bool rememberResult(Attributor &A, typename RQITy::Reachable Result,
+ RQITy &RQI) {
+ if (Result == RQITy::Reachable::No) {
+ if (!InUpdate)
+ A.registerForUpdate(*this);
+ return false;
+ }
+ assert(RQI.Result == RQITy::Reachable::No && "Already reachable?");
+ RQI.Result = Result;
+ return true;
+ }
const std::string getAsStr() const override {
// TODO: Return the number of reachable queries.
- return "reachable";
+ return "#queries(" + std::to_string(QueryVector.size()) + ")";
}
- /// See AbstractAttribute::updateImpl(...).
- ChangeStatus updateImpl(Attributor &A) override {
- return ChangeStatus::UNCHANGED;
+ RQITy *checkQueryCache(Attributor &A, RQITy &StackRQI,
+ typename RQITy::Reachable &Result) {
+ if (!this->getState().isValidState()) {
+ Result = RQITy::Reachable::Yes;
+ return nullptr;
+ }
+
+ auto It = QueryCache.find(&StackRQI);
+ if (It != QueryCache.end()) {
+ Result = (*It)->Result;
+ return nullptr;
+ }
+
+ RQITy *RQIPtr = new (A.Allocator) RQITy(StackRQI);
+ QueryVector.push_back(RQIPtr);
+ QueryCache.insert(RQIPtr);
+ return RQIPtr;
}
+
+private:
+ bool InUpdate = false;
+ SmallVector<RQITy *> QueryVector;
+ DenseSet<RQITy *> QueryCache;
};
-struct AAReachabilityFunction final : public AAReachabilityImpl {
- AAReachabilityFunction(const IRPosition &IRP, Attributor &A)
- : AAReachabilityImpl(IRP, A) {}
+struct AAIntraFnReachabilityFunction final
+ : public CachedReachabilityAA<AAIntraFnReachability, Instruction> {
+ AAIntraFnReachabilityFunction(const IRPosition &IRP, Attributor &A)
+ : CachedReachabilityAA<AAIntraFnReachability, Instruction>(IRP, A) {}
+
+ bool isAssumedReachable(
+ Attributor &A, const Instruction &From, const Instruction &To,
+ const AA::InstExclusionSetTy *ExclusionSet) const override {
+ auto *NonConstThis = const_cast<AAIntraFnReachabilityFunction *>(this);
+ if (&From == &To)
+ return true;
+
+ RQITy StackRQI(A, From, To, ExclusionSet);
+ typename RQITy::Reachable Result;
+ if (RQITy *RQIPtr = NonConstThis->checkQueryCache(A, StackRQI, Result)) {
+ return NonConstThis->isReachableImpl(A, *RQIPtr);
+ }
+ return Result == RQITy::Reachable::Yes;
+ }
+
+ bool isReachableImpl(Attributor &A, RQITy &RQI) override {
+ const Instruction *Origin = RQI.From;
+
+ auto WillReachInBlock = [=](const Instruction &From, const Instruction &To,
+ const AA::InstExclusionSetTy *ExclusionSet) {
+ const Instruction *IP = &From;
+ while (IP && IP != &To) {
+ if (ExclusionSet && IP != Origin && ExclusionSet->count(IP))
+ break;
+ IP = IP->getNextNode();
+ }
+ return IP == &To;
+ };
+
+ const BasicBlock *FromBB = RQI.From->getParent();
+ const BasicBlock *ToBB = RQI.To->getParent();
+ assert(FromBB->getParent() == ToBB->getParent() &&
+ "Not an intra-procedural query!");
+
+ // Check intra-block reachability, however, other reaching paths are still
+ // possible.
+ if (FromBB == ToBB &&
+ WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))
+ return rememberResult(A, RQITy::Reachable::Yes, RQI);
+
+ SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;
+ if (RQI.ExclusionSet)
+ for (auto *I : *RQI.ExclusionSet)
+ ExclusionBlocks.insert(I->getParent());
+
+ // Check if we make it out of the FromBB block at all.
+ if (ExclusionBlocks.count(FromBB) &&
+ !WillReachInBlock(*RQI.From, *FromBB->getTerminator(),
+ RQI.ExclusionSet))
+ return rememberResult(A, RQITy::Reachable::No, RQI);
+
+ SmallPtrSet<const BasicBlock *, 16> Visited;
+ SmallVector<const BasicBlock *, 16> Worklist;
+ Worklist.push_back(FromBB);
+
+ auto &LivenessAA =
+ A.getAAFor<AAIsDead>(*this, getIRPosition(), DepClassTy::OPTIONAL);
+ while (!Worklist.empty()) {
+ const BasicBlock *BB = Worklist.pop_back_val();
+ if (!Visited.insert(BB).second)
+ continue;
+ for (const BasicBlock *SuccBB : successors(BB)) {
+ if (LivenessAA.isEdgeDead(BB, SuccBB))
+ continue;
+ if (SuccBB == ToBB &&
+ WillReachInBlock(SuccBB->front(), *RQI.To, RQI.ExclusionSet))
+ return rememberResult(A, RQITy::Reachable::Yes, RQI);
+ if (ExclusionBlocks.count(SuccBB))
+ continue;
+ Worklist.push_back(SuccBB);
+ }
+ }
+
+ return rememberResult(A, RQITy::Reachable::No, RQI);
+ }
/// See AbstractAttribute::trackStatistics()
- void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(reachable); }
+ void trackStatistics() const override {}
};
} // namespace
@@ -3546,7 +3770,7 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl {
}
if (!AA::isPotentiallyReachable(
- A, *UserI, *getCtxI(), *this,
+ A, *UserI, *getCtxI(), *this, /* ExclusionSet */ nullptr,
[ScopeFn](const Function &Fn) { return &Fn != ScopeFn; }))
return true;
}
@@ -5175,7 +5399,7 @@ struct AAInstanceInfoImpl : public AAInstanceInfo {
// If this call base might reach the scope again we might forward the
// argument back here. This is very conservative.
if (AA::isPotentiallyReachable(
- A, *CB, *Scope, *this,
+ A, *CB, *Scope, *this, /* ExclusionSet */ nullptr,
[Scope](const Function &Fn) { return &Fn != Scope; }))
return false;
return true;
@@ -9921,289 +10145,98 @@ struct AACallEdgesFunction : public AACallEdgesImpl {
}
};
-struct AAFunctionReachabilityFunction : public AAFunctionReachability {
-private:
- struct QuerySet {
- void markReachable(const Function &Fn) {
- Reachable.insert(&Fn);
- Unreachable.erase(&Fn);
- }
+/// -------------------AAInterFnReachability Attribute--------------------------
- /// If there is no information about the function std::nullopt is returned.
- std::optional<bool> isCachedReachable(const Function &Fn) {
- // Assume that we can reach the function.
- // TODO: Be more specific with the unknown callee.
- if (CanReachUnknownCallee)
- return true;
+struct AAInterFnReachabilityFunction
+ : public CachedReachabilityAA<AAInterFnReachability, Function> {
+ AAInterFnReachabilityFunction(const IRPosition &IRP, Attributor &A)
+ : CachedReachabilityAA<AAInterFnReachability, Function>(IRP, A) {}
- if (Reachable.count(&Fn))
- return true;
+ bool instructionCanReach(
+ Attributor &A, const Instruction &From, const Function &To,
+ const AA::InstExclusionSetTy *ExclusionSet,
+ SmallPtrSet<const Function *, 16> *Visited) const override {
+ assert(From.getFunction() == getAnchorScope() && "Queried the wrong AA!");
+ auto *NonConstThis = const_cast<AAInterFnReachabilityFunction *>(this);
- if (Unreachable.count(&Fn))
- return false;
-
- return std::nullopt;
- }
-
- /// Set of functions that we know for sure is reachable.
- DenseSet<const Function *> Reachable;
-
- /// Set of functions that are unreachable, but might become reachable.
- DenseSet<const Function *> Unreachable;
-
- /// If we can reach a function with a call to a unknown function we assume
- /// that we can reach any function.
- bool CanReachUnknownCallee = false;
- };
-
- struct QueryResolver : public QuerySet {
- ChangeStatus update(Attributor &A, const AAFunctionReachability &AA,
- ArrayRef<const AACallEdges *> AAEdgesList) {
- ChangeStatus Change = ChangeStatus::UNCHANGED;
-
- for (const auto *AAEdges : AAEdgesList) {
- if (AAEdges->hasUnknownCallee()) {
- if (!CanReachUnknownCallee) {
- LLVM_DEBUG(dbgs()
- << "[QueryResolver] Edges include unknown callee!\n");
- Change = ChangeStatus::CHANGED;
- }
- CanReachUnknownCallee = true;
- return Change;
- }
- }
-
- for (const Function *Fn : make_early_inc_range(Unreachable)) {
- if (checkIfReachable(A, AA, AAEdgesList, *Fn)) {
- Change = ChangeStatus::CHANGED;
- markReachable(*Fn);
- }
- }
- return Change;
- }
-
- bool isReachable(Attributor &A, AAFunctionReachability &AA,
- ArrayRef<const AACallEdges *> AAEdgesList,
- const Function &Fn) {
- std::optional<bool> Cached = isCachedReachable(Fn);
- if (Cached)
- return *Cached;
-
- // The query was not cached, thus it is new. We need to request an update
- // explicitly to make sure this the information is properly run to a
- // fixpoint.
- A.registerForUpdate(AA);
-
- // We need to assume that this function can't reach Fn to prevent
- // an infinite loop if this function is recursive.
- Unreachable.insert(&Fn);
-
- bool Result = checkIfReachable(A, AA, AAEdgesList, Fn);
- if (Result)
- markReachable(Fn);
- return Result;
- }
-
- bool checkIfReachable(Attributor &A, const AAFunctionReachability &AA,
- ArrayRef<const AACallEdges *> AAEdgesList,
- const Function &Fn) const {
-
- // Handle the most trivial case first.
- for (const auto *AAEdges : AAEdgesList) {
- const SetVector<Function *> &Edges = AAEdges->getOptimisticEdges();
-
- if (Edges.count(const_cast<Function *>(&Fn)))
- return true;
- }
-
- SmallVector<const AAFunctionReachability *, 8> Deps;
- for (const auto &AAEdges : AAEdgesList) {
- const SetVector<Function *> &Edges = AAEdges->getOptimisticEdges();
-
- for (Function *Edge : Edges) {
- // Functions that do not call back into the module can be ignored.
- if (Edge->hasFnAttribute(Attribute::NoCallback))
- continue;
+ RQITy StackRQI(A, From, To, ExclusionSet);
+ typename RQITy::Reachable Result;
+ if (RQITy *RQIPtr = NonConstThis->checkQueryCache(A, StackRQI, Result))
+ return NonConstThis->isReachableImpl(A, *RQIPtr);
+ return Result == RQITy::Reachable::Yes;
+ }
- // We don't need a dependency if the result is reachable.
- const AAFunctionReachability &EdgeReachability =
- A.getAAFor<AAFunctionReachability>(
- AA, IRPosition::function(*Edge), DepClassTy::NONE);
- Deps.push_back(&EdgeReachability);
+ bool isReachableImpl(Attributor &A, RQITy &RQI) override {
+ return isReachableImpl(A, RQI, nullptr);
+ }
- if (EdgeReachability.canReach(A, Fn))
- return true;
- }
- }
+ bool isReachableImpl(Attributor &A, RQITy &RQI,
+ SmallPtrSet<const Function *, 16> *Visited) {
- // The result is false for now, set dependencies and leave.
- for (const auto *Dep : Deps)
- A.recordDependence(*Dep, AA, DepClassTy::REQUIRED);
+ SmallPtrSet<const Function *, 16> LocalVisited;
+ if (!Visited)
+ Visited = &LocalVisited;
- return false;
- }
- };
+ const auto &IntraFnReachability = A.getAAFor<AAIntraFnReachability>(
+ *this, IRPosition::function(*RQI.From->getFunction()),
+ DepClassTy::OPTIONAL);
- /// Get call edges that can be reached by this instruction.
- bool getReachableCallEdges(Attributor &A, const AAReachability &Reachability,
- const Instruction &Inst,
- SmallVector<const AACallEdges *> &Result) const {
// Determine call like instructions that we can reach from the inst.
+ SmallVector<CallBase *> ReachableCallBases;
auto CheckCallBase = [&](Instruction &CBInst) {
- if (!Reachability.isAssumedReachable(A, Inst, CBInst))
- return true;
-
- auto &CB = cast<CallBase>(CBInst);
- const AACallEdges &AAEdges = A.getAAFor<AACallEdges>(
- *this, IRPosition::callsite_function(CB), DepClassTy::REQUIRED);
-
- Result.push_back(&AAEdges);
+ if (IntraFnReachability.isAssumedReachable(A, *RQI.From, CBInst,
+ RQI.ExclusionSet))
+ ReachableCallBases.push_back(cast<CallBase>(&CBInst));
return true;
};
bool UsedAssumedInformation = false;
- return A.checkForAllCallLikeInstructions(CheckCallBase, *this,
- UsedAssumedInformation,
- /* CheckBBLivenessOnly */ true);
- }
-
-public:
- AAFunctionReachabilityFunction(const IRPosition &IRP, Attributor &A)
- : AAFunctionReachability(IRP, A) {}
-
- bool canReach(Attributor &A, const Function &Fn) const override {
- if (!isValidState())
- return true;
-
- const AACallEdges &AAEdges =
- A.getAAFor<AACallEdges>(*this, getIRPosition(), DepClassTy::REQUIRED);
-
- // Attributor returns attributes as const, so this function has to be
- // const for users of this attribute to use it without having to do
- // a const_cast.
- // This is a hack for us to be able to cache queries.
- auto *NonConstThis = const_cast<AAFunctionReachabilityFunction *>(this);
- bool Result = NonConstThis->WholeFunction.isReachable(A, *NonConstThis,
- {&AAEdges}, Fn);
-
- return Result;
- }
-
- /// Can \p CB reach \p Fn
- bool canReach(Attributor &A, CallBase &CB,
- const Function &Fn) const override {
- if (!isValidState())
- return true;
-
- const AACallEdges &AAEdges = A.getAAFor<AACallEdges>(
- *this, IRPosition::callsite_function(CB), DepClassTy::REQUIRED);
-
- // Attributor returns attributes as const, so this function has to be
- // const for users of this attribute to use it without having to do
- // a const_cast.
- // This is a hack for us to be able to cache queries.
- auto *NonConstThis = const_cast<AAFunctionReachabilityFunction *>(this);
- QueryResolver &CBQuery = NonConstThis->CBQueries[&CB];
-
- bool Result = CBQuery.isReachable(A, *NonConstThis, {&AAEdges}, Fn);
-
- return Result;
- }
-
- bool instructionCanReach(Attributor &A, const Instruction &Inst,
- const Function &Fn) const override {
- if (!isValidState())
- return true;
-
- const auto &Reachability = A.getAAFor<AAReachability>(
- *this, IRPosition::function(*getAssociatedFunction()),
- DepClassTy::REQUIRED);
-
- SmallVector<const AACallEdges *> CallEdges;
- bool AllKnown = getReachableCallEdges(A, Reachability, Inst, CallEdges);
- // Attributor returns attributes as const, so this function has to be
- // const for users of this attribute to use it without having to do
- // a const_cast.
- // This is a hack for us to be able to cache queries.
- auto *NonConstThis = const_cast<AAFunctionReachabilityFunction *>(this);
- QueryResolver &InstQSet = NonConstThis->InstQueries[&Inst];
- if (!AllKnown) {
- LLVM_DEBUG(dbgs() << "[AAReachability] Not all reachable edges known, "
- "may reach unknown callee!\n");
- InstQSet.CanReachUnknownCallee = true;
- }
-
- return InstQSet.isReachable(A, *NonConstThis, CallEdges, Fn);
- }
-
- /// See AbstractAttribute::updateImpl(...).
- ChangeStatus updateImpl(Attributor &A) override {
- const AACallEdges &AAEdges =
- A.getAAFor<AACallEdges>(*this, getIRPosition(), DepClassTy::REQUIRED);
- ChangeStatus Change = ChangeStatus::UNCHANGED;
-
- Change |= WholeFunction.update(A, *this, {&AAEdges});
+ if (!A.checkForAllCallLikeInstructions(CheckCallBase, *this,
+ UsedAssumedInformation,
+ /* CheckBBLivenessOnly */ true))
+ return rememberResult(A, RQITy::Reachable::Yes, RQI);
- for (auto &CBPair : CBQueries) {
- const AACallEdges &AAEdges = A.getAAFor<AACallEdges>(
- *this, IRPosition::callsite_function(*CBPair.first),
- DepClassTy::REQUIRED);
+ for (CallBase *CB : ReachableCallBases) {
+ auto &CBEdges = A.getAAFor<AACallEdges>(
+ *this, IRPosition::callsite_function(*CB), DepClassTy::OPTIONAL);
+ if (!CBEdges.getState().isValidState())
+ return rememberResult(A, RQITy::Reachable::Yes, RQI);
+ // TODO Check To backwards in this case.
+ if (CBEdges.hasUnknownCallee())
+ return rememberResult(A, RQITy::Reachable::Yes, RQI);
- Change |= CBPair.second.update(A, *this, {&AAEdges});
- }
+ for (Function *Fn : CBEdges.getOptimisticEdges()) {
+ if (Fn == RQI.To)
+ return rememberResult(A, RQITy::Reachable::Yes, RQI);
+ if (!Visited->insert(Fn).second)
+ continue;
+ if (Fn->isDeclaration()) {
+ if (Fn->hasFnAttribute(Attribute::NoCallback))
+ continue;
+ // TODO Check To backwards in this case.
+ return rememberResult(A, RQITy::Reachable::Yes, RQI);
+ }
- // Update the Instruction queries.
- if (!InstQueries.empty()) {
- const AAReachability *Reachability = &A.getAAFor<AAReachability>(
- *this, IRPosition::function(*getAssociatedFunction()),
- DepClassTy::REQUIRED);
+ const AAInterFnReachability *InterFnReachability = this;
+ if (Fn != getAnchorScope())
+ InterFnReachability = &A.getAAFor<AAInterFnReachability>(
+ *this, IRPosition::function(*Fn), DepClassTy::OPTIONAL);
- // Check for local callbases first.
- for (auto &InstPair : InstQueries) {
- SmallVector<const AACallEdges *> CallEdges;
- bool AllKnown =
- getReachableCallEdges(A, *Reachability, *InstPair.first, CallEdges);
- // Update will return change if we this effects any queries.
- if (!AllKnown) {
- LLVM_DEBUG(dbgs() << "[AAReachability] Not all reachable edges "
- "known, may reach unknown callee!\n");
- InstPair.second.CanReachUnknownCallee = true;
- }
- Change |= InstPair.second.update(A, *this, CallEdges);
+ const Instruction &FnFirstInst = Fn->getEntryBlock().front();
+ if (InterFnReachability->instructionCanReach(A, FnFirstInst, *RQI.To,
+ RQI.ExclusionSet, Visited))
+ return rememberResult(A, RQITy::Reachable::Yes, RQI);
}
}
- return Change;
- }
-
- const std::string getAsStr() const override {
- size_t QueryCount =
- WholeFunction.Reachable.size() + WholeFunction.Unreachable.size();
-
- return "FunctionReachability [" +
- (canReachUnknownCallee()
- ? "unknown"
- : (std::to_string(WholeFunction.Reachable.size()) + "," +
- std::to_string(QueryCount))) +
- "]";
+ return rememberResult(A, RQITy::Reachable::No, RQI);
}
void trackStatistics() const override {}
private:
- bool canReachUnknownCallee() const override {
- return WholeFunction.CanReachUnknownCallee;
- }
-
- /// Used to answer if a the whole function can reacha a specific function.
- QueryResolver WholeFunction;
-
- /// Used to answer if a call base inside this function can reach a specific
- /// function.
- MapVector<const CallBase *, QueryResolver> CBQueries;
-
- /// This is for instruction queries than scan "forward".
- MapVector<const Instruction *, QueryResolver> InstQueries;
+ SmallVector<RQITy *> QueryVector;
+ DenseSet<RQITy *> QueryCache;
};
} // namespace
@@ -11358,7 +11391,7 @@ const char AANoRecurse::ID = 0;
const char AAWillReturn::ID = 0;
const char AAUndefinedBehavior::ID = 0;
const char AANoAlias::ID = 0;
-const char AAReachability::ID = 0;
+const char AAIntraFnReachability::ID = 0;
const char AANoReturn::ID = 0;
const char AAIsDead::ID = 0;
const char AADereferenceable::ID = 0;
@@ -11375,7 +11408,7 @@ const char AAPotentialConstantValues::ID = 0;
const char AAPotentialValues::ID = 0;
const char AANoUndef::ID = 0;
const char AACallEdges::ID = 0;
-const char AAFunctionReachability::ID = 0;
+const char AAInterFnReachability::ID = 0;
const char AAPointerInfo::ID = 0;
const char AAAssumptionInfo::ID = 0;
const char AAUnderlyingObjects::ID = 0;
@@ -11502,9 +11535,9 @@ CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree)
CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUnderlyingObjects)
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack)
-CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAReachability)
CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUndefinedBehavior)
-CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAFunctionReachability)
+CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIntraFnReachability)
+CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAInterFnReachability)
CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryBehavior)
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/alloca-as.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/alloca-as.ll
index 4b8672230b7ff..b9469d19f1d20 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/alloca-as.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/alloca-as.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
target datalayout = "A7"
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll
index 1910894590fd0..f9a6e4cf38d1b 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/dbg.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
declare void @sink(i32)
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll
index b57e74bfd70de..ae82f46e8c5c4 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/naked_functions.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
; Don't promote paramaters of/arguments to naked functions
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll
index 27da1aae7372e..3d7fc9f4af1df 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/nonzero-address-spaces.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
; ArgumentPromotion should preserve the default function address space
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll
index 925595c01774f..071ffebbce59e 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/pr27568.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
target triple = "x86_64-pc-windows-msvc"
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll
index 0f818f25a6fac..b9f43170cc6aa 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/profile.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll
index d80d57f4f108b..9df41e43c5de8 100644
--- a/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll
+++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/variadic.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
; Unused arguments from variadic functions cannot be eliminated as that changes
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll b/llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll
index 3e23a32d313fd..1c9acece2c2a0 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/naked-return.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll b/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll
index 8fe817505a35a..bcfe3658ca159 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/openmp_parallel_for.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=18 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=16 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
;
; void bar(int, float, double);
@@ -36,9 +36,7 @@ define dso_local void @foo(i32 %N) {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
; TUNIT-NEXT: [[P:%.*]] = alloca float, align 4
-; TUNIT-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4
-; TUNIT-NEXT: store i32 7, ptr [[N_ADDR]], align 4
-; TUNIT-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB1]], i32 noundef 3, ptr noundef @.omp_outlined., ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[N_ADDR]], ptr noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) undef, i64 undef)
+; TUNIT-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB1]], i32 noundef 3, ptr noundef @.omp_outlined., ptr noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) undef, ptr noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) undef, i64 undef)
; TUNIT-NEXT: ret void
;
; CGSCC-LABEL: define {{[^@]+}}@foo
@@ -64,7 +62,7 @@ entry:
define internal void @.omp_outlined.(ptr noalias %.global_tid., ptr noalias %.bound_tid., ptr dereferenceable(4) %N, ptr dereferenceable(4) %p, i64 %q) {
; TUNIT-LABEL: define {{[^@]+}}@.omp_outlined.
-; TUNIT-SAME: (ptr noalias nocapture nofree readonly [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[N:%.*]], ptr noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) [[P:%.*]], i64 [[Q:%.*]]) {
+; TUNIT-SAME: (ptr noalias nocapture nofree readonly [[DOTGLOBAL_TID_:%.*]], ptr noalias nocapture nofree readnone [[DOTBOUND_TID_:%.*]], ptr noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) [[N:%.*]], ptr noalias nocapture nofree nonnull readnone align 4 dereferenceable(4) [[P:%.*]], i64 [[Q:%.*]]) {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[Q_ADDR:%.*]] = alloca i64, align 8
; TUNIT-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
@@ -72,19 +70,16 @@ define internal void @.omp_outlined.(ptr noalias %.global_tid., ptr noalias %.bo
; TUNIT-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
; TUNIT-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
; TUNIT-NEXT: store i64 4617315517961601024, ptr [[Q_ADDR]], align 8
-; TUNIT-NEXT: [[TMP:%.*]] = load i32, ptr [[N]], align 4
-; TUNIT-NEXT: [[SUB3:%.*]] = add nsw i32 [[TMP]], -3
-; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP]], 2
-; TUNIT-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+; TUNIT-NEXT: br label [[OMP_PRECOND_THEN:%.*]]
; TUNIT: omp.precond.then:
; TUNIT-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-; TUNIT-NEXT: store i32 [[SUB3]], ptr [[DOTOMP_UB]], align 4
+; TUNIT-NEXT: store i32 4, ptr [[DOTOMP_UB]], align 4
; TUNIT-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
; TUNIT-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
; TUNIT-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4
; TUNIT-NEXT: call void @__kmpc_for_static_init_4(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 [[TMP5]], i32 noundef 34, ptr noundef nonnull align 4 dereferenceable(4) [[DOTOMP_IS_LAST]], ptr noundef nonnull align 4 dereferenceable(4) [[DOTOMP_LB]], ptr noundef nonnull align 4 dereferenceable(4) [[DOTOMP_UB]], ptr noundef nonnull align 4 dereferenceable(4) [[DOTOMP_STRIDE]], i32 noundef 1, i32 noundef 1)
; TUNIT-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-; TUNIT-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP6]], [[SUB3]]
+; TUNIT-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP6]], 4
; TUNIT-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
; TUNIT: cond.true:
; TUNIT-NEXT: br label [[COND_END:%.*]]
@@ -92,7 +87,7 @@ define internal void @.omp_outlined.(ptr noalias %.global_tid., ptr noalias %.bo
; TUNIT-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
; TUNIT-NEXT: br label [[COND_END]]
; TUNIT: cond.end:
-; TUNIT-NEXT: [[COND:%.*]] = phi i32 [ [[SUB3]], [[COND_TRUE]] ], [ [[TMP7]], [[COND_FALSE]] ]
+; TUNIT-NEXT: [[COND:%.*]] = phi i32 [ 4, [[COND_TRUE]] ], [ [[TMP7]], [[COND_FALSE]] ]
; TUNIT-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
; TUNIT-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
; TUNIT-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
@@ -118,7 +113,7 @@ define internal void @.omp_outlined.(ptr noalias %.global_tid., ptr noalias %.bo
; TUNIT: omp.loop.exit:
; TUNIT-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTGLOBAL_TID_]], align 4
; TUNIT-NEXT: call void @__kmpc_for_static_fini(ptr noundef nonnull align 8 dereferenceable(24) @[[GLOB0]], i32 [[TMP12]])
-; TUNIT-NEXT: br label [[OMP_PRECOND_END]]
+; TUNIT-NEXT: br label [[OMP_PRECOND_END:%.*]]
; TUNIT: omp.precond.end:
; TUNIT-NEXT: ret void
;
diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll
index 4c25fc4b63fc0..c04fe58d46cdc 100644
--- a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll
+++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=13 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=5 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
;; This function returns its second argument on all return statements
diff --git a/llvm/test/Transforms/Attributor/cgscc_bugs.ll b/llvm/test/Transforms/Attributor/cgscc_bugs.ll
index f9055980c0002..3ddab4a85c7f3 100644
--- a/llvm/test/Transforms/Attributor/cgscc_bugs.ll
+++ b/llvm/test/Transforms/Attributor/cgscc_bugs.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=6 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
diff --git a/llvm/test/Transforms/Attributor/depgraph.ll b/llvm/test/Transforms/Attributor/depgraph.ll
index fce4e246f580f..ded431294d8a0 100644
--- a/llvm/test/Transforms/Attributor/depgraph.ll
+++ b/llvm/test/Transforms/Attributor/depgraph.ll
@@ -146,9 +146,9 @@ define ptr @checkAndAdvance(ptr align 16 %0) {
; GRAPH-EMPTY:
; GRAPH-NEXT: [AANoRecurse] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn:checkAndAdvance [checkAndAdvance at -1]} with state may-recurse
; GRAPH-EMPTY:
-; GRAPH-NEXT: [AAFunctionReachability] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn:checkAndAdvance [checkAndAdvance at -1]} with state FunctionReachability [1,1]
+; GRAPH-NEXT: [AAInterFnReachability] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn:checkAndAdvance [checkAndAdvance at -1]} with state #queries(1)
; GRAPH-EMPTY:
-; GRAPH-NEXT: [AACallEdges] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn:checkAndAdvance [checkAndAdvance at -1]} with state CallEdges[0,1]
+; GRAPH-NEXT: [AAIntraFnReachability] for CtxI ' %2 = load i32, ptr %0, align 4' at position {fn:checkAndAdvance [checkAndAdvance at -1]} with state #queries(1)
; GRAPH-EMPTY:
; GRAPH-NEXT: [AACallEdges] for CtxI ' %6 = call ptr @checkAndAdvance(ptr %5)' at position {cs: [@-1]} with state CallEdges[0,1]
; GRAPH-EMPTY:
@@ -304,8 +304,8 @@ define ptr @checkAndAdvance(ptr align 16 %0) {
; DOT-DAG: Node[[Node26:0x[a-z0-9]+]] [shape=record,label="{[AAPotentialValues]
; DOT-DAG: Node[[Node27:0x[a-z0-9]+]] [shape=record,label="{[AAInstanceInfo]
; DOT-DAG: Node[[Node28:0x[a-z0-9]+]] [shape=record,label="{[AANoRecurse]
-; DOT-DAG: Node[[Node29:0x[a-z0-9]+]] [shape=record,label="{[AAFunctionReachability]
-; DOT-DAG: Node[[Node30:0x[a-z0-9]+]] [shape=record,label="{[AACallEdges]
+; DOT-DAG: Node[[Node29:0x[a-z0-9]+]] [shape=record,label="{[AAInterFnReachability]
+; DOT-DAG: Node[[Node30:0x[a-z0-9]+]] [shape=record,label="{[AAIntraFnReachability]
; DOT-DAG: Node[[Node31:0x[a-z0-9]+]] [shape=record,label="{[AACallEdges]
; DOT-DAG: Node[[Node32:0x[a-z0-9]+]] [shape=record,label="{[AAIsDead]
; DOT-DAG: Node[[Node33:0x[a-z0-9]+]] [shape=record,label="{[AAWillReturn]
diff --git a/llvm/test/Transforms/Attributor/internal-noalias.ll b/llvm/test/Transforms/Attributor/internal-noalias.ll
index 40ea982276775..29d3f27fa5d3e 100644
--- a/llvm/test/Transforms/Attributor/internal-noalias.ll
+++ b/llvm/test/Transforms/Attributor/internal-noalias.ll
@@ -7,8 +7,8 @@ define dso_local i32 @visible(ptr noalias %A, ptr noalias %B) #0 {
; TUNIT-LABEL: define {{[^@]+}}@visible
; TUNIT-SAME: (ptr noalias nocapture nofree readonly [[A:%.*]], ptr noalias nocapture nofree readonly align 4 [[B:%.*]]) #[[ATTR0:[0-9]+]] {
; TUNIT-NEXT: entry:
-; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @noalias_args(ptr noalias nocapture nofree readonly align 4 [[A]], ptr noalias nocapture nofree readonly align 4 [[B]]) #[[ATTR3:[0-9]+]]
-; TUNIT-NEXT: [[CALL2:%.*]] = call i32 @noalias_args_argmem(ptr noalias nocapture nofree readonly align 4 [[A]], ptr noalias nocapture nofree readonly align 4 [[B]]) #[[ATTR3]]
+; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @noalias_args(ptr noalias nocapture nofree readonly align 4 [[A]], ptr noalias nocapture nofree readonly align 4 [[B]]) #[[ATTR4:[0-9]+]]
+; TUNIT-NEXT: [[CALL2:%.*]] = call i32 @noalias_args_argmem(ptr noalias nocapture nofree readonly align 4 [[A]], ptr noalias nocapture nofree readonly align 4 [[B]]) #[[ATTR4]]
; TUNIT-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[CALL2]]
; TUNIT-NEXT: ret i32 [[ADD]]
;
@@ -36,7 +36,7 @@ define private i32 @noalias_args(ptr %A, ptr %B) #0 {
; TUNIT-NEXT: [[TMP0:%.*]] = load i32, ptr [[A]], align 4
; TUNIT-NEXT: [[TMP1:%.*]] = load i32, ptr [[B]], align 4
; TUNIT-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP0]], [[TMP1]]
-; TUNIT-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[B]]) #[[ATTR3]]
+; TUNIT-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem(ptr nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[A]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[B]]) #[[ATTR4]]
; TUNIT-NEXT: [[ADD2:%.*]] = add nsw i32 [[ADD]], [[CALL]]
; TUNIT-NEXT: ret i32 [[ADD2]]
;
@@ -94,8 +94,8 @@ define dso_local i32 @visible_local(ptr %A) #0 {
; TUNIT-NEXT: entry:
; TUNIT-NEXT: [[B:%.*]] = alloca i32, align 4
; TUNIT-NEXT: store i32 5, ptr [[B]], align 4
-; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @noalias_args(ptr nocapture nofree readonly align 4 [[A]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[B]]) #[[ATTR3]]
-; TUNIT-NEXT: [[CALL2:%.*]] = call i32 @noalias_args_argmem(ptr nocapture nofree readonly align 4 [[A]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[B]]) #[[ATTR3]]
+; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @noalias_args(ptr nocapture nofree readonly align 4 [[A]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[B]]) #[[ATTR4]]
+; TUNIT-NEXT: [[CALL2:%.*]] = call i32 @noalias_args_argmem(ptr nocapture nofree readonly align 4 [[A]], ptr noalias nocapture nofree noundef nonnull readonly align 4 dereferenceable(4) [[B]]) #[[ATTR4]]
; TUNIT-NEXT: [[ADD:%.*]] = add nsw i32 [[CALL1]], [[CALL2]]
; TUNIT-NEXT: ret i32 [[ADD]]
;
@@ -158,11 +158,10 @@ define i32 @visible_local_2() {
}
define internal i32 @noalias_args_argmem_rn(ptr %A, ptr %B) #1 {
-; TUNIT: Function Attrs: nofree noinline norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
+; TUNIT: Function Attrs: nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable
; TUNIT-LABEL: define {{[^@]+}}@noalias_args_argmem_rn
-; TUNIT-SAME: (ptr noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1]] {
-; TUNIT-NEXT: [[T0:%.*]] = load i32, ptr [[B]], align 4
-; TUNIT-NEXT: ret i32 [[T0]]
+; TUNIT-SAME: (ptr noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR3:[0-9]+]] {
+; TUNIT-NEXT: ret i32 undef
;
; CGSCC: Function Attrs: nofree noinline norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable
; CGSCC-LABEL: define {{[^@]+}}@noalias_args_argmem_rn
@@ -181,9 +180,8 @@ define i32 @visible_local_3() {
; TUNIT-LABEL: define {{[^@]+}}@visible_local_3
; TUNIT-SAME: () #[[ATTR2]] {
; TUNIT-NEXT: [[B:%.*]] = alloca i32, align 4
-; TUNIT-NEXT: store i32 5, ptr [[B]], align 4
-; TUNIT-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem_rn(ptr noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[B]]) #[[ATTR4:[0-9]+]]
-; TUNIT-NEXT: ret i32 [[CALL]]
+; TUNIT-NEXT: [[CALL:%.*]] = call i32 @noalias_args_argmem_rn(ptr noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[B]]) #[[ATTR5:[0-9]+]]
+; TUNIT-NEXT: ret i32 5
;
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
; CGSCC-LABEL: define {{[^@]+}}@visible_local_3
@@ -205,8 +203,9 @@ attributes #1 = { argmemonly noinline nounwind uwtable willreturn}
; TUNIT: attributes #[[ATTR0]] = { nofree noinline norecurse nosync nounwind willreturn memory(argmem: read) uwtable }
; TUNIT: attributes #[[ATTR1]] = { nofree noinline norecurse nosync nounwind willreturn memory(argmem: readwrite) uwtable }
; TUNIT: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind willreturn memory(none) }
-; TUNIT: attributes #[[ATTR3]] = { nofree nosync nounwind }
-; TUNIT: attributes #[[ATTR4]] = { nofree nosync nounwind willreturn }
+; TUNIT: attributes #[[ATTR3]] = { nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) uwtable }
+; TUNIT: attributes #[[ATTR4]] = { nofree nosync nounwind }
+; TUNIT: attributes #[[ATTR5]] = { nofree nosync nounwind willreturn }
;.
; CGSCC: attributes #[[ATTR0]] = { nofree noinline nosync nounwind willreturn memory(argmem: read) uwtable }
; CGSCC: attributes #[[ATTR1]] = { nofree noinline norecurse nosync nounwind willreturn memory(argmem: read) uwtable }
diff --git a/llvm/test/Transforms/Attributor/liveness_chains.ll b/llvm/test/Transforms/Attributor/liveness_chains.ll
index 7e45148343d0a..bca6434f43267 100644
--- a/llvm/test/Transforms/Attributor/liveness_chains.ll
+++ b/llvm/test/Transforms/Attributor/liveness_chains.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
; Make sure we need a single iteration to determine the chains are dead/alive.
diff --git a/llvm/test/Transforms/Attributor/lowerheap.ll b/llvm/test/Transforms/Attributor/lowerheap.ll
index 6aee51864d7ef..f98beacd466ee 100644
--- a/llvm/test/Transforms/Attributor/lowerheap.ll
+++ b/llvm/test/Transforms/Attributor/lowerheap.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -max-heap-to-stack-size=-1 -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -max-heap-to-stack-size=-1 -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -max-heap-to-stack-size=-1 -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
declare i64 @subfn(ptr) #0
diff --git a/llvm/test/Transforms/Attributor/misc.ll b/llvm/test/Transforms/Attributor/misc.ll
index 44e7f41abb58a..5a5165e9d144c 100644
--- a/llvm/test/Transforms/Attributor/misc.ll
+++ b/llvm/test/Transforms/Attributor/misc.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=3 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
;
; Mostly check we do not crash on these uses
diff --git a/llvm/test/Transforms/Attributor/noalias.ll b/llvm/test/Transforms/Attributor/noalias.ll
index dcb93fe46cc33..571038e5d76ce 100644
--- a/llvm/test/Transforms/Attributor/noalias.ll
+++ b/llvm/test/Transforms/Attributor/noalias.ll
@@ -846,7 +846,7 @@ define void @test17_caller(i32* noalias %p, i32 %c) {
; TUNIT-NEXT: tail call void @make_alias(i32* nofree writeonly [[P]]) #[[ATTR10]]
; TUNIT-NEXT: br label [[L3:%.*]]
; TUNIT: l2:
-; TUNIT-NEXT: tail call void @only_store(i32* nocapture nofree writeonly align 4 [[P]]) #[[ATTR10]]
+; TUNIT-NEXT: tail call void @only_store(i32* noalias nocapture nofree writeonly align 4 [[P]]) #[[ATTR10]]
; TUNIT-NEXT: br label [[L3]]
; TUNIT: l3:
; TUNIT-NEXT: ret void
diff --git a/llvm/test/Transforms/Attributor/noundef.ll b/llvm/test/Transforms/Attributor/noundef.ll
index ef9e13649cca5..69d637f5d977e 100644
--- a/llvm/test/Transforms/Attributor/noundef.ll
+++ b/llvm/test/Transforms/Attributor/noundef.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=2 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=1 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
declare void @unknown()
diff --git a/llvm/test/Transforms/Attributor/value-simplify-assume.ll b/llvm/test/Transforms/Attributor/value-simplify-assume.ll
index 6a2cbe6dd9003..3d42b2037cc8e 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-assume.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-assume.ll
@@ -347,7 +347,6 @@ define i1 @assume_2_nr(i1 %arg, i1 %cond) norecurse {
; TUNIT-LABEL: define {{[^@]+}}@assume_2_nr
; TUNIT-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -364,7 +363,6 @@ define i1 @assume_2_nr(i1 %arg, i1 %cond) norecurse {
; CGSCC-LABEL: define {{[^@]+}}@assume_2_nr
; CGSCC-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; CGSCC-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
; CGSCC-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; CGSCC: t:
; CGSCC-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -424,9 +422,6 @@ define i1 @assume_3_nr(i1 %arg, i1 %cond) norecurse {
; TUNIT-LABEL: define {{[^@]+}}@assume_3_nr
; TUNIT-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
-; TUNIT-NEXT: [[L:%.*]] = load i1, ptr [[STACK]], align 1
-; TUNIT-NEXT: call void @llvm.assume(i1 noundef [[L]]) #[[ATTR6]]
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -477,7 +472,6 @@ define i1 @assume_4_nr(i1 %arg, i1 %cond) norecurse {
; TUNIT-LABEL: define {{[^@]+}}@assume_4_nr
; TUNIT-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -530,9 +524,6 @@ define i1 @assume_5_nr(i1 %arg, i1 %cond) norecurse {
; TUNIT-LABEL: define {{[^@]+}}@assume_5_nr
; TUNIT-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
-; TUNIT-NEXT: [[L1:%.*]] = load i1, ptr [[STACK]], align 1
-; TUNIT-NEXT: call void @llvm.assume(i1 noundef [[L1]]) #[[ATTR6]]
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -601,9 +592,7 @@ define i1 @assume_5c_nr(i1 %cond) norecurse {
; TUNIT-LABEL: define {{[^@]+}}@assume_5c_nr
; TUNIT-SAME: (i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
-; TUNIT-NEXT: [[L1:%.*]] = load i1, ptr [[STACK]], align 1
-; TUNIT-NEXT: call void @llvm.assume(i1 noundef [[L1]]) #[[ATTR6]]
+; TUNIT-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR6]]
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -973,7 +962,6 @@ define i1 @assume_2(i1 %arg, i1 %cond) {
; TUNIT-LABEL: define {{[^@]+}}@assume_2
; TUNIT-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -990,7 +978,6 @@ define i1 @assume_2(i1 %arg, i1 %cond) {
; CGSCC-LABEL: define {{[^@]+}}@assume_2
; CGSCC-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; CGSCC-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; CGSCC-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
; CGSCC-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; CGSCC: t:
; CGSCC-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -1050,9 +1037,6 @@ define i1 @assume_3(i1 %arg, i1 %cond) {
; TUNIT-LABEL: define {{[^@]+}}@assume_3
; TUNIT-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
-; TUNIT-NEXT: [[L:%.*]] = load i1, ptr [[STACK]], align 1
-; TUNIT-NEXT: call void @llvm.assume(i1 noundef [[L]]) #[[ATTR6]]
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -1103,7 +1087,6 @@ define i1 @assume_4(i1 %arg, i1 %cond) {
; TUNIT-LABEL: define {{[^@]+}}@assume_4
; TUNIT-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -1156,9 +1139,6 @@ define i1 @assume_5(i1 %arg, i1 %cond) {
; TUNIT-LABEL: define {{[^@]+}}@assume_5
; TUNIT-SAME: (i1 [[ARG:%.*]], i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 [[ARG]], ptr [[STACK]], align 1
-; TUNIT-NEXT: [[L1:%.*]] = load i1, ptr [[STACK]], align 1
-; TUNIT-NEXT: call void @llvm.assume(i1 noundef [[L1]]) #[[ATTR6]]
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -1227,9 +1207,7 @@ define i1 @assume_5c(i1 %cond) {
; TUNIT-LABEL: define {{[^@]+}}@assume_5c
; TUNIT-SAME: (i1 noundef [[COND:%.*]]) #[[ATTR3]] {
; TUNIT-NEXT: [[STACK:%.*]] = alloca i1, align 1
-; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
-; TUNIT-NEXT: [[L1:%.*]] = load i1, ptr [[STACK]], align 1
-; TUNIT-NEXT: call void @llvm.assume(i1 noundef [[L1]]) #[[ATTR6]]
+; TUNIT-NEXT: call void @llvm.assume(i1 noundef true) #[[ATTR6]]
; TUNIT-NEXT: br i1 [[COND]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: t:
; TUNIT-NEXT: store i1 true, ptr [[STACK]], align 1
@@ -1303,7 +1281,6 @@ define i32 @assume_read_global_good() {
; TUNIT-NEXT: [[C:%.*]] = icmp eq i32 [[LGS1]], 42
; TUNIT-NEXT: call void @llvm.assume(i1 noundef [[C]]) #[[ATTR6]]
; TUNIT-NEXT: [[LGS2:%.*]] = load i32, ptr @Gstatic_int1, align 4
-; TUNIT-NEXT: store i32 13, ptr @Gstatic_int1, align 4
; TUNIT-NEXT: store i32 17, ptr @Gstatic_int1, align 4
; TUNIT-NEXT: [[LGS3:%.*]] = load i32, ptr @Gstatic_int1, align 4
; TUNIT-NEXT: [[ADD:%.*]] = add i32 [[LGS2]], [[LGS3]]
@@ -1316,7 +1293,6 @@ define i32 @assume_read_global_good() {
; CGSCC-NEXT: [[C:%.*]] = icmp eq i32 [[LGS1]], 42
; CGSCC-NEXT: call void @llvm.assume(i1 noundef [[C]]) #[[ATTR7]]
; CGSCC-NEXT: [[LGS2:%.*]] = load i32, ptr @Gstatic_int1, align 4
-; CGSCC-NEXT: store i32 13, ptr @Gstatic_int1, align 4
; CGSCC-NEXT: store i32 17, ptr @Gstatic_int1, align 4
; CGSCC-NEXT: [[LGS3:%.*]] = load i32, ptr @Gstatic_int1, align 4
; CGSCC-NEXT: [[ADD:%.*]] = add i32 [[LGS2]], [[LGS3]]
diff --git a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
index b6b06b0c74ab7..7570b4cf6dc3e 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-pointer-info.ll
@@ -542,13 +542,9 @@ define i32 @local_alloca_simplifiable_3() {
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
; CHECK-LABEL: define {{[^@]+}}@local_alloca_simplifiable_3
; CHECK-SAME: () #[[ATTR4:[0-9]+]] {
-; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
-; CHECK-NEXT: store i32 1, i32* [[A]], align 4
; CHECK-NEXT: br label [[SPLIT:%.*]]
; CHECK: split:
-; CHECK-NEXT: store i32 2, i32* [[A]], align 4
-; CHECK-NEXT: [[L:%.*]] = load i32, i32* [[A]], align 4
-; CHECK-NEXT: ret i32 [[L]]
+; CHECK-NEXT: ret i32 2
;
%A = alloca i32, align 4
store i32 1, i32* %A
diff --git a/llvm/test/Transforms/Attributor/value-simplify-reachability.ll b/llvm/test/Transforms/Attributor/value-simplify-reachability.ll
index 4ed604b95bd64..419a63654f3d5 100644
--- a/llvm/test/Transforms/Attributor/value-simplify-reachability.ll
+++ b/llvm/test/Transforms/Attributor/value-simplify-reachability.ll
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
-; 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,TUNIT
+; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=11 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
@GInt1 = internal global i32 undef, align 4
@@ -175,11 +175,9 @@ define void @entry3(i1 %c, i32 %v) {
; TUNIT: Function Attrs: norecurse nosync
; TUNIT-LABEL: define {{[^@]+}}@entry3
; TUNIT-SAME: (i1 [[C:%.*]], i32 [[V:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT: [[L0:%.*]] = load i32, ptr @GInt3, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L0]])
+; TUNIT-NEXT: call void @useI32(i32 1)
; TUNIT-NEXT: store i32 1, ptr @GInt3, align 4
-; TUNIT-NEXT: [[L1:%.*]] = load i32, ptr @GInt3, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L1]])
+; TUNIT-NEXT: call void @useI32(i32 noundef 1)
; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: T:
; TUNIT-NEXT: store i32 [[V]], ptr @GInt3, align 4
@@ -190,18 +188,15 @@ define void @entry3(i1 %c, i32 %v) {
; TUNIT-NEXT: [[L3:%.*]] = load i32, ptr @GInt3, align 4
; TUNIT-NEXT: call void @useI32(i32 [[L3]])
; TUNIT-NEXT: store i32 1, ptr @GInt3, align 4
-; TUNIT-NEXT: [[L4:%.*]] = load i32, ptr @GInt3, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L4]])
+; TUNIT-NEXT: call void @useI32(i32 noundef 1)
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: norecurse nosync
; CGSCC-LABEL: define {{[^@]+}}@entry3
; CGSCC-SAME: (i1 [[C:%.*]], i32 [[V:%.*]]) #[[ATTR6:[0-9]+]] {
-; CGSCC-NEXT: [[L0:%.*]] = load i32, ptr @GInt3, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L0]])
+; CGSCC-NEXT: call void @useI32(i32 1)
; CGSCC-NEXT: store i32 1, ptr @GInt3, align 4
-; CGSCC-NEXT: [[L1:%.*]] = load i32, ptr @GInt3, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L1]])
+; CGSCC-NEXT: call void @useI32(i32 noundef 1)
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CGSCC: T:
; CGSCC-NEXT: store i32 [[V]], ptr @GInt3, align 4
@@ -212,8 +207,7 @@ define void @entry3(i1 %c, i32 %v) {
; CGSCC-NEXT: [[L3:%.*]] = load i32, ptr @GInt3, align 4
; CGSCC-NEXT: call void @useI32(i32 [[L3]])
; CGSCC-NEXT: store i32 1, ptr @GInt3, align 4
-; CGSCC-NEXT: [[L4:%.*]] = load i32, ptr @GInt3, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L4]])
+; CGSCC-NEXT: call void @useI32(i32 noundef 1)
; CGSCC-NEXT: ret void
;
%l0 = load i32, ptr @GInt3
@@ -241,10 +235,9 @@ define void @entry4(i1 %c, i32 %v) {
; TUNIT-LABEL: define {{[^@]+}}@entry4
; TUNIT-SAME: (i1 [[C:%.*]], i32 [[V:%.*]]) #[[ATTR5]] {
; TUNIT-NEXT: [[L0:%.*]] = load i32, ptr @GInt4, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L0]])
+; TUNIT-NEXT: call void @useI32(i32 noundef [[L0]])
; TUNIT-NEXT: store i32 1, ptr @GInt4, align 4
-; TUNIT-NEXT: [[L1:%.*]] = load i32, ptr @GInt4, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L1]])
+; TUNIT-NEXT: call void @useI32(i32 noundef 1)
; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: T:
; TUNIT-NEXT: store i32 [[V]], ptr @GInt4, align 4
@@ -255,18 +248,16 @@ define void @entry4(i1 %c, i32 %v) {
; TUNIT-NEXT: [[L3:%.*]] = load i32, ptr @GInt4, align 4
; TUNIT-NEXT: call void @useI32(i32 [[L3]])
; TUNIT-NEXT: store i32 1, ptr @GInt4, align 4
-; TUNIT-NEXT: [[L4:%.*]] = load i32, ptr @GInt4, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L4]])
+; TUNIT-NEXT: call void @useI32(i32 noundef 1)
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: norecurse nosync
; CGSCC-LABEL: define {{[^@]+}}@entry4
; CGSCC-SAME: (i1 [[C:%.*]], i32 [[V:%.*]]) #[[ATTR6]] {
; CGSCC-NEXT: [[L0:%.*]] = load i32, ptr @GInt4, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L0]])
+; CGSCC-NEXT: call void @useI32(i32 noundef [[L0]])
; CGSCC-NEXT: store i32 1, ptr @GInt4, align 4
-; CGSCC-NEXT: [[L1:%.*]] = load i32, ptr @GInt4, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L1]])
+; CGSCC-NEXT: call void @useI32(i32 noundef 1)
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CGSCC: T:
; CGSCC-NEXT: store i32 [[V]], ptr @GInt4, align 4
@@ -277,8 +268,7 @@ define void @entry4(i1 %c, i32 %v) {
; CGSCC-NEXT: [[L3:%.*]] = load i32, ptr @GInt4, align 4
; CGSCC-NEXT: call void @useI32(i32 [[L3]])
; CGSCC-NEXT: store i32 1, ptr @GInt4, align 4
-; CGSCC-NEXT: [[L4:%.*]] = load i32, ptr @GInt4, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L4]])
+; CGSCC-NEXT: call void @useI32(i32 noundef 1)
; CGSCC-NEXT: ret void
;
%l0 = load i32, ptr @GInt4
@@ -306,11 +296,9 @@ define void @entry5(i1 %c, i32 %v) {
; TUNIT: Function Attrs: norecurse nosync
; TUNIT-LABEL: define {{[^@]+}}@entry5
; TUNIT-SAME: (i1 [[C:%.*]], i32 [[V:%.*]]) #[[ATTR5]] {
-; TUNIT-NEXT: [[L0:%.*]] = load i32, ptr @GInt5, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L0]])
+; TUNIT-NEXT: call void @useI32(i32 1)
; TUNIT-NEXT: store i32 1, ptr @GInt5, align 4
-; TUNIT-NEXT: [[L1:%.*]] = load i32, ptr @GInt5, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L1]]) #[[ATTR6:[0-9]+]]
+; TUNIT-NEXT: call void @useI32(i32 noundef 1) #[[ATTR6:[0-9]+]]
; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; TUNIT: T:
; TUNIT-NEXT: store i32 [[V]], ptr @GInt5, align 4
@@ -321,18 +309,15 @@ define void @entry5(i1 %c, i32 %v) {
; TUNIT-NEXT: [[L3:%.*]] = load i32, ptr @GInt5, align 4
; TUNIT-NEXT: call void @useI32(i32 [[L3]]) #[[ATTR6]]
; TUNIT-NEXT: store i32 1, ptr @GInt5, align 4
-; TUNIT-NEXT: [[L4:%.*]] = load i32, ptr @GInt5, align 4
-; TUNIT-NEXT: call void @useI32(i32 [[L4]]) #[[ATTR6]]
+; TUNIT-NEXT: call void @useI32(i32 noundef 1) #[[ATTR6]]
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: norecurse nosync
; CGSCC-LABEL: define {{[^@]+}}@entry5
; CGSCC-SAME: (i1 [[C:%.*]], i32 [[V:%.*]]) #[[ATTR6]] {
-; CGSCC-NEXT: [[L0:%.*]] = load i32, ptr @GInt5, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L0]])
+; CGSCC-NEXT: call void @useI32(i32 1)
; CGSCC-NEXT: store i32 1, ptr @GInt5, align 4
-; CGSCC-NEXT: [[L1:%.*]] = load i32, ptr @GInt5, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L1]]) #[[ATTR7:[0-9]+]]
+; CGSCC-NEXT: call void @useI32(i32 noundef 1) #[[ATTR7:[0-9]+]]
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
; CGSCC: T:
; CGSCC-NEXT: store i32 [[V]], ptr @GInt5, align 4
@@ -343,8 +328,7 @@ define void @entry5(i1 %c, i32 %v) {
; CGSCC-NEXT: [[L3:%.*]] = load i32, ptr @GInt5, align 4
; CGSCC-NEXT: call void @useI32(i32 [[L3]]) #[[ATTR7]]
; CGSCC-NEXT: store i32 1, ptr @GInt5, align 4
-; CGSCC-NEXT: [[L4:%.*]] = load i32, ptr @GInt5, align 4
-; CGSCC-NEXT: call void @useI32(i32 [[L4]]) #[[ATTR7]]
+; CGSCC-NEXT: call void @useI32(i32 noundef 1) #[[ATTR7]]
; CGSCC-NEXT: ret void
;
%l0 = load i32, ptr @GInt5
@@ -727,8 +711,7 @@ define internal void @exclusion_set3_helper(i1 %c, ptr %p) {
; TUNIT-NEXT: call void @usei32(i32 [[USE2]])
; TUNIT-NEXT: br label [[T]]
; TUNIT: m:
-; TUNIT-NEXT: [[USE3:%.*]] = load i32, ptr [[P]], align 4
-; TUNIT-NEXT: call void @usei32(i32 [[USE3]])
+; TUNIT-NEXT: call void @usei32(i32 42)
; TUNIT-NEXT: ret void
;
; CGSCC: Function Attrs: nosync
diff --git a/llvm/unittests/Transforms/IPO/AttributorTest.cpp b/llvm/unittests/Transforms/IPO/AttributorTest.cpp
index cd289a1a2a353..4a38684b0dbf7 100644
--- a/llvm/unittests/Transforms/IPO/AttributorTest.cpp
+++ b/llvm/unittests/Transforms/IPO/AttributorTest.cpp
@@ -169,23 +169,23 @@ TEST_F(AttributorTestBase, AAReachabilityTest) {
// call void @func8
Instruction &F9SecondInst = *++(F9.getEntryBlock().begin());
- const AAFunctionReachability &F1AA =
- A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F1));
+ const AAInterFnReachability &F1AA =
+ A.getOrCreateAAFor<AAInterFnReachability>(IRPosition::function(F1));
- const AAFunctionReachability &F6AA =
- A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F6));
+ const AAInterFnReachability &F6AA =
+ A.getOrCreateAAFor<AAInterFnReachability>(IRPosition::function(F6));
- const AAFunctionReachability &F7AA =
- A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F7));
+ const AAInterFnReachability &F7AA =
+ A.getOrCreateAAFor<AAInterFnReachability>(IRPosition::function(F7));
- const AAFunctionReachability &F9AA =
- A.getOrCreateAAFor<AAFunctionReachability>(IRPosition::function(F9));
+ const AAInterFnReachability &F9AA =
+ A.getOrCreateAAFor<AAInterFnReachability>(IRPosition::function(F9));
F1AA.canReach(A, F3);
F1AA.canReach(A, F4);
F6AA.canReach(A, F4);
- F7AA.canReach(A, F7FirstCB, F3);
- F7AA.canReach(A, F7FirstCB, F4);
+ F7AA.instructionCanReach(A, F7FirstCB, F3);
+ F7AA.instructionCanReach(A, F7FirstCB, F4);
F9AA.instructionCanReach(A, F9FirstInst, F3);
F9AA.instructionCanReach(A, F9FirstInst, F4);
@@ -194,8 +194,8 @@ TEST_F(AttributorTestBase, AAReachabilityTest) {
ASSERT_TRUE(F1AA.canReach(A, F3));
ASSERT_FALSE(F1AA.canReach(A, F4));
- ASSERT_TRUE(F7AA.canReach(A, F7FirstCB, F3));
- ASSERT_FALSE(F7AA.canReach(A, F7FirstCB, F4));
+ ASSERT_TRUE(F7AA.instructionCanReach(A, F7FirstCB, F3));
+ ASSERT_TRUE(F7AA.instructionCanReach(A, F7FirstCB, F4));
// Assumed to be reacahable, since F6 can reach a function with
// a unknown callee.
More information about the llvm-commits
mailing list