Skip to content

Commit 7ca5998

Browse files
authored
Merge pull request #67860 from eeckstein/fix-mandatory-optmization-inlining
MandatoryPerformanceOptimizations: fix some problems with inilning
2 parents 9b5c398 + 8223b3e commit 7ca5998

File tree

6 files changed

+131
-9
lines changed

6 files changed

+131
-9
lines changed

SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,14 @@ private func inlineAndDevirtualize(apply: FullApplySite, alreadyInlinedFunctions
9999
return
100100
}
101101

102-
if shouldInline(apply: apply, callee: callee, alreadyInlinedFunctions: &alreadyInlinedFunctions) {
103-
simplifyCtxt.inlineFunction(apply: apply, mandatoryInline: true)
104-
105-
// In OSSA `partial_apply [on_stack]`s are represented as owned values rather than stack locations.
106-
// It is possible for their destroys to violate stack discipline.
107-
// When inlining into non-OSSA, those destroys are lowered to dealloc_stacks.
108-
// This can result in invalid stack nesting.
109-
if callee.hasOwnership && !apply.parentFunction.hasOwnership {
102+
if apply.canInline &&
103+
shouldInline(apply: apply, callee: callee, alreadyInlinedFunctions: &alreadyInlinedFunctions)
104+
{
105+
if apply.inliningCanInvalidateStackNesting {
110106
simplifyCtxt.notifyInvalidatedStackNesting()
111107
}
108+
109+
simplifyCtxt.inlineFunction(apply: apply, mandatoryInline: true)
112110
}
113111
}
114112

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,15 @@ extension MutatingContext {
110110
}
111111

112112
func inlineFunction(apply: FullApplySite, mandatoryInline: Bool) {
113+
// This is only a best-effort attempt to notity the new cloned instructions as changed.
114+
// TODO: get a list of cloned instructions from the `inlineFunction`
113115
let instAfterInling: Instruction?
114116
switch apply {
115-
case is ApplyInst, is BeginApplyInst:
117+
case is ApplyInst:
116118
instAfterInling = apply.next
119+
case let beginApply as BeginApplyInst:
120+
let next = beginApply.next!
121+
instAfterInling = (next is EndApplyInst ? nil : next)
117122
case is TryApplyInst:
118123
instAfterInling = apply.parentBlock.next?.instructions.first
119124
default:

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
import SIL
14+
import OptimizerBridging
1415

1516
extension Value {
1617
var nonDebugUses: LazyFilterSequence<UseList> {
@@ -396,3 +397,37 @@ extension Function {
396397
}
397398
}
398399

400+
extension FullApplySite {
401+
var canInline: Bool {
402+
// Some checks which are implemented in C++
403+
if !FullApplySite_canInline(bridged) {
404+
return false
405+
}
406+
// Cannot inline a non-inlinable function it an inlinable function.
407+
if parentFunction.isSerialized,
408+
let calleeFunction = referencedFunction,
409+
!calleeFunction.isSerialized {
410+
return false
411+
}
412+
return true
413+
}
414+
415+
var inliningCanInvalidateStackNesting: Bool {
416+
guard let calleeFunction = referencedFunction else {
417+
return false
418+
}
419+
420+
// In OSSA `partial_apply [on_stack]`s are represented as owned values rather than stack locations.
421+
// It is possible for their destroys to violate stack discipline.
422+
// When inlining into non-OSSA, those destroys are lowered to dealloc_stacks.
423+
// This can result in invalid stack nesting.
424+
if calleeFunction.hasOwnership && !parentFunction.hasOwnership {
425+
return true
426+
}
427+
// Inlining of coroutines can result in improperly nested stack allocations.
428+
if self is BeginApplyInst {
429+
return true
430+
}
431+
return false
432+
}
433+
}

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,8 @@ struct BridgedPassContext {
513513
bool enableSimplificationFor(BridgedInstruction inst) const;
514514
};
515515

516+
bool FullApplySite_canInline(BridgedInstruction apply);
517+
516518
//===----------------------------------------------------------------------===//
517519
// Pass registration
518520
//===----------------------------------------------------------------------===//

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,10 @@ bool BridgedPassContext::enableSimplificationFor(BridgedInstruction inst) const
16361636
return false;
16371637
}
16381638

1639+
bool FullApplySite_canInline(BridgedInstruction apply) {
1640+
return swift::SILInliner::canInlineApplySite(swift::FullApplySite(apply.getInst()));
1641+
}
1642+
16391643
// TODO: can't be inlined to work around https://github.com/apple/swift/issues/64502
16401644
CalleeList BridgedCalleeAnalysis::getCallees(BridgedValue callee) const {
16411645
return ca->getCalleeListOfValue(callee.getSILValue());

test/SILOptimizer/mandatory_performance_optimizations.sil

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Builtin
88
import Swift
99
import SwiftShims
1010

11+
sil_global [let] @g1 : $Int32
12+
sil_global [let] @g2 : $Int32
1113

1214
sil @paable : $@convention(thin) (Builtin.Int64) -> ()
1315
sil @moved_pai_callee : $@convention(thin) (@inout_aliasable Builtin.Int64) -> ()
@@ -130,3 +132,79 @@ sil_witness_table public_external [serialized] Int: Comparable module Swift {
130132
method #Comparable."<": <Self where Self : Comparable> (Self.Type) -> (Self, Self) -> Bool : @$sSiSLsSL1loiySbx_xtFZTW
131133
}
132134

135+
sil @get_int_value : $@convention(thin) () -> Int32 {
136+
bb0:
137+
%0 = integer_literal $Builtin.Int32, 10
138+
%1 = struct $Int32 (%0 : $Builtin.Int32)
139+
return %1 : $Int32
140+
}
141+
142+
// CHECK-LABEL: sil [global_init_once_fn] [no_locks] @globalinit_inline_into_init :
143+
// CHECK-NOT: apply
144+
// CHECK: } // end sil function 'globalinit_inline_into_init'
145+
sil [global_init_once_fn] [no_locks] @globalinit_inline_into_init : $@convention(c) () -> () {
146+
bb0:
147+
alloc_global @g1
148+
%1 = global_addr @g1 : $*Int32
149+
%2 = function_ref @get_int_value : $@convention(thin) () -> Int32
150+
%3 = apply %2() : $@convention(thin) () -> Int32
151+
store %3 to %1 : $*Int32
152+
%6 = tuple ()
153+
return %6 : $()
154+
}
155+
156+
// CHECK-LABEL: sil [serialized] [global_init_once_fn] [no_locks] @globalinit_dont_inline_non_inlinable_into_inlinable :
157+
// CHECK: apply
158+
// CHECK: } // end sil function 'globalinit_dont_inline_non_inlinable_into_inlinable'
159+
sil [serialized] [global_init_once_fn] [no_locks] @globalinit_dont_inline_non_inlinable_into_inlinable : $@convention(c) () -> () {
160+
bb0:
161+
alloc_global @g2
162+
%1 = global_addr @g2 : $*Int32
163+
%2 = function_ref @get_int_value : $@convention(thin) () -> Int32
164+
%3 = apply %2() : $@convention(thin) () -> Int32
165+
store %3 to %1 : $*Int32
166+
%6 = tuple ()
167+
return %6 : $()
168+
}
169+
170+
sil @yield_int_value : $@convention(thin) @yield_once () -> (@yields Int32) {
171+
bb0:
172+
%0 = integer_literal $Builtin.Int32, 10
173+
%1 = struct $Int32 (%0 : $Builtin.Int32)
174+
yield %1 : $Int32, resume bb1, unwind bb2
175+
bb1:
176+
%3 = tuple ()
177+
return %3 : $()
178+
bb2:
179+
unwind
180+
}
181+
182+
// CHECK-LABEL: sil [no_locks] @inline_begin_apply :
183+
// CHECK-NOT: begin_apply
184+
// CHECK: } // end sil function 'inline_begin_apply'
185+
sil [no_locks] @inline_begin_apply : $@convention(thin) () -> Int32 {
186+
bb0:
187+
%0 = function_ref @yield_int_value : $@convention(thin) @yield_once () -> (@yields Int32)
188+
(%1, %2) = begin_apply %0() : $@convention(thin) @yield_once () -> (@yields Int32)
189+
end_apply %2
190+
return %1 : $Int32
191+
}
192+
193+
// CHECK-LABEL: sil [no_locks] @dont_inline_begin_apply :
194+
// CHECK: begin_apply
195+
// CHECK: } // end sil function 'dont_inline_begin_apply'
196+
sil [no_locks] @dont_inline_begin_apply : $@convention(thin) () -> Int32 {
197+
bb0:
198+
%0 = function_ref @yield_int_value : $@convention(thin) @yield_once () -> (@yields Int32)
199+
(%1, %2) = begin_apply %0() : $@convention(thin) @yield_once () -> (@yields Int32)
200+
cond_br undef, bb1, bb2
201+
bb1:
202+
end_apply %2
203+
br bb3
204+
bb2:
205+
end_apply %2
206+
br bb3
207+
bb3:
208+
return %1 : $Int32
209+
}
210+

0 commit comments

Comments
 (0)