@@ -122,7 +122,11 @@ private struct Uses {
122122 // Exit blocks of the load/copy_value's liverange which don't have a destroy.
123123 // Those are successor blocks of terminators, like `switch_enum`, which do _not_ forward the value.
124124 // E.g. the none-case of a switch_enum of an Optional.
125- private( set) var nonDestroyingLiverangeExits : Stack < BasicBlock >
125+ private( set) var nonDestroyingLiverangeExits : Stack < Instruction >
126+
127+ var allLifetimeEndingInstructions : [ Instruction ] {
128+ Array ( destroys. lazy. map { $0 } ) + Array( nonDestroyingLiverangeExits)
129+ }
126130
127131 private( set) var usersInDeadEndBlocks : Stack < Instruction >
128132
@@ -179,8 +183,13 @@ private struct Uses {
179183 // A terminator instruction can implicitly end the lifetime of its operand in a success block,
180184 // e.g. a `switch_enum` with a non-payload case block. Such success blocks need an `end_borrow`, though.
181185 for succ in termInst. successors where !succ. arguments. contains ( where: { $0. ownership == . owned} ) {
182- nonDestroyingLiverangeExits. append ( succ)
186+ nonDestroyingLiverangeExits. append ( succ. instructions . first! )
183187 }
188+ } else if !forwardingInst. forwardedResults. contains ( where: { $0. ownership == . owned } ) {
189+ // The forwarding instruction has no owned result, which means it ends the lifetime of its owned operand.
190+ // This can happen with an `unchecked_enum_data` which extracts a trivial payload out of a
191+ // non-trivial enum.
192+ nonDestroyingLiverangeExits. append ( forwardingInst. next!)
184193 }
185194 }
186195
@@ -268,7 +277,7 @@ private func remove(copy: CopyValueInst, collectedUses: Uses, liverange: Instruc
268277 context. erase ( instructions: collectedUses. destroys)
269278}
270279
271- // Handle the special case if the `load` or `copy_valuw ` is immediately followed by a single `move_value`.
280+ // Handle the special case if the `load` or `copy_value ` is immediately followed by a single `move_value`.
272281// In this case we have to preserve the move's flags by inserting a `begin_borrow` with the same flags.
273282// For example:
274283//
@@ -314,15 +323,11 @@ private func createEndBorrows(for beginBorrow: Value, atEndOf liverange: Instruc
314323 // destroy_value %2
315324 // destroy_value %3 // The final destroy. Here we need to create the `end_borrow`(s)
316325 //
317- for destroy in collectedUses. destroys where !liverange. contains ( destroy) {
318- let builder = Builder ( before: destroy, context)
319- builder. createEndBorrow ( of: beginBorrow)
320- }
321- for liverangeExitBlock in collectedUses. nonDestroyingLiverangeExits where
322- !liverange. blockRange. contains ( liverangeExitBlock)
323- {
324- let builder = Builder ( atBeginOf: liverangeExitBlock, context)
325- builder. createEndBorrow ( of: beginBorrow)
326+ for endInst in collectedUses. allLifetimeEndingInstructions {
327+ if !liverange. contains ( endInst) {
328+ let builder = Builder ( before: endInst, context)
329+ builder. createEndBorrow ( of: beginBorrow)
330+ }
326331 }
327332}
328333
0 commit comments