Skip to content

Commit c790052

Browse files
committed
AllocBoxToStack: convert access checks from "dynamic" to "static"
Once we have promoted the box to stack, access violations can be detected statically by the DiagnoseStaticExclusivity pass (which runs after MandatoryAllocBoxToStack). Therefore we can convert dynamic accesses to static accesses. rdar://157458037
1 parent 3de5d6a commit c790052

File tree

3 files changed

+43
-4
lines changed

3 files changed

+43
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocBoxToStack.swift

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import SIL
5454
let allocBoxToStack = FunctionPass(name: "allocbox-to-stack") {
5555
(function: Function, context: FunctionPassContext) in
5656

57-
_ = tryConvertBoxesToStack(in: function, context)
57+
_ = tryConvertBoxesToStack(in: function, isMandatory: false, context)
5858
}
5959

6060
/// The "mandatory" version of the pass, which runs in the mandatory pipeline.
@@ -72,7 +72,7 @@ let mandatoryAllocBoxToStack = ModulePass(name: "mandatory-allocbox-to-stack") {
7272

7373
while let function = worklist.pop() {
7474
moduleContext.transform(function: function) { context in
75-
let specFns = tryConvertBoxesToStack(in: function, context)
75+
let specFns = tryConvertBoxesToStack(in: function, isMandatory: true, context)
7676
worklist.pushIfNotVisited(contentsOf: specFns.specializedFunctions)
7777
originalsOfSpecializedFunctions.pushIfNotVisited(contentsOf: specFns.originalFunctions)
7878
}
@@ -86,9 +86,11 @@ let mandatoryAllocBoxToStack = ModulePass(name: "mandatory-allocbox-to-stack") {
8686
/// Converts all non-escaping `alloc_box` to `alloc_stack` and specializes called functions if a
8787
/// box is passed to a function.
8888
/// Returns the list of original functions for which a specialization has been created.
89-
private func tryConvertBoxesToStack(in function: Function, _ context: FunctionPassContext) -> FunctionSpecializations {
89+
private func tryConvertBoxesToStack(in function: Function, isMandatory: Bool,
90+
_ context: FunctionPassContext
91+
) -> FunctionSpecializations {
9092
var promotableBoxes = Array<(AllocBoxInst, Flags)>()
91-
var functionsToSpecialize = FunctionSpecializations()
93+
var functionsToSpecialize = FunctionSpecializations(isMandatory: isMandatory)
9294

9395
findPromotableBoxes(in: function, &promotableBoxes, &functionsToSpecialize)
9496

@@ -189,6 +191,9 @@ private struct FunctionSpecializations {
189191
private var promotableArguments = CrossFunctionValueWorklist()
190192
private var originals = FunctionWorklist()
191193
private var originalToSpecialized = Dictionary<Function, Function>()
194+
private let isMandatory: Bool
195+
196+
init(isMandatory: Bool) { self.isMandatory = isMandatory }
192197

193198
var originalFunctions: [Function] { originals.functions }
194199
var specializedFunctions: [Function] { originals.functions.lazy.map { originalToSpecialized[$0]! } }
@@ -221,6 +226,12 @@ private struct FunctionSpecializations {
221226
context.erase(instruction: user)
222227
case let projectBox as ProjectBoxInst:
223228
assert(projectBox.fieldIndex == 0, "only single-field boxes are handled")
229+
if isMandatory {
230+
// Once we have promoted the box to stack, access violations can be detected statically by the
231+
// DiagnoseStaticExclusivity pass (which runs after MandatoryAllocBoxToStack).
232+
// Therefore we can convert dynamic accesses to static accesses.
233+
makeAccessesStatic(of: projectBox, context)
234+
}
224235
projectBox.replace(with: stack, context)
225236
case is MarkUninitializedInst, is CopyValueInst, is BeginBorrowInst, is MoveValueInst:
226237
// First, replace the instruction with the original `box`, which adds more uses to `box`.
@@ -478,6 +489,14 @@ private func hoistMarkUnresolvedInsts(stackAddress: Value,
478489
.replaceAll(with: mu, context)
479490
}
480491

492+
private func makeAccessesStatic(of address: Value, _ context: FunctionPassContext) {
493+
for beginAccess in address.uses.users(ofType: BeginAccessInst.self) {
494+
if beginAccess.enforcement == .dynamic {
495+
beginAccess.set(enforcement: .static, context: context)
496+
}
497+
}
498+
}
499+
481500
private extension ApplySite {
482501
func getSpecializableCallee() -> Function? {
483502
if let callee = referencedFunction,

test/SILOptimizer/allocbox_to_stack_ownership.sil

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,3 +1435,19 @@ die:
14351435
destroy_value %copy
14361436
unreachable
14371437
}
1438+
1439+
// CHECK-LABEL: sil [ossa] @test_access_enforcement :
1440+
// OPT: begin_access [modify] [dynamic]
1441+
// MANDATORY: begin_access [modify] [static]
1442+
// CHECK-LABEL: } // end sil function 'test_access_enforcement'
1443+
sil [ossa] @test_access_enforcement : $(Int) -> Int {
1444+
bb0(%0 : $Int):
1445+
%1 = alloc_box ${ var Int }
1446+
%2 = project_box %1 : ${ var Int }, 0
1447+
%3 = begin_access [modify] [dynamic] %2
1448+
store %0 to [trivial] %3
1449+
end_access %3
1450+
%4 = load [trivial] %2
1451+
destroy_value %1
1452+
return %4 : $Int
1453+
}

test/SILOptimizer/allocboxtostack_localapply.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ public func testdfs2() -> Int {
179179

180180
// CHECK-LABEL: sil @$s26allocboxtostack_localapply15call2localfuncsSiyF :
181181
// CHECK-NOT: alloc_box
182+
// CHECK-NOT: begin_access
182183
// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply15call2localfuncsSiyF'
183184
public func call2localfuncs() -> Int {
184185
var a1 = 1
@@ -194,3 +195,6 @@ public func call2localfuncs() -> Int {
194195
return a1
195196
}
196197

198+
// CHECK-LABEL: sil {{.*}} @$s26allocboxtostack_localapply15call2localfuncsSiyF13innerFunctionL_yyFTf0s_n :
199+
// CHECK-NOT: begin_access
200+
// CHECK: } // end sil function '$s26allocboxtostack_localapply15call2localfuncsSiyF13innerFunctionL_yyFTf0s_n'

0 commit comments

Comments
 (0)