mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
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
This commit is contained in:
@@ -54,7 +54,7 @@ import SIL
|
||||
let allocBoxToStack = FunctionPass(name: "allocbox-to-stack") {
|
||||
(function: Function, context: FunctionPassContext) in
|
||||
|
||||
_ = tryConvertBoxesToStack(in: function, context)
|
||||
_ = tryConvertBoxesToStack(in: function, isMandatory: false, context)
|
||||
}
|
||||
|
||||
/// The "mandatory" version of the pass, which runs in the mandatory pipeline.
|
||||
@@ -72,7 +72,7 @@ let mandatoryAllocBoxToStack = ModulePass(name: "mandatory-allocbox-to-stack") {
|
||||
|
||||
while let function = worklist.pop() {
|
||||
moduleContext.transform(function: function) { context in
|
||||
let specFns = tryConvertBoxesToStack(in: function, context)
|
||||
let specFns = tryConvertBoxesToStack(in: function, isMandatory: true, context)
|
||||
worklist.pushIfNotVisited(contentsOf: specFns.specializedFunctions)
|
||||
originalsOfSpecializedFunctions.pushIfNotVisited(contentsOf: specFns.originalFunctions)
|
||||
}
|
||||
@@ -86,9 +86,11 @@ let mandatoryAllocBoxToStack = ModulePass(name: "mandatory-allocbox-to-stack") {
|
||||
/// Converts all non-escaping `alloc_box` to `alloc_stack` and specializes called functions if a
|
||||
/// box is passed to a function.
|
||||
/// Returns the list of original functions for which a specialization has been created.
|
||||
private func tryConvertBoxesToStack(in function: Function, _ context: FunctionPassContext) -> FunctionSpecializations {
|
||||
private func tryConvertBoxesToStack(in function: Function, isMandatory: Bool,
|
||||
_ context: FunctionPassContext
|
||||
) -> FunctionSpecializations {
|
||||
var promotableBoxes = Array<(AllocBoxInst, Flags)>()
|
||||
var functionsToSpecialize = FunctionSpecializations()
|
||||
var functionsToSpecialize = FunctionSpecializations(isMandatory: isMandatory)
|
||||
|
||||
findPromotableBoxes(in: function, &promotableBoxes, &functionsToSpecialize)
|
||||
|
||||
@@ -189,6 +191,9 @@ private struct FunctionSpecializations {
|
||||
private var promotableArguments = CrossFunctionValueWorklist()
|
||||
private var originals = FunctionWorklist()
|
||||
private var originalToSpecialized = Dictionary<Function, Function>()
|
||||
private let isMandatory: Bool
|
||||
|
||||
init(isMandatory: Bool) { self.isMandatory = isMandatory }
|
||||
|
||||
var originalFunctions: [Function] { originals.functions }
|
||||
var specializedFunctions: [Function] { originals.functions.lazy.map { originalToSpecialized[$0]! } }
|
||||
@@ -221,6 +226,12 @@ private struct FunctionSpecializations {
|
||||
context.erase(instruction: user)
|
||||
case let projectBox as ProjectBoxInst:
|
||||
assert(projectBox.fieldIndex == 0, "only single-field boxes are handled")
|
||||
if isMandatory {
|
||||
// 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.
|
||||
makeAccessesStatic(of: projectBox, context)
|
||||
}
|
||||
projectBox.replace(with: stack, context)
|
||||
case is MarkUninitializedInst, is CopyValueInst, is BeginBorrowInst, is MoveValueInst:
|
||||
// First, replace the instruction with the original `box`, which adds more uses to `box`.
|
||||
@@ -478,6 +489,14 @@ private func hoistMarkUnresolvedInsts(stackAddress: Value,
|
||||
.replaceAll(with: mu, context)
|
||||
}
|
||||
|
||||
private func makeAccessesStatic(of address: Value, _ context: FunctionPassContext) {
|
||||
for beginAccess in address.uses.users(ofType: BeginAccessInst.self) {
|
||||
if beginAccess.enforcement == .dynamic {
|
||||
beginAccess.set(enforcement: .static, context: context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension ApplySite {
|
||||
func getSpecializableCallee() -> Function? {
|
||||
if let callee = referencedFunction,
|
||||
|
||||
@@ -1435,3 +1435,19 @@ die:
|
||||
destroy_value %copy
|
||||
unreachable
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil [ossa] @test_access_enforcement :
|
||||
// OPT: begin_access [modify] [dynamic]
|
||||
// MANDATORY: begin_access [modify] [static]
|
||||
// CHECK-LABEL: } // end sil function 'test_access_enforcement'
|
||||
sil [ossa] @test_access_enforcement : $(Int) -> Int {
|
||||
bb0(%0 : $Int):
|
||||
%1 = alloc_box ${ var Int }
|
||||
%2 = project_box %1 : ${ var Int }, 0
|
||||
%3 = begin_access [modify] [dynamic] %2
|
||||
store %0 to [trivial] %3
|
||||
end_access %3
|
||||
%4 = load [trivial] %2
|
||||
destroy_value %1
|
||||
return %4 : $Int
|
||||
}
|
||||
|
||||
@@ -179,6 +179,7 @@ public func testdfs2() -> Int {
|
||||
|
||||
// CHECK-LABEL: sil @$s26allocboxtostack_localapply15call2localfuncsSiyF :
|
||||
// CHECK-NOT: alloc_box
|
||||
// CHECK-NOT: begin_access
|
||||
// CHECK-LABEL:} // end sil function '$s26allocboxtostack_localapply15call2localfuncsSiyF'
|
||||
public func call2localfuncs() -> Int {
|
||||
var a1 = 1
|
||||
@@ -194,3 +195,6 @@ public func call2localfuncs() -> Int {
|
||||
return a1
|
||||
}
|
||||
|
||||
// CHECK-LABEL: sil {{.*}} @$s26allocboxtostack_localapply15call2localfuncsSiyF13innerFunctionL_yyFTf0s_n :
|
||||
// CHECK-NOT: begin_access
|
||||
// CHECK: } // end sil function '$s26allocboxtostack_localapply15call2localfuncsSiyF13innerFunctionL_yyFTf0s_n'
|
||||
|
||||
Reference in New Issue
Block a user