forked from OSchip/llvm-project
[NFC][FuncAttrs] Keep track of modified functions
This is in preparation for only invalidating analyses on changed functions. Reviewed By: asbirlea Differential Revision: https://reviews.llvm.org/D113303
This commit is contained in:
parent
62dd488164
commit
28a06a1b87
|
@ -19,6 +19,7 @@
|
|||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
|
@ -249,7 +250,8 @@ MemoryAccessKind llvm::computeFunctionBodyMemoryAccess(Function &F,
|
|||
|
||||
/// Deduce readonly/readnone attributes for the SCC.
|
||||
template <typename AARGetterT>
|
||||
static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
|
||||
static void addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
// Check if any of the functions in the SCC read or write memory. If they
|
||||
// write memory then they can't be marked readnone or readonly.
|
||||
bool ReadsMemory = false;
|
||||
|
@ -264,7 +266,7 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
|
|||
switch (checkFunctionMemoryAccess(*F, F->hasExactDefinition(),
|
||||
AAR, SCCNodes)) {
|
||||
case MAK_MayWrite:
|
||||
return false;
|
||||
return;
|
||||
case MAK_ReadOnly:
|
||||
ReadsMemory = true;
|
||||
break;
|
||||
|
@ -280,11 +282,10 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
|
|||
// If the SCC contains both functions that read and functions that write, then
|
||||
// we cannot add readonly attributes.
|
||||
if (ReadsMemory && WritesMemory)
|
||||
return false;
|
||||
return;
|
||||
|
||||
// Success! Functions in this SCC do not access memory, or only read memory.
|
||||
// Give them the appropriate attribute.
|
||||
bool MadeChange = false;
|
||||
|
||||
for (Function *F : SCCNodes) {
|
||||
if (F->doesNotAccessMemory())
|
||||
|
@ -298,7 +299,7 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
|
|||
if (F->doesNotReadMemory() && WritesMemory)
|
||||
continue;
|
||||
|
||||
MadeChange = true;
|
||||
Changed.insert(F);
|
||||
|
||||
// Clear out any existing attributes.
|
||||
AttrBuilder AttrsToRemove;
|
||||
|
@ -327,8 +328,6 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
|
|||
else
|
||||
++NumReadNone;
|
||||
}
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
// Compute definitive function attributes for a function taking into account
|
||||
|
@ -779,9 +778,8 @@ determinePointerReadAttrs(Argument *A,
|
|||
}
|
||||
|
||||
/// Deduce returned attributes for the SCC.
|
||||
static bool addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes) {
|
||||
bool Changed = false;
|
||||
|
||||
static void addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
// Check each function in turn, determining if an argument is always returned.
|
||||
for (Function *F : SCCNodes) {
|
||||
// We can infer and propagate function attributes only when we know that the
|
||||
|
@ -821,11 +819,9 @@ static bool addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes) {
|
|||
auto *A = cast<Argument>(RetArg);
|
||||
A->addAttr(Attribute::Returned);
|
||||
++NumReturned;
|
||||
Changed = true;
|
||||
Changed.insert(F);
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// If a callsite has arguments that are also arguments to the parent function,
|
||||
|
@ -891,9 +887,8 @@ static bool addReadAttr(Argument *A, Attribute::AttrKind R) {
|
|||
}
|
||||
|
||||
/// Deduce nocapture attributes for the SCC.
|
||||
static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
|
||||
bool Changed = false;
|
||||
|
||||
static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
ArgumentGraph AG;
|
||||
|
||||
// Check each function in turn, determining which pointer arguments are not
|
||||
|
@ -905,7 +900,8 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
|
|||
if (!F->hasExactDefinition())
|
||||
continue;
|
||||
|
||||
Changed |= addArgumentAttrsFromCallsites(*F);
|
||||
if (addArgumentAttrsFromCallsites(*F))
|
||||
Changed.insert(F);
|
||||
|
||||
// Functions that are readonly (or readnone) and nounwind and don't return
|
||||
// a value can't capture arguments. Don't analyze them.
|
||||
|
@ -916,7 +912,7 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
|
|||
if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) {
|
||||
A->addAttr(Attribute::NoCapture);
|
||||
++NumNoCapture;
|
||||
Changed = true;
|
||||
Changed.insert(F);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
@ -935,7 +931,7 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
|
|||
// If it's trivially not captured, mark it nocapture now.
|
||||
A->addAttr(Attribute::NoCapture);
|
||||
++NumNoCapture;
|
||||
Changed = true;
|
||||
Changed.insert(F);
|
||||
} else {
|
||||
// If it's not trivially captured and not trivially not captured,
|
||||
// then it must be calling into another function in our SCC. Save
|
||||
|
@ -959,7 +955,8 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
|
|||
Self.insert(&*A);
|
||||
Attribute::AttrKind R = determinePointerReadAttrs(&*A, Self);
|
||||
if (R != Attribute::None)
|
||||
Changed = addReadAttr(A, R);
|
||||
if (addReadAttr(A, R))
|
||||
Changed.insert(F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -983,7 +980,7 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
|
|||
Argument *A = ArgumentSCC[0]->Definition;
|
||||
A->addAttr(Attribute::NoCapture);
|
||||
++NumNoCapture;
|
||||
Changed = true;
|
||||
Changed.insert(A->getParent());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1025,7 +1022,7 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
|
|||
Argument *A = ArgumentSCC[i]->Definition;
|
||||
A->addAttr(Attribute::NoCapture);
|
||||
++NumNoCapture;
|
||||
Changed = true;
|
||||
Changed.insert(A->getParent());
|
||||
}
|
||||
|
||||
// We also want to compute readonly/readnone. With a small number of false
|
||||
|
@ -1056,12 +1053,11 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
|
|||
if (ReadAttr != Attribute::None) {
|
||||
for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
|
||||
Argument *A = ArgumentSCC[i]->Definition;
|
||||
Changed = addReadAttr(A, ReadAttr);
|
||||
if (addReadAttr(A, ReadAttr))
|
||||
Changed.insert(A->getParent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// Tests whether a function is "malloc-like".
|
||||
|
@ -1132,7 +1128,8 @@ static bool isFunctionMallocLike(Function *F, const SCCNodeSet &SCCNodes) {
|
|||
}
|
||||
|
||||
/// Deduce noalias attributes for the SCC.
|
||||
static bool addNoAliasAttrs(const SCCNodeSet &SCCNodes) {
|
||||
static void addNoAliasAttrs(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
// Check each function in turn, determining which functions return noalias
|
||||
// pointers.
|
||||
for (Function *F : SCCNodes) {
|
||||
|
@ -1144,7 +1141,7 @@ static bool addNoAliasAttrs(const SCCNodeSet &SCCNodes) {
|
|||
// definition we'll get at link time is *exactly* the definition we see now.
|
||||
// For more details, see GlobalValue::mayBeDerefined.
|
||||
if (!F->hasExactDefinition())
|
||||
return false;
|
||||
return;
|
||||
|
||||
// We annotate noalias return values, which are only applicable to
|
||||
// pointer types.
|
||||
|
@ -1152,10 +1149,9 @@ static bool addNoAliasAttrs(const SCCNodeSet &SCCNodes) {
|
|||
continue;
|
||||
|
||||
if (!isFunctionMallocLike(F, SCCNodes))
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool MadeChange = false;
|
||||
for (Function *F : SCCNodes) {
|
||||
if (F->returnDoesNotAlias() ||
|
||||
!F->getReturnType()->isPointerTy())
|
||||
|
@ -1163,10 +1159,8 @@ static bool addNoAliasAttrs(const SCCNodeSet &SCCNodes) {
|
|||
|
||||
F->setReturnDoesNotAlias();
|
||||
++NumNoAlias;
|
||||
MadeChange = true;
|
||||
Changed.insert(F);
|
||||
}
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
/// Tests whether this function is known to not return null.
|
||||
|
@ -1242,13 +1236,12 @@ static bool isReturnNonNull(Function *F, const SCCNodeSet &SCCNodes,
|
|||
}
|
||||
|
||||
/// Deduce nonnull attributes for the SCC.
|
||||
static bool addNonNullAttrs(const SCCNodeSet &SCCNodes) {
|
||||
static void addNonNullAttrs(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
// Speculative that all functions in the SCC return only nonnull
|
||||
// pointers. We may refute this as we analyze functions.
|
||||
bool SCCReturnsNonNull = true;
|
||||
|
||||
bool MadeChange = false;
|
||||
|
||||
// Check each function in turn, determining which functions return nonnull
|
||||
// pointers.
|
||||
for (Function *F : SCCNodes) {
|
||||
|
@ -1260,7 +1253,7 @@ static bool addNonNullAttrs(const SCCNodeSet &SCCNodes) {
|
|||
// definition we'll get at link time is *exactly* the definition we see now.
|
||||
// For more details, see GlobalValue::mayBeDerefined.
|
||||
if (!F->hasExactDefinition())
|
||||
return false;
|
||||
return;
|
||||
|
||||
// We annotate nonnull return values, which are only applicable to
|
||||
// pointer types.
|
||||
|
@ -1276,7 +1269,7 @@ static bool addNonNullAttrs(const SCCNodeSet &SCCNodes) {
|
|||
<< " as nonnull\n");
|
||||
F->addRetAttr(Attribute::NonNull);
|
||||
++NumNonNullReturn;
|
||||
MadeChange = true;
|
||||
Changed.insert(F);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1294,11 +1287,9 @@ static bool addNonNullAttrs(const SCCNodeSet &SCCNodes) {
|
|||
LLVM_DEBUG(dbgs() << "SCC marking " << F->getName() << " as nonnull\n");
|
||||
F->addRetAttr(Attribute::NonNull);
|
||||
++NumNonNullReturn;
|
||||
MadeChange = true;
|
||||
Changed.insert(F);
|
||||
}
|
||||
}
|
||||
|
||||
return MadeChange;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1351,12 +1342,13 @@ public:
|
|||
InferenceDescriptors.push_back(AttrInference);
|
||||
}
|
||||
|
||||
bool run(const SCCNodeSet &SCCNodes);
|
||||
void run(const SCCNodeSet &SCCNodes, SmallSet<Function *, 8> &Changed);
|
||||
};
|
||||
|
||||
/// Perform all the requested attribute inference actions according to the
|
||||
/// attribute predicates stored before.
|
||||
bool AttributeInferer::run(const SCCNodeSet &SCCNodes) {
|
||||
void AttributeInferer::run(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
SmallVector<InferenceDescriptor, 4> InferInSCC = InferenceDescriptors;
|
||||
// Go through all the functions in SCC and check corresponding attribute
|
||||
// assumptions for each of them. Attributes that are invalid for this SCC
|
||||
|
@ -1365,7 +1357,7 @@ bool AttributeInferer::run(const SCCNodeSet &SCCNodes) {
|
|||
|
||||
// No attributes whose assumptions are still valid - done.
|
||||
if (InferInSCC.empty())
|
||||
return false;
|
||||
return;
|
||||
|
||||
// Check if our attributes ever need scanning/can be scanned.
|
||||
llvm::erase_if(InferInSCC, [F](const InferenceDescriptor &ID) {
|
||||
|
@ -1408,9 +1400,8 @@ bool AttributeInferer::run(const SCCNodeSet &SCCNodes) {
|
|||
}
|
||||
|
||||
if (InferInSCC.empty())
|
||||
return false;
|
||||
return;
|
||||
|
||||
bool Changed = false;
|
||||
for (Function *F : SCCNodes)
|
||||
// At this point InferInSCC contains only functions that were either:
|
||||
// - explicitly skipped from scan/inference, or
|
||||
|
@ -1419,10 +1410,9 @@ bool AttributeInferer::run(const SCCNodeSet &SCCNodes) {
|
|||
for (auto &ID : InferInSCC) {
|
||||
if (ID.SkipFunction(*F))
|
||||
continue;
|
||||
Changed = true;
|
||||
Changed.insert(F);
|
||||
ID.SetAttribute(*F);
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
|
||||
struct SCCNodesResult {
|
||||
|
@ -1478,7 +1468,8 @@ static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes) {
|
|||
/// Attempt to remove convergent function attribute when possible.
|
||||
///
|
||||
/// Returns true if any changes to function attributes were made.
|
||||
static bool inferConvergent(const SCCNodeSet &SCCNodes) {
|
||||
static void inferConvergent(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
AttributeInferer AI;
|
||||
|
||||
// Request to remove the convergent attribute from all functions in the SCC
|
||||
|
@ -1501,7 +1492,7 @@ static bool inferConvergent(const SCCNodeSet &SCCNodes) {
|
|||
},
|
||||
/* RequiresExactDefinition= */ false});
|
||||
// Perform all the requested attribute inference actions.
|
||||
return AI.run(SCCNodes);
|
||||
AI.run(SCCNodes, Changed);
|
||||
}
|
||||
|
||||
/// Infer attributes from all functions in the SCC by scanning every
|
||||
|
@ -1510,7 +1501,8 @@ static bool inferConvergent(const SCCNodeSet &SCCNodes) {
|
|||
/// - addition of NoUnwind attribute
|
||||
///
|
||||
/// Returns true if any changes to function attributes were made.
|
||||
static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) {
|
||||
static void inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
AttributeInferer AI;
|
||||
|
||||
if (!DisableNoUnwindInference)
|
||||
|
@ -1559,19 +1551,20 @@ static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) {
|
|||
/* RequiresExactDefinition= */ true});
|
||||
|
||||
// Perform all the requested attribute inference actions.
|
||||
return AI.run(SCCNodes);
|
||||
AI.run(SCCNodes, Changed);
|
||||
}
|
||||
|
||||
static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {
|
||||
static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
// Try and identify functions that do not recurse.
|
||||
|
||||
// If the SCC contains multiple nodes we know for sure there is recursion.
|
||||
if (SCCNodes.size() != 1)
|
||||
return false;
|
||||
return;
|
||||
|
||||
Function *F = *SCCNodes.begin();
|
||||
if (!F || !F->hasExactDefinition() || F->doesNotRecurse())
|
||||
return false;
|
||||
return;
|
||||
|
||||
// If all of the calls in F are identifiable and are to norecurse functions, F
|
||||
// is norecurse. This check also detects self-recursion as F is not currently
|
||||
|
@ -1582,7 +1575,7 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {
|
|||
Function *Callee = CB->getCalledFunction();
|
||||
if (!Callee || Callee == F || !Callee->doesNotRecurse())
|
||||
// Function calls a potentially recursive function.
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Every call was to a non-recursive function other than this function, and
|
||||
|
@ -1590,7 +1583,7 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {
|
|||
// recurse.
|
||||
F->setDoesNotRecurse();
|
||||
++NumNoRecurse;
|
||||
return true;
|
||||
Changed.insert(F);
|
||||
}
|
||||
|
||||
static bool instructionDoesNotReturn(Instruction &I) {
|
||||
|
@ -1608,9 +1601,8 @@ static bool basicBlockCanReturn(BasicBlock &BB) {
|
|||
}
|
||||
|
||||
// Set the noreturn function attribute if possible.
|
||||
static bool addNoReturnAttrs(const SCCNodeSet &SCCNodes) {
|
||||
bool Changed = false;
|
||||
|
||||
static void addNoReturnAttrs(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
for (Function *F : SCCNodes) {
|
||||
if (!F || !F->hasExactDefinition() || F->hasFnAttribute(Attribute::Naked) ||
|
||||
F->doesNotReturn())
|
||||
|
@ -1620,11 +1612,9 @@ static bool addNoReturnAttrs(const SCCNodeSet &SCCNodes) {
|
|||
// FIXME: this doesn't handle recursion or unreachable blocks.
|
||||
if (none_of(*F, basicBlockCanReturn)) {
|
||||
F->setDoesNotReturn();
|
||||
Changed = true;
|
||||
Changed.insert(F);
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
static bool functionWillReturn(const Function &F) {
|
||||
|
@ -1657,19 +1647,16 @@ static bool functionWillReturn(const Function &F) {
|
|||
}
|
||||
|
||||
// Set the willreturn function attribute if possible.
|
||||
static bool addWillReturn(const SCCNodeSet &SCCNodes) {
|
||||
bool Changed = false;
|
||||
|
||||
static void addWillReturn(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
for (Function *F : SCCNodes) {
|
||||
if (!F || F->willReturn() || !functionWillReturn(*F))
|
||||
continue;
|
||||
|
||||
F->setWillReturn();
|
||||
NumWillReturn++;
|
||||
Changed = true;
|
||||
Changed.insert(F);
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
// Return true if this is an atomic which has an ordering stronger than
|
||||
|
@ -1728,7 +1715,8 @@ static bool InstrBreaksNoSync(Instruction &I, const SCCNodeSet &SCCNodes) {
|
|||
}
|
||||
|
||||
// Infer the nosync attribute.
|
||||
static bool addNoSyncAttr(const SCCNodeSet &SCCNodes) {
|
||||
static void addNoSyncAttr(const SCCNodeSet &SCCNodes,
|
||||
SmallSet<Function *, 8> &Changed) {
|
||||
AttributeInferer AI;
|
||||
AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
|
||||
Attribute::NoSync,
|
||||
|
@ -1745,7 +1733,7 @@ static bool addNoSyncAttr(const SCCNodeSet &SCCNodes) {
|
|||
++NumNoSync;
|
||||
},
|
||||
/* RequiresExactDefinition= */ true});
|
||||
return AI.run(SCCNodes);
|
||||
AI.run(SCCNodes, Changed);
|
||||
}
|
||||
|
||||
static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
|
||||
|
@ -1779,32 +1767,33 @@ static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
|
|||
}
|
||||
|
||||
template <typename AARGetterT>
|
||||
static bool deriveAttrsInPostOrder(ArrayRef<Function *> Functions,
|
||||
AARGetterT &&AARGetter) {
|
||||
static SmallSet<Function *, 8>
|
||||
deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter) {
|
||||
SCCNodesResult Nodes = createSCCNodeSet(Functions);
|
||||
bool Changed = false;
|
||||
|
||||
// Bail if the SCC only contains optnone functions.
|
||||
if (Nodes.SCCNodes.empty())
|
||||
return Changed;
|
||||
return {};
|
||||
|
||||
Changed |= addArgumentReturnedAttrs(Nodes.SCCNodes);
|
||||
Changed |= addReadAttrs(Nodes.SCCNodes, AARGetter);
|
||||
Changed |= addArgumentAttrs(Nodes.SCCNodes);
|
||||
Changed |= inferConvergent(Nodes.SCCNodes);
|
||||
Changed |= addNoReturnAttrs(Nodes.SCCNodes);
|
||||
Changed |= addWillReturn(Nodes.SCCNodes);
|
||||
SmallSet<Function *, 8> Changed;
|
||||
|
||||
addArgumentReturnedAttrs(Nodes.SCCNodes, Changed);
|
||||
addReadAttrs(Nodes.SCCNodes, AARGetter, Changed);
|
||||
addArgumentAttrs(Nodes.SCCNodes, Changed);
|
||||
inferConvergent(Nodes.SCCNodes, Changed);
|
||||
addNoReturnAttrs(Nodes.SCCNodes, Changed);
|
||||
addWillReturn(Nodes.SCCNodes, Changed);
|
||||
|
||||
// If we have no external nodes participating in the SCC, we can deduce some
|
||||
// more precise attributes as well.
|
||||
if (!Nodes.HasUnknownCall) {
|
||||
Changed |= addNoAliasAttrs(Nodes.SCCNodes);
|
||||
Changed |= addNonNullAttrs(Nodes.SCCNodes);
|
||||
Changed |= inferAttrsFromFunctionBodies(Nodes.SCCNodes);
|
||||
Changed |= addNoRecurseAttrs(Nodes.SCCNodes);
|
||||
addNoAliasAttrs(Nodes.SCCNodes, Changed);
|
||||
addNonNullAttrs(Nodes.SCCNodes, Changed);
|
||||
inferAttrsFromFunctionBodies(Nodes.SCCNodes, Changed);
|
||||
addNoRecurseAttrs(Nodes.SCCNodes, Changed);
|
||||
}
|
||||
|
||||
Changed |= addNoSyncAttr(Nodes.SCCNodes);
|
||||
addNoSyncAttr(Nodes.SCCNodes, Changed);
|
||||
|
||||
// Finally, infer the maximal set of attributes from the ones we've inferred
|
||||
// above. This is handling the cases where one attribute on a signature
|
||||
|
@ -1812,7 +1801,8 @@ static bool deriveAttrsInPostOrder(ArrayRef<Function *> Functions,
|
|||
// the later is missing (or simply less sophisticated).
|
||||
for (Function *F : Nodes.SCCNodes)
|
||||
if (F)
|
||||
Changed |= inferAttributesFromOthers(*F);
|
||||
if (inferAttributesFromOthers(*F))
|
||||
Changed.insert(F);
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
@ -1835,14 +1825,14 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
|
|||
Functions.push_back(&N.getFunction());
|
||||
}
|
||||
|
||||
if (deriveAttrsInPostOrder(Functions, AARGetter)) {
|
||||
// We have not changed the call graph or removed/added functions.
|
||||
PreservedAnalyses PA;
|
||||
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
|
||||
return PA;
|
||||
}
|
||||
auto ChangedFunctions = deriveAttrsInPostOrder(Functions, AARGetter);
|
||||
if (ChangedFunctions.empty())
|
||||
return PreservedAnalyses::all();
|
||||
|
||||
return PreservedAnalyses::all();
|
||||
PreservedAnalyses PA;
|
||||
// We have not added or removed functions.
|
||||
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
|
||||
return PA;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1887,7 +1877,7 @@ static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) {
|
|||
Functions.push_back(I->getFunction());
|
||||
}
|
||||
|
||||
return deriveAttrsInPostOrder(Functions, AARGetter);
|
||||
return !deriveAttrsInPostOrder(Functions, AARGetter).empty();
|
||||
}
|
||||
|
||||
bool PostOrderFunctionAttrsLegacyPass::runOnSCC(CallGraphSCC &SCC) {
|
||||
|
|
Loading…
Reference in New Issue