Skip to content

Commit 4378995

Browse files
committed
LifetimeDependenceDefUseWalker: store to unsafeMutableAddress
Handle storing to a mutable property implemented as unsafeMutableAddress. In SIL, the stored address comes from pointer_to_address. Recognize the addressor pattern and handle the store as if it writes to a regular property of 'self'. Required for UnsafePointer<~Escapable>.pointee.
1 parent 4a7895e commit 4378995

File tree

2 files changed

+41
-3
lines changed

2 files changed

+41
-3
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ extension LifetimeDependenceDefUseWalker {
862862
return walkDownUses(of: value, using: operand)
863863
}
864864

865-
// copy_addr
865+
// copy_addr %operand to %address; %_newAddr = mark_dependence %address on %operand
866866
mutating func loadedAddressUse(of operand: Operand, intoAddress address: Operand) -> WalkResult {
867867
if leafUse(of: operand) == .abortWalk {
868868
return .abortWalk
@@ -971,7 +971,29 @@ extension LifetimeDependenceDefUseWalker {
971971
break
972972
case .yield:
973973
return storeToYieldDependence(address: address, of: operand)
974-
case .global, .class, .tail, .storeBorrow, .pointer, .index, .unidentified:
974+
case let .pointer(p2a):
975+
if !address.isEscapable, let base = p2a.isResultOfUnsafeAddressor() {
976+
let selfValue = base.value
977+
if selfValue.type.isAddress {
978+
// Normally an unsafeMutableAddressor is mutating, so this is the common case (address-type
979+
// 'selfValue'). Treat the store to this pointer-to-address projection just like any store to the local
980+
// variable holding 'selfValue'.
981+
return visitStoredUses(of: operand, into: selfValue)
982+
}
983+
// selfValue.type might not an be address:
984+
// (1) mark_dependence on unsafeAddress is handled like a storedUse
985+
// (2) nonmutating unsafeMutableAddress (e.g. UnsafeMutable[Buffer]Pointer).
986+
// A nonmutating unsafeMutableAddress is only expected to happen for UnsafeMutable[Buffer]Pointer, in which case
987+
988+
// If selfValue is trivial (UnsafeMutable[Buffer]Pointer), its uses can be ignored.
989+
if selfValue.type.isTrivial(in: selfValue.parentFunction) {
990+
return .continueWalk
991+
}
992+
// Otherwise a store to indirect memory is conservatively escaping.
993+
return escapingDependence(on: operand)
994+
}
995+
break
996+
case .global, .class, .tail, .storeBorrow, .index, .unidentified:
975997
// An address produced by .storeBorrow should never be stored into.
976998
//
977999
// TODO: allow storing an immortal value into a global.
@@ -1045,7 +1067,7 @@ extension LifetimeDependenceDefUseWalker {
10451067
}
10461068
case .dependenceDest:
10471069
// Simply a marker that indicates the start of an in-memory dependent value. If this was a mark_dependence, uses
1048-
// of its forwarded address has were visited by LocalVariableAccessWalker and recorded as separate local accesses.
1070+
// of its forwarded address were visited by LocalVariableAccessWalker and recorded as separate local accesses.
10491071
return .continueWalk
10501072
case .store, .storeBorrow:
10511073
// A store does not use the previous in-memory value.

SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,22 @@ public extension PointerToAddressInst {
512512
}
513513
return nil
514514
}
515+
516+
// If this address is the result of a call to unsafe[Mutable]Address, return the 'self' operand of the apply. This
517+
// represents the base value into which this address projects.
518+
func isResultOfUnsafeAddressor() -> Operand? {
519+
if isStrict,
520+
let extract = pointer as? StructExtractInst,
521+
extract.`struct`.type.isAnyUnsafePointer,
522+
let addressorApply = extract.`struct` as? ApplyInst,
523+
let addressorFunc = addressorApply.referencedFunction,
524+
addressorFunc.isAddressor
525+
{
526+
let selfArgIdx = addressorFunc.selfArgumentIndex!
527+
return addressorApply.argumentOperands[selfArgIdx]
528+
}
529+
return nil
530+
}
515531
}
516532

517533
/// TODO: migrate AccessBase to use this instead of GlobalVariable because many utilities need to get back to a

0 commit comments

Comments
 (0)