1- //===--- SimplifyBeginAndLoadBorrow .swift ---------------------------------===//
1+ //===--- SimplifyBeginBorrow .swift ------- ---------------------------------===//
22//
33// This source file is part of the Swift.org open source project
44//
@@ -14,68 +14,72 @@ import SIL
1414
1515extension BeginBorrowInst : OnoneSimplifiable , SILCombineSimplifiable {
1616 func simplify( _ context: SimplifyContext ) {
17- if borrowedValue. ownership == . owned,
18- // We need to keep lexical lifetimes in place.
19- !isLexical,
20- // The same for borrow-scopes which encapsulated pointer escapes.
21- !findPointerEscapingUse( of: borrowedValue)
22- {
23- tryReplaceBorrowWithOwnedOperand ( beginBorrow: self , context)
24- } else {
25- removeBorrowOfThinFunction ( beginBorrow: self , context)
17+ if isLexical && context. preserveDebugInfo {
18+ // We must not remove `begin_borrow [lexical] because this is important for diagnostic passes.
19+ return
2620 }
27- }
28- }
2921
30- extension LoadBorrowInst : Simplifiable , SILCombineSimplifiable {
31- func simplify( _ context: SimplifyContext ) {
32- if uses. ignoreDebugUses. ignore ( usersOfType: EndBorrowInst . self) . isEmpty {
33- context. erase ( instructionIncludingAllUsers: self )
34- return
22+ switch borrowedValue. ownership {
23+ case . owned:
24+ if tryReplaceBorrowWithOwnedOperand ( beginBorrow: self , context) {
25+ return
26+ }
27+ case . guaranteed:
28+ if tryReplaceInnerBorrowScope ( beginBorrow: self , context) {
29+ return
30+ }
31+ default :
32+ // Note that the operand of `begin_borrow` can have "none" ownership, e.g. in case of
33+ // ```
34+ // %1 = enum $NonTrivialEnum, #NonTrivialEnum.trivialCase!enumelt // ownership = none
35+ // %2 = begin_borrow %1
36+ // ```
37+ break
3538 }
39+ removeBorrowOfThinFunction ( beginBorrow: self , context)
40+ }
41+ }
3642
37- // If the load_borrow is followed by a copy_value, combine both into a `load [copy]`:
38- // ```
39- // %1 = load_borrow %0
40- // %2 = some_forwarding_instruction %1 // zero or more forwarding instructions
41- // %3 = copy_value %2
42- // end_borrow %1
43- // ```
44- // ->
45- // ```
46- // %1 = load [copy] %0
47- // %3 = some_forwarding_instruction %1 // zero or more forwarding instructions
48- // ```
49- //
50- tryCombineWithCopy ( context)
43+ // See comments of `tryReplaceCopy` and `convertAllUsesToOwned`
44+ private func tryReplaceBorrowWithOwnedOperand( beginBorrow: BeginBorrowInst , _ context: SimplifyContext ) -> Bool {
45+ if findPointerEscapingUse ( of: beginBorrow. borrowedValue) {
46+ return false
5147 }
5248
53- private func tryCombineWithCopy( _ context: SimplifyContext ) {
54- let forwardedValue = lookThroughSingleForwardingUses ( )
55- guard let singleUser = forwardedValue. uses. ignore ( usersOfType: EndBorrowInst . self) . singleUse? . instruction,
56- let copy = singleUser as? CopyValueInst ,
57- copy. parentBlock == self . parentBlock else {
58- return
59- }
60- let builder = Builder ( before: self , context)
61- let loadCopy = builder. createLoad ( fromAddress: address, ownership: . copy)
62- let forwardedOwnedValue = replaceGuaranteed ( value: self , withOwnedValue: loadCopy, context)
63- copy. replace ( with: forwardedOwnedValue, context)
64- context. erase ( instructionIncludingAllUsers: self )
49+ // The last value of a (potentially empty) forwarding chain, beginning at the `begin_borrow`.
50+ let forwardedValue = beginBorrow. lookThroughOwnedConvertibaleForwardingChain ( )
51+ guard forwardedValue. allUsesCanBeConvertedToOwned else {
52+ return false
6553 }
54+ if tryReplaceCopy ( of: forwardedValue, withCopiedOperandOf: beginBorrow, context) {
55+ return true
56+ }
57+ if beginBorrow. borrowedValue. isDestroyed ( after: beginBorrow) {
58+ convertAllUsesToOwned ( of: beginBorrow, context)
59+ return true
60+ }
61+ return false
6662}
6763
68- private func tryReplaceBorrowWithOwnedOperand( beginBorrow: BeginBorrowInst , _ context: SimplifyContext ) {
69- // The last value of a (potentially empty) forwarding chain, beginning at the `begin_borrow`.
70- let forwardedValue = beginBorrow. lookThroughSingleForwardingUses ( )
71- if forwardedValue. allUsesCanBeConvertedToOwned {
72- if tryReplaceCopy ( of: forwardedValue, withCopiedOperandOf: beginBorrow, context) {
73- return
74- }
75- if beginBorrow. borrowedValue. isDestroyed ( after: beginBorrow) {
76- convertAllUsesToOwned ( of: beginBorrow, context)
77- }
64+ /// Removes a borrow scope if the borrowed operand is already a guaranteed value.
65+ /// ```
66+ /// bb0(%0 : @guaranteed $T):
67+ /// %1 = begin_borrow %0
68+ /// // ... uses of %1
69+ /// end_borrow %1
70+ /// ```
71+ /// ->
72+ /// ```
73+ /// bb0(%0 : @guaranteed $T):
74+ /// // ... uses of %0
75+ /// ```
76+ private func tryReplaceInnerBorrowScope( beginBorrow: BeginBorrowInst , _ context: SimplifyContext ) -> Bool {
77+ guard beginBorrow. scopeEndingOperands. allSatisfy ( { $0. instruction is EndBorrowInst } ) else {
78+ return false
7879 }
80+ beginBorrow. uses. ignore ( usersOfType: EndBorrowInst . self) . replaceAll ( with: beginBorrow. borrowedValue, context)
81+ context. erase ( instructionIncludingAllUsers: beginBorrow)
82+ return true
7983}
8084
8185private func removeBorrowOfThinFunction( beginBorrow: BeginBorrowInst , _ context: SimplifyContext ) {
@@ -143,27 +147,30 @@ private func convertAllUsesToOwned(of beginBorrow: BeginBorrowInst, _ context: S
143147 context. erase ( instructionIncludingAllUsers: beginBorrow)
144148}
145149
146- private extension Value {
147- /// Returns the last value of a (potentially empty) forwarding chain.
150+ extension Value {
151+ /// Returns the last value of a (potentially empty) forwarding chain where all operands can be
152+ /// converted to "owned" ownership.
148153 /// For example, returns %3 for the following def-use chain:
149154 /// ```
150155 /// %1 = struct_extract %self, #someField
151156 /// %2 = tuple_extract %1, 0
152157 /// %3 = struct $S(%2) // %3 has no forwarding users
153158 /// ```
154159 /// Returns self if this value has no uses which are ForwardingInstructions.
155- func lookThroughSingleForwardingUses ( ) -> Value {
156- if let singleUse = uses. ignore ( usersOfType: EndBorrowInst . self) . singleUse,
160+ func lookThroughOwnedConvertibaleForwardingChain ( ) -> Value {
161+ if let singleUse = uses. ignore ( usersOfType: EndBorrowInst . self) . ignoreDebugUses . ignoreTypeDependence . singleUse,
157162 let fwdInst = singleUse. instruction as? ( SingleValueInstruction & ForwardingInstruction ) ,
158163 fwdInst. canConvertToOwned,
159164 fwdInst. isSingleForwardedOperand ( singleUse) ,
160165 fwdInst. parentBlock == parentBlock
161166 {
162- return fwdInst. lookThroughSingleForwardingUses ( )
167+ return fwdInst. lookThroughOwnedConvertibaleForwardingChain ( )
163168 }
164169 return self
165170 }
171+ }
166172
173+ private extension Value {
167174 var allUsesCanBeConvertedToOwned : Bool {
168175 let relevantUses = uses. ignore ( usersOfType: EndBorrowInst . self)
169176 return relevantUses. allSatisfy { $0. canAccept ( ownership: . owned) }
@@ -209,12 +216,12 @@ private extension ForwardingInstruction {
209216
210217/// Replaces a guaranteed value with an owned value.
211218///
212- /// If the `guaranteedValue `'s use is a ForwardingInstruction (or forwarding instruction chain),
219+ /// If the `value `'s use is a ForwardingInstruction (or forwarding instruction chain),
213220/// it is converted to an owned version of the forwarding instruction (or instruction chain).
214221///
215- /// Returns the last owned value in a forwarding-chain or `ownedValue` if `guaranteedValue ` has
222+ /// Returns the last owned value in a forwarding-chain or `ownedValue` if `value ` has
216223/// no forwarding uses.
217- private func replaceGuaranteed( value: Value , withOwnedValue ownedValue: Value , _ context: SimplifyContext ) -> Value {
224+ func replaceGuaranteed( value: SingleValueInstruction , withOwnedValue ownedValue: Value , _ context: SimplifyContext ) -> Value {
218225 var result = ownedValue
219226 var numForwardingUses = 0
220227 for use in value. uses {
@@ -239,6 +246,11 @@ private func replaceGuaranteed(value: Value, withOwnedValue ownedValue: Value, _
239246 result = replaceGuaranteed ( value: fwdInst, withOwnedValue: fwdInst, context)
240247 case is EndBorrowInst :
241248 break
249+ case let dv as DebugValueInst where dv != value. next:
250+ // Move the debug_value immediatly after the value definition to avoid a use-after-consume
251+ // in case the debug_value is originally located after the forwarding instruction.
252+ dv. move ( before: value. next!, context)
253+ fallthrough
242254 default :
243255 precondition ( use. canAccept ( ownership: . owned) )
244256 use. set ( to: ownedValue, context)
0 commit comments