Skip to content

Commit

Permalink
Disallow inlining of self-recursive functions into other functions.
Browse files Browse the repository at this point in the history
This effectively returns us to the code from dc65f70.

With the recent pass manager changes, combined with upcoming inliner
changes, we can potentially run the inliner more than we currently
do. Allowing self-recursive functions to be inlined, and running the
inliner more often, can result in a lot of code bloat, which increases
binary sizes and compile times. Even with a relatively small value (10)
for the number of times we allow a function to run through the pass
pipeline, we end up with a significant increase in the stdlib and
stdlib unit test build times.

This results in some performance regressions, but I think the trade-off
here is reasonable.
  • Loading branch information
rudkx committed Feb 3, 2016
1 parent a83089b commit a971646
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 21 deletions.
24 changes: 7 additions & 17 deletions lib/SILOptimizer/IPO/PerformanceInliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,22 +547,13 @@ bool SILPerformanceInliner::hasInliningCycle(SILFunction *Caller,
return InlinedBefore;
}

// Return true if the callee does few (or no) self-recursive calls.
static bool calleeHasMinimalSelfRecursion(SILFunction *Callee) {
int countSelfRecursiveCalls = 0;

for (auto &BB : *Callee) {
for (auto &I : BB) {
if (auto Apply = FullApplySite::isa(&I)) {
// Return true if the callee has self-recursive calls.
static bool calleeIsSelfRecursive(SILFunction *Callee) {
for (auto &BB : *Callee)
for (auto &I : BB)
if (auto Apply = FullApplySite::isa(&I))
if (Apply.getCalleeFunction() == Callee)
++countSelfRecursiveCalls;

if (countSelfRecursiveCalls > 2)
return true;
}
}
}

return false;
}

Expand Down Expand Up @@ -651,9 +642,8 @@ SILFunction *SILPerformanceInliner::getEligibleFunction(FullApplySite AI) {

// Inlining self-recursive functions into other functions can result
// in excessive code duplication since we run the inliner multiple
// times in our pipeline, so we only do it for callees with few
// self-recursive calls.
if (calleeHasMinimalSelfRecursion(Callee)) {
// times in our pipeline
if (calleeIsSelfRecursive(Callee)) {
DEBUG(llvm::dbgs() << " FAIL: Callee is self-recursive in "
<< Callee->getName() << ".\n");
return nullptr;
Expand Down
10 changes: 6 additions & 4 deletions test/SILOptimizer/inline_recursive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ private func recFunc(x: Int32) -> Int32 {
return 0
}

//CHECK-LABEL: sil {{.*}}callit
// CHECK-LABEL: sil {{.*}}callit
// CHECK: bb0:
// CHECK-NEXT: integer_literal $Builtin.Int32, 0
// CHECK-NEXT: struct
// CHECK-NEXT: return
// CHECK: [[REF:%.*]] = function_ref @_TF16inline_recursiveP33_38E63D320CFF538A1F98BBC31453B1EB7recFuncFVs5Int32S0_
// CHECK: [[INTLIT:%.*]] = integer_literal $Builtin.Int32, 3
// CHECK: [[STRUCT:%.*]] = struct $Int32 ([[INTLIT]] : $Builtin.Int32)
// CHECK: [[APPLY:%.*]] = apply [[REF]]([[STRUCT]])
// CHECK: return [[APPLY]]

func callit() -> Int32 {
return recFunc(3)
Expand Down

0 comments on commit a971646

Please sign in to comment.