Skip to content

Commit 010291f

Browse files
authored
Merge pull request #82728 from eeckstein/fix-allocbox-to-stack
MandatoryAllocBoxToStack: also handle new specialized functions and re-enable the pass again
2 parents d27ce64 + 35edadc commit 010291f

File tree

7 files changed

+71
-21
lines changed

7 files changed

+71
-21
lines changed

SwiftCompilerSources/Sources/Optimizer/DataStructures/Worklist.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ struct FunctionWorklist {
125125
}
126126
}
127127

128-
mutating func pushIfNotVisited(contentsOf functions: [Function]) {
128+
mutating func pushIfNotVisited<S: Sequence>(contentsOf functions: S) where S.Element == Function {
129129
for f in functions {
130130
pushIfNotVisited(f)
131131
}

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocBoxToStack.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,16 @@ let allocBoxToStack = FunctionPass(name: "allocbox-to-stack") {
6565
let mandatoryAllocBoxToStack = ModulePass(name: "mandatory-allocbox-to-stack") {
6666
(moduleContext: ModulePassContext) in
6767

68+
var worklist = FunctionWorklist()
69+
worklist.pushIfNotVisited(contentsOf: moduleContext.functions)
70+
6871
var originalsOfSpecializedFunctions = FunctionWorklist()
6972

70-
for function in moduleContext.functions {
73+
while let function = worklist.pop() {
7174
moduleContext.transform(function: function) { context in
7275
let specFns = tryConvertBoxesToStack(in: function, context)
73-
originalsOfSpecializedFunctions.pushIfNotVisited(contentsOf: specFns)
76+
worklist.pushIfNotVisited(contentsOf: specFns.specializedFunctions)
77+
originalsOfSpecializedFunctions.pushIfNotVisited(contentsOf: specFns.originalFunctions)
7478
}
7579
}
7680

@@ -82,7 +86,7 @@ let mandatoryAllocBoxToStack = ModulePass(name: "mandatory-allocbox-to-stack") {
8286
/// Converts all non-escaping `alloc_box` to `alloc_stack` and specializes called functions if a
8387
/// box is passed to a function.
8488
/// Returns the list of original functions for which a specialization has been created.
85-
private func tryConvertBoxesToStack(in function: Function, _ context: FunctionPassContext) -> [Function] {
89+
private func tryConvertBoxesToStack(in function: Function, _ context: FunctionPassContext) -> FunctionSpecializations {
8690
var promotableBoxes = Array<(AllocBoxInst, Flags)>()
8791
var functionsToSpecialize = FunctionSpecializations()
8892

@@ -101,7 +105,7 @@ private func tryConvertBoxesToStack(in function: Function, _ context: FunctionPa
101105
function.fixStackNesting(context)
102106
}
103107

104-
return functionsToSpecialize.originalFunctions
108+
return functionsToSpecialize
105109
}
106110

107111
private func findPromotableBoxes(in function: Function,
@@ -187,6 +191,7 @@ private struct FunctionSpecializations {
187191
private var originalToSpecialized = Dictionary<Function, Function>()
188192

189193
var originalFunctions: [Function] { originals.functions }
194+
var specializedFunctions: [Function] { originals.functions.lazy.map { originalToSpecialized[$0]! } }
190195

191196
mutating func add(promotableArguments: [FunctionArgument]) {
192197
for arg in promotableArguments {

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,12 @@ static void addMandatoryDiagnosticOptPipeline(SILPassPipelinePlan &P) {
116116
// Select access kind after capture promotion and before stack promotion.
117117
// This guarantees that stack-promotable boxes have [static] enforcement.
118118
P.addAccessEnforcementSelection();
119-
/* Temporarily disabled: rdar://154686063, rdar://154713388
119+
120120
#ifdef SWIFT_ENABLE_SWIFT_IN_SWIFT
121121
P.addMandatoryAllocBoxToStack();
122122
#else
123-
*/
124123
P.addLegacyAllocBoxToStack();
125-
//#endif
124+
#endif
126125
P.addNoReturnFolding();
127126
P.addBooleanLiteralFolding();
128127
addDefiniteInitialization(P);
@@ -418,8 +417,7 @@ void addHighLevelLoopOptPasses(SILPassPipelinePlan &P) {
418417
void addFunctionPasses(SILPassPipelinePlan &P,
419418
OptimizationLevelKind OpLevel) {
420419
// Promote box allocations to stack allocations.
421-
// TODO: change this to add addAllocBoxToStack once rdar://154686063, rdar://154713388 is fixed
422-
P.addLegacyAllocBoxToStack();
420+
P.addAllocBoxToStack();
423421

424422
if (P.getOptions().DestroyHoisting == DestroyHoistingOption::On) {
425423
P.addDestroyAddrHoisting();

test/IRGen/generic_tuples.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ func dup<T>(_ x: T) -> (T, T) { var x = x; return (x,x) }
2727
// Copy 'x' into the first result.
2828
// CHECK-NEXT: call ptr [[WITNESS]](ptr noalias %0, ptr noalias [[X_ALLOCA]], ptr %T)
2929
// Copy 'x' into the second element.
30-
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 4
31-
// CHECK-NEXT: [[WITNESS:%.*]] = load ptr, ptr [[WITNESS_ADDR]], align 8
3230
// CHECK-NEXT: call ptr [[WITNESS]](ptr noalias %1, ptr noalias [[X_ALLOCA]], ptr %T)
31+
// CHECK-NEXT: [[WITNESS_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 1
32+
// CHECK-NEXT: [[DESTROYWITNESS:%.*]] = load ptr, ptr [[WITNESS_ADDR]], align 8
33+
// CHECK-NEXT: call void [[DESTROYWITNESS]](ptr noalias [[X_ALLOCA]],
3334

3435
struct S {}
3536

test/SILOptimizer/allocbox_to_stack_ownership.sil

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,3 +1198,36 @@ bb0(%0 : $*T, %1 : $*T, %2 : $*T):
11981198
%15 = tuple ()
11991199
return %15 : $()
12001200
}
1201+
1202+
// CHECK-LABEL: sil [ossa] @alloc_box_in_specialized_callee :
1203+
// CHECK-NOT: alloc_box
1204+
// CHECK-LABEL: } // end sil function 'alloc_box_in_specialized_callee'
1205+
sil [ossa] @alloc_box_in_specialized_callee : $@convention(thin) (Int) -> () {
1206+
bb0(%0 : $Int):
1207+
%1 = alloc_box ${ var Int }
1208+
%2 = project_box %1, 0
1209+
store %0 to [trivial] %2
1210+
%4 = function_ref @callee_with_allocbox : $@convention(thin) (@guaranteed { var Int }) -> ()
1211+
%5 = apply %4(%1) : $@convention(thin) (@guaranteed { var Int }) -> ()
1212+
destroy_value %1
1213+
%r = tuple ()
1214+
return %r
1215+
}
1216+
1217+
// CHECK-LABEL: sil shared [ossa] @$s20callee_with_allocboxTf0s_n :
1218+
// CHECK-NOT: alloc_box
1219+
// CHECK-LABEL: } // end sil function '$s20callee_with_allocboxTf0s_n'
1220+
1221+
// CHECK-LABEL: sil [ossa] @callee_with_allocbox :
1222+
// CHECK-NOT: alloc_box
1223+
// CHECK-LABEL: } // end sil function 'callee_with_allocbox'
1224+
sil [ossa] @callee_with_allocbox : $@convention(thin) (@guaranteed { var Int }) -> () {
1225+
bb0(%0 : @guaranteed ${ var Int }):
1226+
%1 = alloc_box ${ var Int }
1227+
%2 = project_box %1 : ${ var Int }, 0
1228+
%3 = project_box %0 : ${ var Int }, 0
1229+
copy_addr %3 to %2
1230+
destroy_value %1
1231+
%r = tuple ()
1232+
return %r
1233+
}

test/SILOptimizer/allocboxtostack_localapply.swift

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public func testboxescapes() -> (() -> ()) {
103103
}
104104

105105
// CHECK-LABEL: sil [noinline] @$s26allocboxtostack_localapply9testrecurSiyF :
106-
// CHECK: alloc_box ${ var Int }, var, name "x"
106+
// CHECK: alloc_stack [var_decl] $Int, var, name "x"
107107
// CHECK-LABEL: } // end sil function '$s26allocboxtostack_localapply9testrecurSiyF'
108108
@inline(never)
109109
public func testrecur() -> Int {
@@ -146,14 +146,9 @@ public func testdfs1() -> Int {
146146
return common()
147147
}
148148

149-
// Test to make sure we don't optimize the case when we have an inner common function call for multiple boxes.
150-
// We don't optimize this case now, because we don't have additional logic to correctly construct AppliesToSpecialize
151-
// Order of function calls constructed in PromotedOperands: bar innercommon local1 bas innercommon local2
152-
// AppliesToSpecialize should have the order: bar bas innercommon local1 local2
153-
// Since we don't maintain any tree like data structure with more info on the call tree, this is not possible to construct today
154149
// CHECK-LABEL: sil [noinline] @$s26allocboxtostack_localapply8testdfs2SiyF :
155-
// CHECK: alloc_box ${ var Int }, var, name "x"
156-
// CHECK: alloc_box ${ var Int }, var, name "y"
150+
// CHECK: alloc_stack [var_decl] $Int, var, name "x"
151+
// CHECK: alloc_stack [var_decl] $Int, var, name "y"
157152
// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply8testdfs2SiyF'
158153
@inline(never)
159154
public func testdfs2() -> Int {
@@ -182,3 +177,20 @@ public func testdfs2() -> Int {
182177
return local1() + local2()
183178
}
184179

180+
// CHECK-LABEL: sil @$s26allocboxtostack_localapply15call2localfuncsSiyF :
181+
// CHECK-NOT: alloc_box
182+
// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply15call2localfuncsSiyF'
183+
public func call2localfuncs() -> Int {
184+
var a1 = 1
185+
186+
@inline(never)
187+
func innerFunction() {
188+
a1 += 1
189+
}
190+
191+
innerFunction()
192+
innerFunction()
193+
194+
return a1
195+
}
196+

test/SILOptimizer/definite_init_protocol_init.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ struct AddressOnlyStruct : TriviallyConstructible {
9999
// CHECK-NEXT: apply [[FN]]<AddressOnlyStruct>([[SELF_BOX]], %1, [[METATYPE]])
100100
// CHECK-NEXT: copy_addr [take] [[SELF_BOX]] to [init] [[SELF]]
101101
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
102-
// CHECK-NEXT: copy_addr [take] [[SELF]] to [init] %0
102+
// CHECK-NEXT: copy_addr [[SELF]] to [init] %0
103+
// CHECK-NEXT: destroy_addr [[SELF]]
103104
// CHECK-NEXT: dealloc_stack [[SELF]]
104105
// CHECK-NEXT: [[RESULT:%.*]] = tuple ()
105106
// CHECK-NEXT: return [[RESULT]]

0 commit comments

Comments
 (0)