@@ -54,7 +54,7 @@ import SIL
5454let 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+
481500private extension ApplySite {
482501 func getSpecializableCallee( ) -> Function ? {
483502 if let callee = referencedFunction,
0 commit comments