mirror of
https://github.com/apple/swift.git
synced 2026-02-27 18:26:24 +01:00
* Replace address casts of heap objects ``` %1 = unchecked_addr_cast %0 : $*SomeClass to $*OtherClass %2 = load [copy] %1 ``` with ref-casts of the loaded value ``` %1 = load [copy] %0 %2 = unchecked_ref_cast %1 : $SomeClass to $OtherClass ``` * Replace a `load_borrow` of a `store_borrow` with a `begin_borrow`: ``` %1 = alloc_stack $T %2 = store_borrow %0 to %1 ... %3 = load_borrow %2 // ... uses of %3 end_borrow %3 ``` -> ``` %1 = alloc_stack $T %2 = store_borrow %0 to %1 ... %3 = begin_borrow %0 // ... uses of %3 end_borrow %3 ```
117 lines
3.9 KiB
Swift
117 lines
3.9 KiB
Swift
//===--- SimplifyLoadBorrow.swift -----------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SIL
|
|
|
|
extension LoadBorrowInst : Simplifiable, SILCombineSimplifiable {
|
|
func simplify(_ context: SimplifyContext) {
|
|
if uses.ignoreDebugUses.ignore(usersOfType: EndBorrowInst.self).isEmpty {
|
|
context.erase(instructionIncludingAllUsers: self)
|
|
return
|
|
}
|
|
|
|
if tryCombineWithCopy(context) {
|
|
return
|
|
}
|
|
|
|
if tryRemoveAddrCast(context) {
|
|
return
|
|
}
|
|
|
|
tryForwardStoreBorrow(context)
|
|
}
|
|
|
|
/// If the load_borrow is followed by a copy_value, combine both into a `load [copy]`:
|
|
/// ```
|
|
/// %1 = load_borrow %0
|
|
/// %2 = some_forwarding_instruction %1 // zero or more forwarding instructions
|
|
/// %3 = copy_value %2
|
|
/// end_borrow %1
|
|
/// ```
|
|
/// ->
|
|
/// ```
|
|
/// %1 = load [copy] %0
|
|
/// %3 = some_forwarding_instruction %1 // zero or more forwarding instructions
|
|
/// ```
|
|
///
|
|
private func tryCombineWithCopy(_ context: SimplifyContext) -> Bool {
|
|
let forwardedValue = lookThroughOwnedConvertibaleForwardingChain()
|
|
guard let singleUser = forwardedValue.uses.ignore(usersOfType: EndBorrowInst.self).singleUse?.instruction,
|
|
let copy = singleUser as? CopyValueInst,
|
|
copy.parentBlock == self.parentBlock else {
|
|
return false
|
|
}
|
|
let builder = Builder(before: self, context)
|
|
let loadCopy = builder.createLoad(fromAddress: address, ownership: .copy)
|
|
let forwardedOwnedValue = replaceGuaranteed(value: self, withOwnedValue: loadCopy, context)
|
|
copy.replace(with: forwardedOwnedValue, context)
|
|
context.erase(instructionIncludingAllUsers: self)
|
|
return true
|
|
}
|
|
|
|
/// Replaces address casts of heap objects
|
|
/// ```
|
|
/// %1 = unchecked_addr_cast %0 : $*SomeClass to $*OtherClass
|
|
/// %2 = load_borrow %1
|
|
/// // ... uses of %2
|
|
/// end_borrow %2
|
|
/// ```
|
|
/// with ref-casts of the loaded value
|
|
/// ```
|
|
/// %1 = load_borrow %0
|
|
/// %2 = unchecked_ref_cast %1 : $SomeClass to $OtherClass
|
|
/// // ... uses of %2
|
|
/// end_borrow %2
|
|
/// ```
|
|
/// Address casts are bad because they prevent alias analysis and AccessPath computation.
|
|
/// It's always better to use the corresponding value casts instead.
|
|
///
|
|
private func tryRemoveAddrCast(_ context: SimplifyContext) -> Bool {
|
|
guard let addrCast = address.isAddressCastOfHeapObjects else {
|
|
return false
|
|
}
|
|
let builder = Builder(before: self, context)
|
|
let newLoad = builder.createLoadBorrow(fromAddress: addrCast.fromAddress)
|
|
let cast = builder.createUncheckedRefCast(from: newLoad, to: addrCast.type.objectType)
|
|
replace(with: newLoad, context)
|
|
newLoad.uses.filter{ !$0.endsLifetime }.ignore(user: cast).replaceAll(with: cast, context)
|
|
return true
|
|
}
|
|
|
|
/// Replaces a `load_borrow` of a `store_borrow` with a `begin_borrow`:
|
|
/// ```
|
|
/// %1 = alloc_stack $T
|
|
/// %2 = store_borrow %0 to %1
|
|
/// ...
|
|
/// %3 = load_borrow %2
|
|
/// // ... uses of %3
|
|
/// end_borrow %3
|
|
/// ```
|
|
/// ->
|
|
/// ```
|
|
/// %1 = alloc_stack $T
|
|
/// %2 = store_borrow %0 to %1
|
|
/// ...
|
|
/// %3 = begin_borrow %0
|
|
/// // ... uses of %3
|
|
/// end_borrow %3
|
|
/// ```
|
|
private func tryForwardStoreBorrow(_ context: SimplifyContext) {
|
|
guard let storeBorrow = address as? StoreBorrowInst else {
|
|
return
|
|
}
|
|
let builder = Builder(before: self, context)
|
|
let beginBorrow = builder.createBeginBorrow(of: storeBorrow.source)
|
|
replace(with: beginBorrow, context)
|
|
}
|
|
}
|