Skip to content

Commit 49017c8

Browse files
authored
Merge pull request swiftlang#30042 from eeckstein/reinstate-inliner-change
Reinstate "Inliner: inline generic thunks which return a partial_apply."
2 parents 09c199b + 2f6c9f3 commit 49017c8

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,15 @@ bool SILPerformanceInliner::isProfitableToInline(
526526
return true;
527527
}
528528

529+
static bool returnsClosure(SILFunction *F) {
530+
for (SILBasicBlock &BB : *F) {
531+
if (auto *RI = dyn_cast<ReturnInst>(BB.getTerminator())) {
532+
return isa<PartialApplyInst>(RI->getOperand());
533+
}
534+
}
535+
return false;
536+
}
537+
529538
/// Checks if a given generic apply should be inlined unconditionally, i.e.
530539
/// without any complex analysis using e.g. a cost model.
531540
/// It returns true if a function should be inlined.
@@ -570,6 +579,13 @@ static Optional<bool> shouldInlineGeneric(FullApplySite AI) {
570579
return None;
571580
}
572581

582+
// The returned partial_apply of a thunk is most likely being optimized away
583+
// if inlined. Because some thunks cannot be specialized (e.g. if an opened
584+
// existential is in the subsitution list), we inline such thunks also in case
585+
// they are generic.
586+
if (Callee->isThunk() && returnsClosure(Callee))
587+
return true;
588+
573589
// All other generic functions should not be inlined if this kind of inlining
574590
// is disabled.
575591
if (!EnableSILInliningOfGenerics)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-swift-frontend -primary-file %s -O -sil-verify-all -module-name=test -emit-sil | %FileCheck %s
2+
3+
// Also do an end-to-end test to check all components, including IRGen.
4+
// RUN: %empty-directory(%t)
5+
// RUN: %target-build-swift -O %s -o %t/a.out
6+
// RUN: %target-run %t/a.out | %FileCheck --check-prefix=CHECK-OUTPUT %s
7+
8+
// REQUIRES: executable_test,swift_stdlib_no_asserts,optimized_stdlib
9+
10+
protocol P {
11+
func foo() throws -> Int
12+
}
13+
14+
struct S: P {
15+
var a: Int
16+
var b: Int
17+
var c: Int
18+
var d: Int
19+
20+
func foo() throws -> Int {
21+
return a + b + c + d
22+
}
23+
}
24+
25+
func callClosure<R>(_ body: () throws -> R) rethrows -> R {
26+
try body()
27+
}
28+
29+
// Check that the optimizer can eliminat all calls to thunks and directly
30+
// try_apply's the witness method.
31+
32+
// CHECK-LABEL: sil hidden [noinline] @$s4test6testitySiSgAA1P_pF
33+
// CHECK: [[METHOD:%[0-9]+]] = witness_method $@opened{{.*}} #P.foo
34+
// CHECK: try_apply [[METHOD]]<@opened
35+
// CHECK: // end sil function '$s4test6testitySiSgAA1P_pF'
36+
@inline(never)
37+
func testit(_ p: P) -> Int? {
38+
return try? callClosure(p.foo)
39+
}
40+
41+
let p: P = S(a: 1, b: 2, c: 3, d: 4)
42+
43+
// CHECK-OUTPUT: 10
44+
print(testit(p)!)
45+

0 commit comments

Comments
 (0)