@@ -649,6 +649,19 @@ private extension MovableInstructions {
649
649
var changed = false
650
650
651
651
for scopedInst in scopedInsts {
652
+ if let storeBorrowInst = scopedInst as? StoreBorrowInst {
653
+ _ = storeBorrowInst. allocStack. hoist ( outOf: loop, context)
654
+
655
+ var sankFirst = false
656
+ for deallocStack in storeBorrowInst. allocStack. deallocations {
657
+ if sankFirst {
658
+ context. erase ( instruction: deallocStack)
659
+ } else {
660
+ sankFirst = deallocStack. sink ( outOf: loop, context)
661
+ }
662
+ }
663
+ }
664
+
652
665
guard scopedInst. hoist ( outOf: loop, context) else {
653
666
continue
654
667
}
@@ -706,7 +719,7 @@ private extension MovableInstructions {
706
719
var ssaUpdater = SSAUpdater (
707
720
function: firstStore. parentFunction,
708
721
type: firstStore. destination. type. objectType,
709
- ownership: firstStore. storeOwnership == . initialize ? . owned : . none ,
722
+ ownership: firstStore. source . ownership ,
710
723
context
711
724
)
712
725
@@ -868,7 +881,7 @@ private extension Instruction {
868
881
}
869
882
870
883
if let singleValueInst = self as? SingleValueInstruction ,
871
- !( self is BeginAccessInst ) ,
884
+ !( self is ScopedInstruction ) ,
872
885
let identicalInst = ( loop. preheader!. instructions. first { otherInst in
873
886
return singleValueInst != otherInst && singleValueInst. isIdenticalTo ( otherInst)
874
887
} ) {
@@ -1070,43 +1083,70 @@ private extension ScopedInstruction where Self: UnaryInstruction {
1070
1083
return false
1071
1084
}
1072
1085
1073
- let areBeginAccessesSafe = analyzedInstructions. scopedInsts
1074
- . allSatisfy { otherScopedInst in
1075
- guard self != otherScopedInst else { return true }
1086
+ // Instruction specific preconditions
1087
+ switch self {
1088
+ case is BeginAccessInst , is LoadBorrowInst :
1089
+ guard ( analyzedInstructions. scopedInsts
1090
+ . allSatisfy { otherScopedInst in
1091
+ guard self != otherScopedInst else { return true }
1076
1092
1077
- return operand. value. accessPath. isDistinct ( from: otherScopedInst. operand. value. accessPath)
1093
+ return operand. value. accessPath. isDistinct ( from: otherScopedInst. operand. value. accessPath)
1094
+ } ) else {
1095
+ return false
1078
1096
}
1079
-
1080
- guard areBeginAccessesSafe else { return false }
1097
+ default :
1098
+ break
1099
+ }
1081
1100
1082
1101
var scope = InstructionRange ( begin: self , ends: endInstructions, context)
1083
1102
defer { scope. deinitialize ( ) }
1084
-
1085
- for fullApplyInst in analyzedInstructions. fullApplies {
1086
- guard mayWriteToMemory && fullApplyInst. mayReadOrWrite ( address: operand. value, context. aliasAnalysis) ||
1087
- !mayWriteToMemory && fullApplyInst. mayWrite ( toAddress: operand. value, context. aliasAnalysis) else {
1088
- continue
1089
- }
1090
-
1091
- // After hoisting the begin/end_access the apply will be within the scope, so it must not have a conflicting access.
1092
- if !scope. contains ( fullApplyInst) {
1093
- return false
1103
+
1104
+ // Instruction specific range related conditions
1105
+ switch self {
1106
+ case is BeginApplyInst :
1107
+ return false // TODO: Add support. Like read-only apply hoist + end_apply sink.
1108
+ case is LoadBorrowInst :
1109
+ for storeInst in analyzedInstructions. stores {
1110
+ if storeInst. mayWrite ( toAddress: operand. value, context. aliasAnalysis) {
1111
+ if !scope. contains ( storeInst) {
1112
+ return false
1113
+ }
1114
+ }
1094
1115
}
1095
- }
1116
+
1117
+ fallthrough
1118
+ case is BeginAccessInst :
1119
+ for fullApplyInst in analyzedInstructions. fullApplies {
1120
+ guard mayWriteToMemory && fullApplyInst. mayReadOrWrite ( address: operand. value, context. aliasAnalysis) ||
1121
+ !mayWriteToMemory && fullApplyInst. mayWrite ( toAddress: operand. value, context. aliasAnalysis) else {
1122
+ continue
1123
+ }
1096
1124
1097
- switch operand. value. accessPath. base {
1098
- case . class, . global:
1099
- for sideEffect in analyzedInstructions. loopSideEffects where sideEffect. mayRelease {
1100
- // Since a class might have a deinitializer, hoisting begin/end_access pair could violate
1101
- // exclusive access if the deinitializer accesses address used by begin_access.
1102
- if !scope. contains ( sideEffect) {
1125
+ // After hoisting the begin/end_access the apply will be within the scope, so it must not have a conflicting access.
1126
+ if !scope. contains ( fullApplyInst) {
1103
1127
return false
1104
1128
}
1105
1129
}
1130
+
1131
+ switch operand. value. accessPath. base {
1132
+ case . class, . global:
1133
+ for sideEffect in analyzedInstructions. loopSideEffects where sideEffect. mayRelease {
1134
+ // Since a class might have a deinitializer, hoisting begin/end_access pair could violate
1135
+ // exclusive access if the deinitializer accesses address used by begin_access.
1136
+ if !scope. contains ( sideEffect) {
1137
+ return false
1138
+ }
1139
+ }
1106
1140
1107
- return true
1141
+ return true
1142
+ default :
1143
+ return true
1144
+ }
1145
+ case is BeginBorrowInst , is StoreBorrowInst :
1146
+ // Ensure the value is produced outside the loop.
1147
+ return !loop. contains ( block: operand. value. parentBlock)
1108
1148
default :
1109
- return true
1149
+ return false
1110
1150
}
1111
1151
}
1112
1152
}
0 commit comments