Skip to content

Commit f40a13a

Browse files
committed
SILInliner: Disable inlining mulitple yields and don't create a temporary for yielded address values
Just use the yielded address from the callee directly. This also allows handling yielded 'inout'/'out' values.
1 parent 3121af2 commit f40a13a

File tree

4 files changed

+129
-89
lines changed

4 files changed

+129
-89
lines changed

include/swift/SILOptimizer/Utils/SILInliner.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class SILInliner : public TypeSubstCloner<SILInliner> {
4242
public:
4343
enum class InlineKind { MandatoryInline, PerformanceInline };
4444

45+
// Returns true if this an begin_apply instruction that we can inline or
46+
// another application site.
47+
static bool canInlineBeginApply(FullApplySite AI);
48+
4549
private:
4650
InlineKind IKind;
4751

lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,11 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI,
661661
if (!Callee) {
662662
return nullptr;
663663
}
664+
665+
// We don't currently support inlining co-routines with several yields.
666+
if (!SILInliner::canInlineBeginApply(AI))
667+
return nullptr;
668+
664669
auto ModuleName = Callee->getModule().getSwiftModule()->getName().str();
665670
bool IsInStdlib = (ModuleName == STDLIB_NAME || ModuleName == SWIFT_ONONE_SUPPORT);
666671

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,32 @@
1717
#include "llvm/Support/Debug.h"
1818
using namespace swift;
1919

20+
bool SILInliner::canInlineBeginApply(FullApplySite AI) {
21+
// Don't inline a coroutine with multiple yields. We are not yet able to do
22+
// so. The current implementation cannot handle values that are live across
23+
// only some yields.
24+
unsigned NumYields = 0;
25+
if (auto BA = dyn_cast<BeginApplyInst>(AI)) {
26+
for (auto &B : BA->getReferencedFunction()->getBlocks()) {
27+
if (isa<YieldInst>(B.getTerminator()))
28+
NumYields++;
29+
if (NumYields > 1)
30+
return false;
31+
}
32+
}
33+
return true;
34+
}
35+
2036
bool SILInliner::canInlineFunction(FullApplySite AI) {
37+
if (!canInlineBeginApply(AI))
38+
return false;
2139
return AI.getFunction() != &Original;
2240
}
2341

2442
/// Utility class for rewiring control-flow of inlined begin_apply functions.
2543
class BeginApplySite {
2644
SmallVector<SILBasicBlock *, 4> ExitingBlocks;
27-
SmallVector<AllocStackInst*, 8> YieldedIndirectValues;
45+
SmallVector<SILValue, 8> YieldedIndirectValues;
2846
SILLocation Loc;
2947
SILBuilder &Builder;
3048
BeginApplyInst *BeginApply;
@@ -77,17 +95,10 @@ class BeginApplySite {
7795
void processApply(SILBasicBlock *ReturnToBB) {
7896
// Handle direct and indirect results.
7997
for (auto YieldedValue : BeginApply->getYieldedValues()) {
80-
// Insert an alloc_stack for indirect results.
98+
// Store the addresses of indirect results so that we can replace them by
99+
// the yielded address value later.
81100
if (YieldedValue->getType().isAddress()) {
82-
Builder.setInsertionPoint(F->getEntryBlock()->begin());
83-
auto Addr = Builder.createAllocStack(
84-
Loc, YieldedValue->getType().getObjectType());
85-
YieldedValue->replaceAllUsesWith(Addr);
86-
YieldedIndirectValues.push_back(Addr);
87-
for (auto *Exit : ExitingBlocks) {
88-
Builder.setInsertionPoint(Exit->getTerminator());
89-
Builder.createDeallocStack(Loc, Addr);
90-
}
101+
YieldedIndirectValues.push_back(YieldedValue);
91102
continue;
92103
}
93104
// Insert a phi for direct results.
@@ -148,8 +159,7 @@ class BeginApplySite {
148159
auto YieldedVal = remapValue(CalleeYieldedVal);
149160
if (YieldedVal->getType().isAddress()) {
150161
auto YieldedDestAddr = YieldedIndirectValues[IndirectIdx++];
151-
Builder.createCopyAddr(Loc, YieldedVal, YieldedDestAddr, IsTake,
152-
IsInitialization);
162+
YieldedDestAddr->replaceAllUsesWith(YieldedVal);
153163
} else
154164
BrResults.push_back(YieldedVal);
155165
}

test/SILOptimizer/inline_begin_apply.sil

Lines changed: 97 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ unwind:
4646

4747
// CHECK-LABEL: sil @test_simple_call
4848
// CHECK: bb0(%0 : @trivial $Builtin.Int1):
49-
// CHECK: [[IND_RES:%.*]] = alloc_stack $Indirect<SomeSubclass>
5049
// CHECK: [[MARKER:%.*]] = function_ref @marker
5150
// CHECK: [[MARKER2:%.*]] = function_ref @marker
5251
// CHECK: [[I:%.*]] = integer_literal $Builtin.Int32, 1000
@@ -55,7 +54,6 @@ unwind:
5554
// CHECK: [[MK_IND:%.*]] = function_ref @make_indirect
5655
// CHECK: apply [[MK_IND]]<SomeSubclass>([[TEMP]])
5756
// CHECK: [[INTTOKEN:%.*]] = integer_literal $Builtin.Int32, 0
58-
// CHECK: copy_addr [take] [[TEMP]] to [initialization] [[IND_RES]] : $*Indirect<SomeSubclass>
5957
// CHECK: br bb3([[INTTOKEN]] : $Builtin.Int32)
6058

6159
// CHECK:bb1:
@@ -71,7 +69,7 @@ unwind:
7169
// CHECK: br bb7
7270

7371
// CHECK: bb3([[WHICH_YIELD:%.*]] : @trivial $Builtin.Int32):
74-
// CHECK: destroy_addr [[IND_RES]] : $*Indirect<SomeSubclass>
72+
// CHECK: destroy_addr [[TEMP]] : $*Indirect<SomeSubclass>
7573
// CHECK: cond_br %0, bb4, bb6
7674

7775
// CHECK: bb4:
@@ -82,7 +80,7 @@ unwind:
8280

8381
// CHECK: bb5:
8482
// CHECK: [[I5:%.*]] = integer_literal $Builtin.Int32, 20
85-
// CHECK: %29 = apply [[MARKER]]([[I5]])
83+
// CHECK: apply [[MARKER]]([[I5]])
8684
// CHECK: br bb8
8785

8886
// CHECK: bb6:
@@ -97,7 +95,6 @@ unwind:
9795
// CHECK: br bb8
9896

9997
// CHECK:bb8:
100-
// CHECK: dealloc_stack [[IND_RES]] : $*Indirect<SomeSubclass>
10198
// CHECK: return
10299
// CHECK:}
103100

@@ -173,79 +170,11 @@ unwind:
173170
unwind
174171
}
175172

173+
// We don't support inlining functions with multiple yields yet.
176174
// CHECK-LABEL: sil @test_simple_call_two_yields : $@convention(thin) (Builtin.Int1, Builtin.Int1) -> () {
177175
// CHECK: bb0(%0 : @trivial $Builtin.Int1, %1 : @trivial $Builtin.Int1):
178-
// CHECK: %2 = alloc_stack $Indirect<SomeSubclass>
179-
// CHECK: %3 = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
180-
// CHECK: %4 = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
181-
// CHECK: %5 = integer_literal $Builtin.Int32, 1000
182-
// CHECK: %6 = apply %4(%5) : $@convention(thin) (Builtin.Int32) -> ()
183-
// CHECK: %7 = alloc_stack $Indirect<SomeSubclass>
184-
// CHECK: %8 = function_ref @make_indirect
185-
// CHECK: cond_br %0, bb1, bb6
186-
187-
// CHECK: bb1:
188-
// CHECK: %10 = apply %8<SomeSubclass>(%7)
189-
// CHECK: %11 = integer_literal $Builtin.Int64, 31
190-
// CHECK: %12 = integer_literal $Builtin.Int32, 0
191-
// CHECK: copy_addr [take] %7 to [initialization] %2 : $*Indirect<SomeSubclass>
192-
// CHECK: br bb9(%11 : $Builtin.Int64, %12 : $Builtin.Int32)
193-
194-
// CHECK: bb2:
195-
// CHECK: br bb3
196-
197-
// CHECK: bb3:
198-
// CHECK: %16 = integer_literal $Builtin.Int32, 2000
199-
// CHECK: %17 = apply %4(%16)
200-
// CHECK: dealloc_stack %7 : $*Indirect<SomeSubclass>
201-
// CHECK: br bb11
202-
203-
// CHECK: bb4:
204-
// CHECK: br bb5
205-
206-
// CHECK: bb5:
207-
// CHECK: %22 = integer_literal $Builtin.Int32, 3000
208-
// CHECK: %23 = apply %4(%22)
209-
// CHECK: dealloc_stack %7 : $*Indirect<SomeSubclass>
210-
// CHECK: br bb13
211-
212-
// CHECK: bb6:
213-
// CHECK: %26 = apply %8<SomeSubclass>(%7) : $@convention(thin) <τ_0_0 where τ_0_0 : SomeClass> () -> @out Indirect<τ_0_0>
214-
// CHECK: %27 = integer_literal $Builtin.Int64, 32
215-
// CHECK: %28 = integer_literal $Builtin.Int32, 1
216-
// CHECK: copy_addr [take] %7 to [initialization] %2 : $*Indirect<SomeSubclass>
217-
// CHECK: br bb9(%27 : $Builtin.Int64, %28 : $Builtin.Int32)
218-
219-
// CHECK: bb7:
220-
// CHECK: br bb3
221-
222-
// CHECK: bb8:
223-
// CHECK: br bb5
224-
225-
// CHECK: bb9(%33 : @trivial $Builtin.Int64, %34 : @trivial $Builtin.Int32):
226-
// CHECK: destroy_addr %2 : $*Indirect<SomeSubclass>
227-
// CHECK: cond_br %1, bb10, bb12
228-
229-
// CHECK: bb10:
230-
// CHECK: %37 = integer_literal $Builtin.Int32, 0
231-
// CHECK: %38 = integer_literal $Builtin.Int32, 1
232-
// CHECK: switch_value %34 : $Builtin.Int32, case %37: bb2, case %38: bb7
233-
234-
// CHECK: bb11:
235-
// CHECK: br bb14
236-
237-
// CHECK: bb12:
238-
// CHECK: %41 = integer_literal $Builtin.Int32, 0
239-
// CHECK: %42 = integer_literal $Builtin.Int32, 1
240-
// CHECK: switch_value %34 : $Builtin.Int32, case %41: bb4, case %42: bb8
241-
242-
// CHECK: bb13:
243-
// CHECK: br bb14
244-
245-
// CHECK: bb14:
246-
// CHECK: %45 = tuple ()
247-
// CHECK: dealloc_stack %2 : $*Indirect<SomeSubclass>
248-
// CHECK: return %45 : $()
176+
// CHECK: begin_apply
177+
// CHECK: return
249178

250179
sil @test_simple_call_two_yields : $(Builtin.Int1, Builtin.Int1) -> () {
251180
entry(%flag : @trivial $Builtin.Int1, %flag2 : @trivial $Builtin.Int1):
@@ -348,3 +277,95 @@ cont:
348277
%ret = tuple ()
349278
return %ret : $()
350279
}
280+
281+
sil @use : $@convention(thin) (@in Builtin.Int8) -> ()
282+
283+
sil [transparent] @yield_inout : $@yield_once() -> (@yields @inout Builtin.Int8) {
284+
entry:
285+
%addr = alloc_stack $Builtin.Int8
286+
%8 = integer_literal $Builtin.Int8, 8
287+
store %8 to [trivial] %addr : $*Builtin.Int8
288+
yield %addr : $*Builtin.Int8, resume resume, unwind unwind
289+
290+
resume:
291+
%use = function_ref @use : $@convention(thin) (@in Builtin.Int8) -> ()
292+
apply %use(%addr) : $@convention(thin) (@in Builtin.Int8) -> ()
293+
dealloc_stack %addr: $*Builtin.Int8
294+
%ret = tuple ()
295+
return %ret : $()
296+
297+
unwind:
298+
%3000 = integer_literal $Builtin.Int32, 3000
299+
%marker = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
300+
apply %marker(%3000) : $@convention(thin) (Builtin.Int32) -> ()
301+
dealloc_stack %addr: $*Builtin.Int8
302+
unwind
303+
}
304+
305+
306+
// CHECK: sil @test_simple_call_yield_inout : $@convention(thin) (Builtin.Int1) -> () {
307+
// CHECK: bb0(%0 : @trivial $Builtin.Int1):
308+
// CHECK: %1 = alloc_stack $Builtin.Int8
309+
// CHECK: %2 = integer_literal $Builtin.Int8, 8
310+
// CHECK: store %2 to [trivial] %1 : $*Builtin.Int8
311+
// CHECK: %4 = integer_literal $Builtin.Int32, 0
312+
// CHECK: br bb3(%4 : $Builtin.Int32)
313+
314+
// CHECK: bb1:
315+
// CHECK: %6 = function_ref @use : $@convention(thin) (@in Builtin.Int8) -> ()
316+
// CHECK: %7 = apply %6(%1) : $@convention(thin) (@in Builtin.Int8) -> ()
317+
// CHECK: dealloc_stack %1 : $*Builtin.Int8
318+
// CHECK: %9 = tuple ()
319+
// CHECK: br bb5
320+
321+
// CHECK: bb2:
322+
// CHECK: %11 = integer_literal $Builtin.Int32, 3000
323+
// CHECK: %12 = function_ref @marker : $@convention(thin) (Builtin.Int32) -> ()
324+
// CHECK: %13 = apply %12(%11) : $@convention(thin) (Builtin.Int32) -> ()
325+
// CHECK: dealloc_stack %1 : $*Builtin.Int8
326+
// CHECK: br bb7
327+
328+
// CHECK: bb3(%16 : @trivial $Builtin.Int32):
329+
// CHECK: cond_br %0, bb4, bb6
330+
331+
// CHECK: bb4:
332+
// CHECK: %18 = integer_literal $Builtin.Int8, 8
333+
// CHECK: store %18 to [trivial] %1 : $*Builtin.Int8
334+
// CHECK: %20 = integer_literal $Builtin.Int32, 0
335+
// CHECK: switch_value %16 : $Builtin.Int32, case %20: bb1
336+
337+
// CHECK: bb5:
338+
// CHECK: br bb8
339+
340+
// CHECK: bb6:
341+
// CHECK: %23 = integer_literal $Builtin.Int32, 0
342+
// CHECK: switch_value %16 : $Builtin.Int32, case %23: bb2
343+
344+
// CHECK: bb7:
345+
// CHECK: br bb8
346+
347+
// CHECK: bb8:
348+
// CHECK: %26 = tuple ()
349+
// CHECK: return %26 : $()
350+
// CHECK: }
351+
352+
sil @test_simple_call_yield_inout : $(Builtin.Int1) -> () {
353+
entry(%flag : @trivial $Builtin.Int1):
354+
%0 = function_ref @yield_inout : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8)
355+
(%addr, %token) = begin_apply %0() : $@convention(thin) @yield_once() -> (@yields @inout Builtin.Int8)
356+
cond_br %flag, yes, no
357+
358+
yes:
359+
%8 = integer_literal $Builtin.Int8, 8
360+
store %8 to [trivial] %addr : $*Builtin.Int8
361+
end_apply %token
362+
br cont
363+
364+
no:
365+
abort_apply %token
366+
br cont
367+
368+
cont:
369+
%ret = tuple ()
370+
return %ret : $()
371+
}

0 commit comments

Comments
 (0)