@@ -54,7 +54,7 @@ import SIL
54
54
let allocBoxToStack = FunctionPass ( name: " allocbox-to-stack " ) {
55
55
( function: Function , context: FunctionPassContext ) in
56
56
57
- _ = tryConvertBoxesToStack ( in: function, context)
57
+ _ = tryConvertBoxesToStack ( in: function, isMandatory : false , context)
58
58
}
59
59
60
60
/// The "mandatory" version of the pass, which runs in the mandatory pipeline.
@@ -72,7 +72,7 @@ let mandatoryAllocBoxToStack = ModulePass(name: "mandatory-allocbox-to-stack") {
72
72
73
73
while let function = worklist. pop ( ) {
74
74
moduleContext. transform ( function: function) { context in
75
- let specFns = tryConvertBoxesToStack ( in: function, context)
75
+ let specFns = tryConvertBoxesToStack ( in: function, isMandatory : true , context)
76
76
worklist. pushIfNotVisited ( contentsOf: specFns. specializedFunctions)
77
77
originalsOfSpecializedFunctions. pushIfNotVisited ( contentsOf: specFns. originalFunctions)
78
78
}
@@ -86,9 +86,11 @@ let mandatoryAllocBoxToStack = ModulePass(name: "mandatory-allocbox-to-stack") {
86
86
/// Converts all non-escaping `alloc_box` to `alloc_stack` and specializes called functions if a
87
87
/// box is passed to a function.
88
88
/// 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 {
90
92
var promotableBoxes = Array < ( AllocBoxInst , Flags ) > ( )
91
- var functionsToSpecialize = FunctionSpecializations ( )
93
+ var functionsToSpecialize = FunctionSpecializations ( isMandatory : isMandatory )
92
94
93
95
findPromotableBoxes ( in: function, & promotableBoxes, & functionsToSpecialize)
94
96
@@ -189,6 +191,9 @@ private struct FunctionSpecializations {
189
191
private var promotableArguments = CrossFunctionValueWorklist ( )
190
192
private var originals = FunctionWorklist ( )
191
193
private var originalToSpecialized = Dictionary < Function , Function > ( )
194
+ private let isMandatory : Bool
195
+
196
+ init ( isMandatory: Bool ) { self . isMandatory = isMandatory }
192
197
193
198
var originalFunctions : [ Function ] { originals. functions }
194
199
var specializedFunctions : [ Function ] { originals. functions. lazy. map { originalToSpecialized [ $0] ! } }
@@ -221,6 +226,12 @@ private struct FunctionSpecializations {
221
226
context. erase ( instruction: user)
222
227
case let projectBox as ProjectBoxInst :
223
228
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
+ }
224
235
projectBox. replace ( with: stack, context)
225
236
case is MarkUninitializedInst , is CopyValueInst , is BeginBorrowInst , is MoveValueInst :
226
237
// First, replace the instruction with the original `box`, which adds more uses to `box`.
@@ -478,6 +489,14 @@ private func hoistMarkUnresolvedInsts(stackAddress: Value,
478
489
. replaceAll ( with: mu, context)
479
490
}
480
491
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
+
481
500
private extension ApplySite {
482
501
func getSpecializableCallee( ) -> Function ? {
483
502
if let callee = referencedFunction,
0 commit comments