1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 11:02:59 +02:00

Revert "[NewPM] Only invalidate modified functions' analyses in CGSCC passes"

This reverts commit d14d84af2f5ebb8ae2188ce6884a29a586dc0a40.

Causes unacceptable memory regressions.
This commit is contained in:
Arthur Eubanks 2021-05-21 16:14:08 -07:00
parent 6347acc246
commit 1514e1d07b
7 changed files with 126 additions and 133 deletions

View File

@ -858,7 +858,7 @@ incorporateNewSCCRange(const SCCRangeT &NewSCCRange, LazyCallGraph &G,
// split-off SCCs. // split-off SCCs.
// We know however that this will preserve any FAM proxy so go ahead and mark // We know however that this will preserve any FAM proxy so go ahead and mark
// that. // that.
auto PA = PreservedAnalyses::allInSet<AllAnalysesOn<Function>>(); PreservedAnalyses PA;
PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
AM.invalidate(*OldC, PA); AM.invalidate(*OldC, PA);

View File

@ -1019,12 +1019,11 @@ PreservedAnalyses ArgumentPromotionPass::run(LazyCallGraph::SCC &C,
do { do {
LocalChange = false; LocalChange = false;
FunctionAnalysisManager &FAM =
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
for (LazyCallGraph::Node &N : C) { for (LazyCallGraph::Node &N : C) {
Function &OldF = N.getFunction(); Function &OldF = N.getFunction();
FunctionAnalysisManager &FAM =
AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
// FIXME: This lambda must only be used with this function. We should // FIXME: This lambda must only be used with this function. We should
// skip the lambda and just get the AA results directly. // skip the lambda and just get the AA results directly.
auto AARGetter = [&](Function &F) -> AAResults & { auto AARGetter = [&](Function &F) -> AAResults & {
@ -1047,13 +1046,6 @@ PreservedAnalyses ArgumentPromotionPass::run(LazyCallGraph::SCC &C,
C.getOuterRefSCC().replaceNodeFunction(N, *NewF); C.getOuterRefSCC().replaceNodeFunction(N, *NewF);
FAM.clear(OldF, OldF.getName()); FAM.clear(OldF, OldF.getName());
OldF.eraseFromParent(); OldF.eraseFromParent();
PreservedAnalyses FuncPA;
FuncPA.preserveSet<CFGAnalyses>();
for (auto *U : NewF->users()) {
auto *UserF = cast<CallBase>(U)->getParent()->getParent();
FAM.invalidate(*UserF, FuncPA);
}
} }
Changed |= LocalChange; Changed |= LocalChange;
@ -1062,10 +1054,7 @@ PreservedAnalyses ArgumentPromotionPass::run(LazyCallGraph::SCC &C,
if (!Changed) if (!Changed)
return PreservedAnalyses::all(); return PreservedAnalyses::all();
PreservedAnalyses PA; return PreservedAnalyses::none();
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
PA.preserveSet<AllAnalysesOn<Function>>();
return PA;
} }
namespace { namespace {

View File

@ -240,8 +240,7 @@ MemoryAccessKind llvm::computeFunctionBodyMemoryAccess(Function &F,
/// Deduce readonly/readnone attributes for the SCC. /// Deduce readonly/readnone attributes for the SCC.
template <typename AARGetterT> template <typename AARGetterT>
static void addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter, static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
SmallSetVector<Function *, 8> &Changed) {
// Check if any of the functions in the SCC read or write memory. If they // 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. // write memory then they can't be marked readnone or readonly.
bool ReadsMemory = false; bool ReadsMemory = false;
@ -256,7 +255,7 @@ static void addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
switch (checkFunctionMemoryAccess(*F, F->hasExactDefinition(), switch (checkFunctionMemoryAccess(*F, F->hasExactDefinition(),
AAR, SCCNodes)) { AAR, SCCNodes)) {
case MAK_MayWrite: case MAK_MayWrite:
return; return false;
case MAK_ReadOnly: case MAK_ReadOnly:
ReadsMemory = true; ReadsMemory = true;
break; break;
@ -272,10 +271,11 @@ static void addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
// If the SCC contains both functions that read and functions that write, then // If the SCC contains both functions that read and functions that write, then
// we cannot add readonly attributes. // we cannot add readonly attributes.
if (ReadsMemory && WritesMemory) if (ReadsMemory && WritesMemory)
return; return false;
// Success! Functions in this SCC do not access memory, or only read memory. // Success! Functions in this SCC do not access memory, or only read memory.
// Give them the appropriate attribute. // Give them the appropriate attribute.
bool MadeChange = false;
for (Function *F : SCCNodes) { for (Function *F : SCCNodes) {
if (F->doesNotAccessMemory()) if (F->doesNotAccessMemory())
@ -289,7 +289,7 @@ static void addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
if (F->doesNotReadMemory() && WritesMemory) if (F->doesNotReadMemory() && WritesMemory)
continue; continue;
Changed.insert(F); MadeChange = true;
// Clear out any existing attributes. // Clear out any existing attributes.
AttrBuilder AttrsToRemove; AttrBuilder AttrsToRemove;
@ -318,6 +318,8 @@ static void addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter,
else else
++NumReadNone; ++NumReadNone;
} }
return MadeChange;
} }
namespace { namespace {
@ -579,8 +581,9 @@ determinePointerReadAttrs(Argument *A,
} }
/// Deduce returned attributes for the SCC. /// Deduce returned attributes for the SCC.
static void addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes, static bool addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) { bool Changed = false;
// Check each function in turn, determining if an argument is always returned. // Check each function in turn, determining if an argument is always returned.
for (Function *F : SCCNodes) { for (Function *F : SCCNodes) {
// We can infer and propagate function attributes only when we know that the // We can infer and propagate function attributes only when we know that the
@ -620,9 +623,11 @@ static void addArgumentReturnedAttrs(const SCCNodeSet &SCCNodes,
auto *A = cast<Argument>(RetArg); auto *A = cast<Argument>(RetArg);
A->addAttr(Attribute::Returned); A->addAttr(Attribute::Returned);
++NumReturned; ++NumReturned;
Changed.insert(F); Changed = true;
} }
} }
return Changed;
} }
/// If a callsite has arguments that are also arguments to the parent function, /// If a callsite has arguments that are also arguments to the parent function,
@ -688,8 +693,9 @@ static bool addReadAttr(Argument *A, Attribute::AttrKind R) {
} }
/// Deduce nocapture attributes for the SCC. /// Deduce nocapture attributes for the SCC.
static void addArgumentAttrs(const SCCNodeSet &SCCNodes, static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) { bool Changed = false;
ArgumentGraph AG; ArgumentGraph AG;
// Check each function in turn, determining which pointer arguments are not // Check each function in turn, determining which pointer arguments are not
@ -701,8 +707,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (!F->hasExactDefinition()) if (!F->hasExactDefinition())
continue; continue;
if (addArgumentAttrsFromCallsites(*F)) Changed |= addArgumentAttrsFromCallsites(*F);
Changed.insert(F);
// Functions that are readonly (or readnone) and nounwind and don't return // Functions that are readonly (or readnone) and nounwind and don't return
// a value can't capture arguments. Don't analyze them. // a value can't capture arguments. Don't analyze them.
@ -713,7 +718,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) { if (A->getType()->isPointerTy() && !A->hasNoCaptureAttr()) {
A->addAttr(Attribute::NoCapture); A->addAttr(Attribute::NoCapture);
++NumNoCapture; ++NumNoCapture;
Changed.insert(F); Changed = true;
} }
} }
continue; continue;
@ -732,7 +737,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
// If it's trivially not captured, mark it nocapture now. // If it's trivially not captured, mark it nocapture now.
A->addAttr(Attribute::NoCapture); A->addAttr(Attribute::NoCapture);
++NumNoCapture; ++NumNoCapture;
Changed.insert(F); Changed = true;
} else { } else {
// If it's not trivially captured and not trivially not captured, // If it's not trivially captured and not trivially not captured,
// then it must be calling into another function in our SCC. Save // then it must be calling into another function in our SCC. Save
@ -756,8 +761,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
Self.insert(&*A); Self.insert(&*A);
Attribute::AttrKind R = determinePointerReadAttrs(&*A, Self); Attribute::AttrKind R = determinePointerReadAttrs(&*A, Self);
if (R != Attribute::None) if (R != Attribute::None)
if (addReadAttr(A, R)) Changed = addReadAttr(A, R);
Changed.insert(F);
} }
} }
} }
@ -781,7 +785,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
Argument *A = ArgumentSCC[0]->Definition; Argument *A = ArgumentSCC[0]->Definition;
A->addAttr(Attribute::NoCapture); A->addAttr(Attribute::NoCapture);
++NumNoCapture; ++NumNoCapture;
Changed.insert(A->getParent()); Changed = true;
} }
continue; continue;
} }
@ -823,7 +827,7 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
Argument *A = ArgumentSCC[i]->Definition; Argument *A = ArgumentSCC[i]->Definition;
A->addAttr(Attribute::NoCapture); A->addAttr(Attribute::NoCapture);
++NumNoCapture; ++NumNoCapture;
Changed.insert(A->getParent()); Changed = true;
} }
// We also want to compute readonly/readnone. With a small number of false // We also want to compute readonly/readnone. With a small number of false
@ -854,11 +858,12 @@ static void addArgumentAttrs(const SCCNodeSet &SCCNodes,
if (ReadAttr != Attribute::None) { if (ReadAttr != Attribute::None) {
for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) { for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
Argument *A = ArgumentSCC[i]->Definition; Argument *A = ArgumentSCC[i]->Definition;
if (addReadAttr(A, ReadAttr)) Changed = addReadAttr(A, ReadAttr);
Changed.insert(A->getParent());
} }
} }
} }
return Changed;
} }
/// Tests whether a function is "malloc-like". /// Tests whether a function is "malloc-like".
@ -929,8 +934,7 @@ static bool isFunctionMallocLike(Function *F, const SCCNodeSet &SCCNodes) {
} }
/// Deduce noalias attributes for the SCC. /// Deduce noalias attributes for the SCC.
static void addNoAliasAttrs(const SCCNodeSet &SCCNodes, static bool addNoAliasAttrs(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) {
// Check each function in turn, determining which functions return noalias // Check each function in turn, determining which functions return noalias
// pointers. // pointers.
for (Function *F : SCCNodes) { for (Function *F : SCCNodes) {
@ -942,7 +946,7 @@ static void addNoAliasAttrs(const SCCNodeSet &SCCNodes,
// definition we'll get at link time is *exactly* the definition we see now. // definition we'll get at link time is *exactly* the definition we see now.
// For more details, see GlobalValue::mayBeDerefined. // For more details, see GlobalValue::mayBeDerefined.
if (!F->hasExactDefinition()) if (!F->hasExactDefinition())
return; return false;
// We annotate noalias return values, which are only applicable to // We annotate noalias return values, which are only applicable to
// pointer types. // pointer types.
@ -950,9 +954,10 @@ static void addNoAliasAttrs(const SCCNodeSet &SCCNodes,
continue; continue;
if (!isFunctionMallocLike(F, SCCNodes)) if (!isFunctionMallocLike(F, SCCNodes))
return; return false;
} }
bool MadeChange = false;
for (Function *F : SCCNodes) { for (Function *F : SCCNodes) {
if (F->returnDoesNotAlias() || if (F->returnDoesNotAlias() ||
!F->getReturnType()->isPointerTy()) !F->getReturnType()->isPointerTy())
@ -960,8 +965,10 @@ static void addNoAliasAttrs(const SCCNodeSet &SCCNodes,
F->setReturnDoesNotAlias(); F->setReturnDoesNotAlias();
++NumNoAlias; ++NumNoAlias;
Changed.insert(F); MadeChange = true;
} }
return MadeChange;
} }
/// Tests whether this function is known to not return null. /// Tests whether this function is known to not return null.
@ -1037,12 +1044,13 @@ static bool isReturnNonNull(Function *F, const SCCNodeSet &SCCNodes,
} }
/// Deduce nonnull attributes for the SCC. /// Deduce nonnull attributes for the SCC.
static void addNonNullAttrs(const SCCNodeSet &SCCNodes, static bool addNonNullAttrs(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) {
// Speculative that all functions in the SCC return only nonnull // Speculative that all functions in the SCC return only nonnull
// pointers. We may refute this as we analyze functions. // pointers. We may refute this as we analyze functions.
bool SCCReturnsNonNull = true; bool SCCReturnsNonNull = true;
bool MadeChange = false;
// Check each function in turn, determining which functions return nonnull // Check each function in turn, determining which functions return nonnull
// pointers. // pointers.
for (Function *F : SCCNodes) { for (Function *F : SCCNodes) {
@ -1055,7 +1063,7 @@ static void addNonNullAttrs(const SCCNodeSet &SCCNodes,
// definition we'll get at link time is *exactly* the definition we see now. // definition we'll get at link time is *exactly* the definition we see now.
// For more details, see GlobalValue::mayBeDerefined. // For more details, see GlobalValue::mayBeDerefined.
if (!F->hasExactDefinition()) if (!F->hasExactDefinition())
return; return false;
// We annotate nonnull return values, which are only applicable to // We annotate nonnull return values, which are only applicable to
// pointer types. // pointer types.
@ -1071,7 +1079,7 @@ static void addNonNullAttrs(const SCCNodeSet &SCCNodes,
<< " as nonnull\n"); << " as nonnull\n");
F->addAttribute(AttributeList::ReturnIndex, Attribute::NonNull); F->addAttribute(AttributeList::ReturnIndex, Attribute::NonNull);
++NumNonNullReturn; ++NumNonNullReturn;
Changed.insert(F); MadeChange = true;
} }
continue; continue;
} }
@ -1090,9 +1098,11 @@ static void addNonNullAttrs(const SCCNodeSet &SCCNodes,
LLVM_DEBUG(dbgs() << "SCC marking " << F->getName() << " as nonnull\n"); LLVM_DEBUG(dbgs() << "SCC marking " << F->getName() << " as nonnull\n");
F->addAttribute(AttributeList::ReturnIndex, Attribute::NonNull); F->addAttribute(AttributeList::ReturnIndex, Attribute::NonNull);
++NumNonNullReturn; ++NumNonNullReturn;
Changed.insert(F); MadeChange = true;
} }
} }
return MadeChange;
} }
namespace { namespace {
@ -1145,13 +1155,12 @@ public:
InferenceDescriptors.push_back(AttrInference); InferenceDescriptors.push_back(AttrInference);
} }
void run(const SCCNodeSet &SCCNodes, SmallSetVector<Function *, 8> &Changed); bool run(const SCCNodeSet &SCCNodes);
}; };
/// Perform all the requested attribute inference actions according to the /// Perform all the requested attribute inference actions according to the
/// attribute predicates stored before. /// attribute predicates stored before.
void AttributeInferer::run(const SCCNodeSet &SCCNodes, bool AttributeInferer::run(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) {
SmallVector<InferenceDescriptor, 4> InferInSCC = InferenceDescriptors; SmallVector<InferenceDescriptor, 4> InferInSCC = InferenceDescriptors;
// Go through all the functions in SCC and check corresponding attribute // Go through all the functions in SCC and check corresponding attribute
// assumptions for each of them. Attributes that are invalid for this SCC // assumptions for each of them. Attributes that are invalid for this SCC
@ -1160,7 +1169,7 @@ void AttributeInferer::run(const SCCNodeSet &SCCNodes,
// No attributes whose assumptions are still valid - done. // No attributes whose assumptions are still valid - done.
if (InferInSCC.empty()) if (InferInSCC.empty())
return; return false;
// Check if our attributes ever need scanning/can be scanned. // Check if our attributes ever need scanning/can be scanned.
llvm::erase_if(InferInSCC, [F](const InferenceDescriptor &ID) { llvm::erase_if(InferInSCC, [F](const InferenceDescriptor &ID) {
@ -1203,8 +1212,9 @@ void AttributeInferer::run(const SCCNodeSet &SCCNodes,
} }
if (InferInSCC.empty()) if (InferInSCC.empty())
return; return false;
bool Changed = false;
for (Function *F : SCCNodes) for (Function *F : SCCNodes)
// At this point InferInSCC contains only functions that were either: // At this point InferInSCC contains only functions that were either:
// - explicitly skipped from scan/inference, or // - explicitly skipped from scan/inference, or
@ -1213,9 +1223,10 @@ void AttributeInferer::run(const SCCNodeSet &SCCNodes,
for (auto &ID : InferInSCC) { for (auto &ID : InferInSCC) {
if (ID.SkipFunction(*F)) if (ID.SkipFunction(*F))
continue; continue;
Changed.insert(F); Changed = true;
ID.SetAttribute(*F); ID.SetAttribute(*F);
} }
return Changed;
} }
struct SCCNodesResult { struct SCCNodesResult {
@ -1271,8 +1282,7 @@ static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes) {
/// Attempt to remove convergent function attribute when possible. /// Attempt to remove convergent function attribute when possible.
/// ///
/// Returns true if any changes to function attributes were made. /// Returns true if any changes to function attributes were made.
static void inferConvergent(const SCCNodeSet &SCCNodes, static bool inferConvergent(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) {
AttributeInferer AI; AttributeInferer AI;
// Request to remove the convergent attribute from all functions in the SCC // Request to remove the convergent attribute from all functions in the SCC
@ -1295,7 +1305,7 @@ static void inferConvergent(const SCCNodeSet &SCCNodes,
}, },
/* RequiresExactDefinition= */ false}); /* RequiresExactDefinition= */ false});
// Perform all the requested attribute inference actions. // Perform all the requested attribute inference actions.
AI.run(SCCNodes, Changed); return AI.run(SCCNodes);
} }
/// Infer attributes from all functions in the SCC by scanning every /// Infer attributes from all functions in the SCC by scanning every
@ -1304,9 +1314,7 @@ static void inferConvergent(const SCCNodeSet &SCCNodes,
/// - addition of NoUnwind attribute /// - addition of NoUnwind attribute
/// ///
/// Returns true if any changes to function attributes were made. /// Returns true if any changes to function attributes were made.
static void static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) {
inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes,
SmallSetVector<Function *, 8> &Changed) {
AttributeInferer AI; AttributeInferer AI;
if (!DisableNoUnwindInference) if (!DisableNoUnwindInference)
@ -1355,20 +1363,19 @@ inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes,
/* RequiresExactDefinition= */ true}); /* RequiresExactDefinition= */ true});
// Perform all the requested attribute inference actions. // Perform all the requested attribute inference actions.
AI.run(SCCNodes, Changed); return AI.run(SCCNodes);
} }
static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes, static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) {
// Try and identify functions that do not recurse. // Try and identify functions that do not recurse.
// If the SCC contains multiple nodes we know for sure there is recursion. // If the SCC contains multiple nodes we know for sure there is recursion.
if (SCCNodes.size() != 1) if (SCCNodes.size() != 1)
return; return false;
Function *F = *SCCNodes.begin(); Function *F = *SCCNodes.begin();
if (!F || !F->hasExactDefinition() || F->doesNotRecurse()) if (!F || !F->hasExactDefinition() || F->doesNotRecurse())
return; return false;
// If all of the calls in F are identifiable and are to norecurse functions, F // 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 // is norecurse. This check also detects self-recursion as F is not currently
@ -1379,7 +1386,7 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
Function *Callee = CB->getCalledFunction(); Function *Callee = CB->getCalledFunction();
if (!Callee || Callee == F || !Callee->doesNotRecurse()) if (!Callee || Callee == F || !Callee->doesNotRecurse())
// Function calls a potentially recursive function. // Function calls a potentially recursive function.
return; return false;
} }
// Every call was to a non-recursive function other than this function, and // Every call was to a non-recursive function other than this function, and
@ -1387,7 +1394,7 @@ static void addNoRecurseAttrs(const SCCNodeSet &SCCNodes,
// recurse. // recurse.
F->setDoesNotRecurse(); F->setDoesNotRecurse();
++NumNoRecurse; ++NumNoRecurse;
Changed.insert(F); return true;
} }
static bool instructionDoesNotReturn(Instruction &I) { static bool instructionDoesNotReturn(Instruction &I) {
@ -1405,8 +1412,9 @@ static bool basicBlockCanReturn(BasicBlock &BB) {
} }
// Set the noreturn function attribute if possible. // Set the noreturn function attribute if possible.
static void addNoReturnAttrs(const SCCNodeSet &SCCNodes, static bool addNoReturnAttrs(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) { bool Changed = false;
for (Function *F : SCCNodes) { for (Function *F : SCCNodes) {
if (!F || !F->hasExactDefinition() || F->hasFnAttribute(Attribute::Naked) || if (!F || !F->hasExactDefinition() || F->hasFnAttribute(Attribute::Naked) ||
F->doesNotReturn()) F->doesNotReturn())
@ -1416,9 +1424,11 @@ static void addNoReturnAttrs(const SCCNodeSet &SCCNodes,
// FIXME: this doesn't handle recursion or unreachable blocks. // FIXME: this doesn't handle recursion or unreachable blocks.
if (none_of(*F, basicBlockCanReturn)) { if (none_of(*F, basicBlockCanReturn)) {
F->setDoesNotReturn(); F->setDoesNotReturn();
Changed.insert(F); Changed = true;
} }
} }
return Changed;
} }
static bool functionWillReturn(const Function &F) { static bool functionWillReturn(const Function &F) {
@ -1451,16 +1461,19 @@ static bool functionWillReturn(const Function &F) {
} }
// Set the willreturn function attribute if possible. // Set the willreturn function attribute if possible.
static void addWillReturn(const SCCNodeSet &SCCNodes, static bool addWillReturn(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) { bool Changed = false;
for (Function *F : SCCNodes) { for (Function *F : SCCNodes) {
if (!F || F->willReturn() || !functionWillReturn(*F)) if (!F || F->willReturn() || !functionWillReturn(*F))
continue; continue;
F->setWillReturn(); F->setWillReturn();
NumWillReturn++; NumWillReturn++;
Changed.insert(F); Changed = true;
} }
return Changed;
} }
// Return true if this is an atomic which has an ordering stronger than // Return true if this is an atomic which has an ordering stronger than
@ -1519,8 +1532,7 @@ static bool InstrBreaksNoSync(Instruction &I, const SCCNodeSet &SCCNodes) {
} }
// Infer the nosync attribute. // Infer the nosync attribute.
static void addNoSyncAttr(const SCCNodeSet &SCCNodes, static bool addNoSyncAttr(const SCCNodeSet &SCCNodes) {
SmallSetVector<Function *, 8> &Changed) {
AttributeInferer AI; AttributeInferer AI;
AI.registerAttrInference(AttributeInferer::InferenceDescriptor{ AI.registerAttrInference(AttributeInferer::InferenceDescriptor{
Attribute::NoSync, Attribute::NoSync,
@ -1537,7 +1549,7 @@ static void addNoSyncAttr(const SCCNodeSet &SCCNodes,
++NumNoSync; ++NumNoSync;
}, },
/* RequiresExactDefinition= */ true}); /* RequiresExactDefinition= */ true});
AI.run(SCCNodes, Changed); return AI.run(SCCNodes);
} }
static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) { static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
@ -1570,33 +1582,32 @@ static SCCNodesResult createSCCNodeSet(ArrayRef<Function *> Functions) {
} }
template <typename AARGetterT> template <typename AARGetterT>
static SmallSetVector<Function *, 8> static bool deriveAttrsInPostOrder(ArrayRef<Function *> Functions,
deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter) { AARGetterT &&AARGetter) {
SCCNodesResult Nodes = createSCCNodeSet(Functions); SCCNodesResult Nodes = createSCCNodeSet(Functions);
bool Changed = false;
// Bail if the SCC only contains optnone functions. // Bail if the SCC only contains optnone functions.
if (Nodes.SCCNodes.empty()) if (Nodes.SCCNodes.empty())
return {}; return Changed;
SmallSetVector<Function *, 8> Changed; Changed |= addArgumentReturnedAttrs(Nodes.SCCNodes);
Changed |= addReadAttrs(Nodes.SCCNodes, AARGetter);
addArgumentReturnedAttrs(Nodes.SCCNodes, Changed); Changed |= addArgumentAttrs(Nodes.SCCNodes);
addReadAttrs(Nodes.SCCNodes, AARGetter, Changed); Changed |= inferConvergent(Nodes.SCCNodes);
addArgumentAttrs(Nodes.SCCNodes, Changed); Changed |= addNoReturnAttrs(Nodes.SCCNodes);
inferConvergent(Nodes.SCCNodes, Changed); Changed |= addWillReturn(Nodes.SCCNodes);
addNoReturnAttrs(Nodes.SCCNodes, Changed);
addWillReturn(Nodes.SCCNodes, Changed);
// If we have no external nodes participating in the SCC, we can deduce some // If we have no external nodes participating in the SCC, we can deduce some
// more precise attributes as well. // more precise attributes as well.
if (!Nodes.HasUnknownCall) { if (!Nodes.HasUnknownCall) {
addNoAliasAttrs(Nodes.SCCNodes, Changed); Changed |= addNoAliasAttrs(Nodes.SCCNodes);
addNonNullAttrs(Nodes.SCCNodes, Changed); Changed |= addNonNullAttrs(Nodes.SCCNodes);
inferAttrsFromFunctionBodies(Nodes.SCCNodes, Changed); Changed |= inferAttrsFromFunctionBodies(Nodes.SCCNodes);
addNoRecurseAttrs(Nodes.SCCNodes, Changed); Changed |= addNoRecurseAttrs(Nodes.SCCNodes);
} }
addNoSyncAttr(Nodes.SCCNodes, Changed); Changed |= addNoSyncAttr(Nodes.SCCNodes);
// Finally, infer the maximal set of attributes from the ones we've inferred // 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 // above. This is handling the cases where one attribute on a signature
@ -1604,8 +1615,7 @@ deriveAttrsInPostOrder(ArrayRef<Function *> Functions, AARGetterT &&AARGetter) {
// the later is missing (or simply less sophisticated). // the later is missing (or simply less sophisticated).
for (Function *F : Nodes.SCCNodes) for (Function *F : Nodes.SCCNodes)
if (F) if (F)
if (inferAttributesFromOthers(*F)) Changed |= inferAttributesFromOthers(*F);
Changed.insert(F);
return Changed; return Changed;
} }
@ -1628,24 +1638,14 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C,
Functions.push_back(&N.getFunction()); Functions.push_back(&N.getFunction());
} }
auto ChangedFunctions = deriveAttrsInPostOrder(Functions, AARGetter); if (deriveAttrsInPostOrder(Functions, AARGetter)) {
if (ChangedFunctions.empty()) { // We have not changed the call graph or removed/added functions.
return PreservedAnalyses::all(); PreservedAnalyses PA;
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
return PA;
} }
// Invalidate analyses for modified functions so that we don't have to return PreservedAnalyses::all();
// invalidate all analyses for all functions in this SCC.
PreservedAnalyses FuncPA;
// We haven't changed the CFG for modified functions.
FuncPA.preserveSet<CFGAnalyses>();
for (Function *Changed : ChangedFunctions)
FAM.invalidate(*Changed, FuncPA);
// We have not changed the call graph or removed/added functions.
PreservedAnalyses PA;
PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
PA.preserveSet<AllAnalysesOn<Function>>();
return PA;
} }
namespace { namespace {
@ -1690,7 +1690,7 @@ static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) {
Functions.push_back(I->getFunction()); Functions.push_back(I->getFunction());
} }
return !deriveAttrsInPostOrder(Functions, AARGetter).empty(); return deriveAttrsInPostOrder(Functions, AARGetter);
} }
bool PostOrderFunctionAttrsLegacyPass::runOnSCC(CallGraphSCC &SCC) { bool PostOrderFunctionAttrsLegacyPass::runOnSCC(CallGraphSCC &SCC) {

View File

@ -951,10 +951,6 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
UR.InlinedInternalEdges.insert({&N, OldC}); UR.InlinedInternalEdges.insert({&N, OldC});
} }
InlinedCallees.clear(); InlinedCallees.clear();
// Invalidate analyses for this function now so that we don't have to
// invalidate analyses for all functions in this SCC later.
FAM.invalidate(F, PreservedAnalyses::none());
} }
// Now that we've finished inlining all of the calls across this SCC, delete // Now that we've finished inlining all of the calls across this SCC, delete
@ -994,12 +990,10 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC,
if (!Changed) if (!Changed)
return PreservedAnalyses::all(); return PreservedAnalyses::all();
PreservedAnalyses PA;
// Even if we change the IR, we update the core CGSCC data structures and so // Even if we change the IR, we update the core CGSCC data structures and so
// can preserve the proxy to the function analysis manager. // can preserve the proxy to the function analysis manager.
PreservedAnalyses PA;
PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
// We have already invalidated all analyses on modified functions.
PA.preserveSet<AllAnalysesOn<Function>>();
return PA; return PA;
} }

View File

@ -398,11 +398,19 @@
; NEWPM-NEXT: Running pass: InlinerPass on (f) ; NEWPM-NEXT: Running pass: InlinerPass on (f)
; NEWPM-NEXT: Running pass: PostOrderFunctionAttrsPass on (f) ; NEWPM-NEXT: Running pass: PostOrderFunctionAttrsPass on (f)
; NEWPM-NEXT: Running analysis: AAManager on f ; NEWPM-NEXT: Running analysis: AAManager on f
; NEWPM-NEXT: Invalidating analysis: PreservedCFGCheckerAnalysis on f
; NEWPM-NEXT: Invalidating analysis: DominatorTreeAnalysis on f
; NEWPM-NEXT: Invalidating analysis: BasicAA on f
; NEWPM-NEXT: Invalidating analysis: AAManager on f
; NEWPM-NEXT: Running pass: ArgumentPromotionPass on (f) ; NEWPM-NEXT: Running pass: ArgumentPromotionPass on (f)
; NEWPM-NEXT: Running pass: OpenMPOptCGSCCPass on (f) ; NEWPM-NEXT: Running pass: OpenMPOptCGSCCPass on (f)
; NEWPM-NEXT: Running analysis: PreservedCFGCheckerAnalysis on f
; NEWPM-NEXT: Running pass: SROA on f ; NEWPM-NEXT: Running pass: SROA on f
; NEWPM-NEXT: Running analysis: DominatorTreeAnalysis on f
; NEWPM-NEXT: Running pass: EarlyCSEPass on f ; NEWPM-NEXT: Running pass: EarlyCSEPass on f
; NEWPM-NEXT: Running analysis: MemorySSAAnalysis on f ; NEWPM-NEXT: Running analysis: MemorySSAAnalysis on f
; NEWPM-NEXT: Running analysis: AAManager on f
; NEWPM-NEXT: Running analysis: BasicAA on f
; NEWPM-NEXT: Running pass: SpeculativeExecutionPass on f ; NEWPM-NEXT: Running pass: SpeculativeExecutionPass on f
; NEWPM-NEXT: Running pass: JumpThreadingPass on f ; NEWPM-NEXT: Running pass: JumpThreadingPass on f
; NEWPM-NEXT: Running analysis: LazyValueAnalysis on f ; NEWPM-NEXT: Running analysis: LazyValueAnalysis on f
@ -444,6 +452,16 @@
; NEWPM-NEXT: Running pass: LCSSAPass on f ; NEWPM-NEXT: Running pass: LCSSAPass on f
; NEWPM-NEXT: Running pass: SimplifyCFGPass on f ; NEWPM-NEXT: Running pass: SimplifyCFGPass on f
; NEWPM-NEXT: Running pass: InstCombinePass on f ; NEWPM-NEXT: Running pass: InstCombinePass on f
; NEWPM-NEXT: Invalidating analysis: PreservedCFGCheckerAnalysis on f
; NEWPM-NEXT: Invalidating analysis: DominatorTreeAnalysis on f
; NEWPM-NEXT: Invalidating analysis: BasicAA on f
; NEWPM-NEXT: Invalidating analysis: AAManager on f
; NEWPM-NEXT: Invalidating analysis: MemorySSAAnalysis on f
; NEWPM-NEXT: Invalidating analysis: LoopAnalysis on f
; NEWPM-NEXT: Invalidating analysis: PhiValuesAnalysis on f
; NEWPM-NEXT: Invalidating analysis: MemoryDependenceAnalysis on f
; NEWPM-NEXT: Invalidating analysis: DemandedBitsAnalysis on f
; NEWPM-NEXT: Invalidating analysis: PostDominatorTreeAnalysis on f
; NEWPM-NEXT: Invalidating analysis: CallGraphAnalysis on ; NEWPM-NEXT: Invalidating analysis: CallGraphAnalysis on
; NEWPM-NEXT: Running pass: GlobalOptPass on ; NEWPM-NEXT: Running pass: GlobalOptPass on
; NEWPM-NEXT: Running pass: GlobalDCEPass on ; NEWPM-NEXT: Running pass: GlobalDCEPass on
@ -451,9 +469,14 @@
; NEWPM-NEXT: Running pass: ReversePostOrderFunctionAttrsPass on ; NEWPM-NEXT: Running pass: ReversePostOrderFunctionAttrsPass on
; NEWPM-NEXT: Running analysis: CallGraphAnalysis on ; NEWPM-NEXT: Running analysis: CallGraphAnalysis on
; NEWPM-NEXT: Running pass: RequireAnalysisPass<{{.*}}GlobalsAA ; NEWPM-NEXT: Running pass: RequireAnalysisPass<{{.*}}GlobalsAA
; NEWPM-NEXT: Running analysis: PreservedCFGCheckerAnalysis on f
; NEWPM-NEXT: Running pass: Float2IntPass on f ; NEWPM-NEXT: Running pass: Float2IntPass on f
; NEWPM-NEXT: Running analysis: DominatorTreeAnalysis on f
; NEWPM-NEXT: Running pass: LowerConstantIntrinsicsPass on f ; NEWPM-NEXT: Running pass: LowerConstantIntrinsicsPass on f
; NEWPM-NEXT: Running pass: LowerMatrixIntrinsicsPass on f ; NEWPM-NEXT: Running pass: LowerMatrixIntrinsicsPass on f
; NEWPM-NEXT: Running analysis: AAManager on f
; NEWPM-NEXT: Running analysis: BasicAA on f
; NEWPM-NEXT: Running analysis: LoopAnalysis on f
; NEWPM-NEXT: Running pass: EarlyCSEPass on f ; NEWPM-NEXT: Running pass: EarlyCSEPass on f
; NEWPM-NEXT: Running pass: LoopSimplifyPass on f ; NEWPM-NEXT: Running pass: LoopSimplifyPass on f
; NEWPM-NEXT: Running pass: LCSSAPass on f ; NEWPM-NEXT: Running pass: LCSSAPass on f
@ -464,6 +487,9 @@
; NEWPM-NEXT: Running pass: LoopVectorizePass on f ; NEWPM-NEXT: Running pass: LoopVectorizePass on f
; NEWPM-NEXT: Running analysis: BlockFrequencyAnalysis on f ; NEWPM-NEXT: Running analysis: BlockFrequencyAnalysis on f
; NEWPM-NEXT: Running analysis: BranchProbabilityAnalysis on f ; NEWPM-NEXT: Running analysis: BranchProbabilityAnalysis on f
; NEWPM-NEXT: Running analysis: PostDominatorTreeAnalysis on f
; NEWPM-NEXT: Running analysis: DemandedBitsAnalysis on f
; NEWPM-NEXT: Running analysis: MemorySSAAnalysis on f
; NEWPM-NEXT: Running pass: LoopLoadEliminationPass on f ; NEWPM-NEXT: Running pass: LoopLoadEliminationPass on f
; NEWPM-NEXT: Running pass: InstCombinePass on f ; NEWPM-NEXT: Running pass: InstCombinePass on f
; NEWPM-NEXT: Running pass: SimplifyCFGPass on f ; NEWPM-NEXT: Running pass: SimplifyCFGPass on f

View File

@ -1,17 +0,0 @@
; RUN: opt -passes=inliner-wrapper < %s -disable-output -debug-pass-manager 2>&1 | FileCheck %s
; We shouldn't invalidate any function analyses on g since it's never modified.
; CHECK-NOT: Invalidating{{.*}} on g
; CHECK: Invalidating{{.*}} on f
; CHECK-NOT: Invalidating{{.*}} on g
define void @f() {
call void @g()
ret void
}
define void @g() alwaysinline {
call void @f()
ret void
}

View File

@ -8,11 +8,11 @@
; ;
; CHECK: Running pass: InlinerPass on (test1_f, test1_g, test1_h) ; CHECK: Running pass: InlinerPass on (test1_f, test1_g, test1_h)
; CHECK: Running analysis: DominatorTreeAnalysis on test1_f ; CHECK: Running analysis: DominatorTreeAnalysis on test1_f
; CHECK: Running analysis: DominatorTreeAnalysis on test1_g
; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_f ; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_f
; CHECK: Invalidating analysis: LoopAnalysis on test1_f ; CHECK: Invalidating analysis: LoopAnalysis on test1_f
; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_f ; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_f
; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_f ; CHECK: Invalidating analysis: BlockFrequencyAnalysis on test1_f
; CHECK: Running analysis: DominatorTreeAnalysis on test1_g
; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_g ; CHECK: Invalidating analysis: DominatorTreeAnalysis on test1_g
; CHECK: Invalidating analysis: LoopAnalysis on test1_g ; CHECK: Invalidating analysis: LoopAnalysis on test1_g
; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_g ; CHECK: Invalidating analysis: BranchProbabilityAnalysis on test1_g
@ -29,6 +29,7 @@
; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_h ; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_h
; CHECK-NOT: Invalidating analysis: ; CHECK-NOT: Invalidating analysis:
; CHECK: Running pass: DominatorTreeVerifierPass on test1_f ; CHECK: Running pass: DominatorTreeVerifierPass on test1_f
; CHECK-NEXT: Running analysis: DominatorTreeAnalysis on test1_f
; An external function used to control branches. ; An external function used to control branches.
declare i1 @flag() declare i1 @flag()