[SILOptimizer] Turn "is self-recursive" check into analysis

The body of a function has to be re-analyzed for every call
site of the function, which is very expensive and if the
body is not changed would produce the same result.

This takes about ~10% from swift-syntax overall build time
in release configuration.
This commit is contained in:
Pavel Yaskevich
2025-03-24 00:22:37 -07:00
parent a59a2a1690
commit 41c88f864a
8 changed files with 154 additions and 31 deletions

View File

@@ -18,6 +18,7 @@
#include "swift/SIL/PatternMatch.h"
#include "swift/SIL/SILCloner.h"
#include "swift/SILOptimizer/Analysis/LoopAnalysis.h"
#include "swift/SILOptimizer/Analysis/IsSelfRecursiveAnalysis.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/SILOptimizer/PassManager/Transforms.h"
#include "swift/SILOptimizer/Utils/BasicBlockOptUtils.h"
@@ -209,7 +210,8 @@ static std::optional<uint64_t> getMaxLoopTripCount(SILLoop *Loop,
/// Check whether we can duplicate the instructions in the loop and use a
/// heuristic that looks at the trip count and the cost of the instructions in
/// the loop to determine whether we should unroll this loop.
static bool canAndShouldUnrollLoop(SILLoop *Loop, uint64_t TripCount) {
static bool canAndShouldUnrollLoop(SILLoop *Loop, uint64_t TripCount,
IsSelfRecursiveAnalysis *SRA) {
assert(Loop->getSubLoops().empty() && "Expect innermost loops");
if (TripCount > 32)
return false;
@@ -231,7 +233,7 @@ static bool canAndShouldUnrollLoop(SILLoop *Loop, uint64_t TripCount) {
++Cost;
if (auto AI = FullApplySite::isa(&Inst)) {
auto Callee = AI.getCalleeFunction();
if (Callee && getEligibleFunction(AI, InlineSelection::Everything)) {
if (Callee && getEligibleFunction(AI, InlineSelection::Everything, SRA)) {
// If callee is rather big and potentially inlinable, it may be better
// not to unroll, so that the body of the callee can be inlined later.
Cost += Callee->size() * InsnsPerBB;
@@ -386,7 +388,7 @@ updateSSA(SILFunction *Fn, SILLoop *Loop,
/// Try to fully unroll the loop if we can determine the trip count and the trip
/// count is below a threshold.
static bool tryToUnrollLoop(SILLoop *Loop) {
static bool tryToUnrollLoop(SILLoop *Loop, IsSelfRecursiveAnalysis *SRA) {
assert(Loop->getSubLoops().empty() && "Expecting innermost loops");
LLVM_DEBUG(llvm::dbgs() << "Trying to unroll loop : \n" << *Loop);
@@ -407,7 +409,7 @@ static bool tryToUnrollLoop(SILLoop *Loop) {
return false;
}
if (!canAndShouldUnrollLoop(Loop, MaxTripCount.value())) {
if (!canAndShouldUnrollLoop(Loop, MaxTripCount.value(), SRA)) {
LLVM_DEBUG(llvm::dbgs() << "Not unrolling, exceeds cost threshold\n");
return false;
}
@@ -487,6 +489,7 @@ class LoopUnrolling : public SILFunctionTransform {
bool Changed = false;
auto *Fun = getFunction();
SILLoopInfo *LoopInfo = PM->getAnalysis<SILLoopAnalysis>()->get(Fun);
IsSelfRecursiveAnalysis *SRA = PM->getAnalysis<IsSelfRecursiveAnalysis>();
LLVM_DEBUG(llvm::dbgs() << "Loop Unroll running on function : "
<< Fun->getName() << "\n");
@@ -514,7 +517,7 @@ class LoopUnrolling : public SILFunctionTransform {
// Try to unroll innermost loops.
for (auto *Loop : InnermostLoops)
Changed |= tryToUnrollLoop(Loop);
Changed |= tryToUnrollLoop(Loop, SRA);
if (Changed) {
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);