diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index 60cc874d4d4..2445b7f3c8a 100644 --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -935,6 +935,68 @@ static bool addNonNullAttrs(const SCCNodeSet &SCCNodes, return MadeChange; } +/// Removes convergent attributes where we can prove that none of the SCC's +/// callees are themselves convergent. Returns true if successful at removing +/// the attribute. +static bool removeConvergentAttrs(const CallGraphSCC &SCC, + const SCCNodeSet &SCCNodes) { + // Determines whether a function can be made non-convergent, ignoring all + // other functions in SCC. (A function can *actually* be made non-convergent + // only if all functions in its SCC can be made convergent.) + auto CanRemoveConvergent = [&] (CallGraphNode *CGN) { + Function *F = CGN->getFunction(); + if (!F) return false; + + if (!F->isConvergent()) return true; + + // Can't remove convergent from declarations. + if (F->isDeclaration()) return false; + + // Don't remove convergent from optnone functions. + if (F->hasFnAttribute(Attribute::OptimizeNone)) + return false; + + // Can't remove convergent if any of F's callees -- ignoring functions in the + // SCC itself -- are convergent. + if (llvm::any_of(*CGN, [&](const CallGraphNode::CallRecord &CR) { + Function *F = CR.second->getFunction(); + return SCCNodes.count(F) == 0 && (!F || F->isConvergent()); + })) + return false; + + // CGN doesn't contain calls to intrinsics, so iterate over all of F's + // callsites, looking for any calls to convergent intrinsics. If we find one, + // F must remain marked as convergent. + auto IsConvergentIntrinsicCall = [](Instruction &I) { + CallSite CS(cast<Value>(&I)); + if (!CS) + return false; + Function *Callee = CS.getCalledFunction(); + return Callee && Callee->isIntrinsic() && Callee->isConvergent(); + }; + return !llvm::any_of(*F, [=](BasicBlock &BB) { + return llvm::any_of(BB, IsConvergentIntrinsicCall); + }); + }; + + // We can remove the convergent attr from functions in the SCC if they all can + // be made non-convergent (because they call only non-convergent functions, + // other than each other). + if (!llvm::all_of(SCC, CanRemoveConvergent)) return false; + + // If we got here, all of the SCC's callees are non-convergent, and none of + // the optnone functions in the SCC are marked as convergent. Therefore all + // of the SCC's functions can be marked as non-convergent. + for (CallGraphNode *CGN : SCC) + if (Function *F = CGN->getFunction()) { + if (F->isConvergent()) + DEBUG(dbgs() << "Removing convergent attr from " << F->getName() + << "\n"); + F->setNotConvergent(); + } + return true; +} + static bool setDoesNotRecurse(Function &F) { if (F.doesNotRecurse()) return false; @@ -1011,6 +1073,7 @@ bool PostOrderFunctionAttrs::runOnSCC(CallGraphSCC &SCC) { if (!ExternalNode) { Changed |= addNoAliasAttrs(SCCNodes); Changed |= addNonNullAttrs(SCCNodes, *TLI); + Changed |= removeConvergentAttrs(SCC, SCCNodes); } Changed |= addNoRecurseAttrs(SCC); |