Skip to content

Commit d653b0c

Browse files
authored
Merge pull request #84739 from atrick/lifedep-unsafeaddress
LifetimeDependenceDefUseWalker: store to unsafeMutableAddress
2 parents 5179bc9 + 4378995 commit d653b0c

File tree

8 files changed

+104
-10
lines changed

8 files changed

+104
-10
lines changed

SwiftCompilerSources/Sources/AST/Type.swift

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,8 @@ extension TypeProperties {
147147
public var isDynamicSelf: Bool { rawType.bridged.isDynamicSelf()}
148148
public var isBox: Bool { rawType.bridged.isBox() }
149149

150-
/// True if this is the type which represents an integer literal used in a type position.
151-
/// For example `N` in `struct T<let N: Int> {}`
152-
public var isInteger: Bool { rawType.bridged.isInteger() }
153-
154150
public var canBeClass: Type.TraitResult { rawType.bridged.canBeClass().result }
155151

156-
/// True if this the nominal type `Swift.Optional`.
157-
public var isOptional: Bool { rawType.bridged.isOptional() }
158-
159152
/// True if this type is a value type (struct/enum) that defines a `deinit`.
160153
public var isValueTypeWithDeinit: Bool {
161154
if let nominal = nominal, nominal.valueTypeDestructor != nil {
@@ -164,6 +157,34 @@ extension TypeProperties {
164157
return false
165158
}
166159

160+
//===--------------------------------------------------------------------===//
161+
// Checks for stdlib types
162+
//===--------------------------------------------------------------------===//
163+
164+
/// True if this is the type which represents an integer literal used in a type position.
165+
/// For example `N` in `struct T<let N: Int> {}`
166+
public var isInteger: Bool { rawType.bridged.isInteger() }
167+
168+
/// True if this the nominal type `Swift.Optional`.
169+
public var isOptional: Bool { rawType.bridged.isOptional() }
170+
171+
/// A non-nil result type implies isUnsafe[Raw][Mutable]Pointer. A raw
172+
/// pointer has a `void` element type.
173+
public var unsafePointerElementType: Type? {
174+
Type(bridgedOrNil: rawType.bridged.getAnyPointerElementType())
175+
}
176+
177+
public var isAnyUnsafePointer: Bool {
178+
unsafePointerElementType != nil
179+
}
180+
181+
public var isAnyUnsafeBufferPointer: Bool {
182+
rawType.bridged.isUnsafeBufferPointerType()
183+
|| rawType.bridged.isUnsafeMutableBufferPointerType()
184+
|| rawType.bridged.isUnsafeRawBufferPointerType()
185+
|| rawType.bridged.isUnsafeMutableRawBufferPointerType()
186+
}
187+
167188
//===--------------------------------------------------------------------===//
168189
// Properties of lowered `SILFunctionType`s
169190
//===--------------------------------------------------------------------===//

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/Function.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
5252

5353
public var isConvertPointerToPointerArgument: Bool { bridged.isConvertPointerToPointerArgument() }
5454

55+
public var isAddressor: Bool { bridged.isAddressor() }
56+
5557
public var specializationLevel: Int { bridged.specializationLevel() }
5658

5759
public var isSpecialization: Bool { bridged.isSpecialization() }

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

include/swift/AST/ASTBridging.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2955,6 +2955,11 @@ struct BridgedASTType {
29552955
BRIDGED_INLINE bool isBuiltinFixedWidthInteger(SwiftInt width) const;
29562956
BRIDGED_INLINE bool isOptional() const;
29572957
BRIDGED_INLINE bool isBuiltinType() const;
2958+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType getAnyPointerElementType() const;
2959+
BRIDGED_INLINE bool isUnsafeBufferPointerType() const;
2960+
BRIDGED_INLINE bool isUnsafeMutableBufferPointerType() const;
2961+
BRIDGED_INLINE bool isUnsafeRawBufferPointerType() const;
2962+
BRIDGED_INLINE bool isUnsafeMutableRawBufferPointerType() const;
29582963
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDeclObj getNominalOrBoundGenericNominal() const;
29592964
BRIDGED_INLINE TraitResult canBeClass() const;
29602965
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDeclObj getAnyNominal() const;

include/swift/AST/ASTBridgingImpl.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,26 @@ bool BridgedASTType::isBuiltinType() const {
566566
return unbridged()->isBuiltinType();
567567
}
568568

569+
BridgedASTType BridgedASTType::getAnyPointerElementType() const {
570+
return {unbridged()->getCanonicalType()->getAnyPointerElementType().getPointer()};
571+
}
572+
573+
bool BridgedASTType::isUnsafeBufferPointerType() const {
574+
return unbridged()->isUnsafeBufferPointer();
575+
}
576+
577+
bool BridgedASTType::isUnsafeMutableBufferPointerType() const {
578+
return unbridged()->isUnsafeMutableBufferPointer();
579+
}
580+
581+
bool BridgedASTType::isUnsafeRawBufferPointerType() const {
582+
return unbridged()->isUnsafeRawBufferPointer();
583+
}
584+
585+
bool BridgedASTType::isUnsafeMutableRawBufferPointerType() const {
586+
return unbridged()->isUnsafeMutableRawBufferPointer();
587+
}
588+
569589
OptionalBridgedDeclObj BridgedASTType::getNominalOrBoundGenericNominal() const {
570590
return {unbridged()->getNominalOrBoundGenericNominal()};
571591
}

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ struct BridgedFunction {
562562
BRIDGED_INLINE bool isSpecialization() const;
563563
bool isTrapNoReturn() const;
564564
bool isConvertPointerToPointerArgument() const;
565+
bool isAddressor() const;
565566
bool isAutodiffVJP() const;
566567
SwiftInt specializationLevel() const;
567568
SWIFT_IMPORT_UNSAFE BridgedSubstitutionMap getMethodSubstitutions(BridgedSubstitutionMap contextSubs,

lib/SILOptimizer/Utils/OptimizerBridging.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,13 @@ bool BridgedFunction::isConvertPointerToPointerArgument() const {
511511
return false;
512512
}
513513

514+
bool BridgedFunction::isAddressor() const {
515+
if (auto declRef = dyn_cast_or_null<AccessorDecl>(getFunction()->getDeclRef().getDecl())) {
516+
return declRef->isAnyAddressor();
517+
}
518+
return false;
519+
}
520+
514521
bool BridgedFunction::isAutodiffVJP() const {
515522
return swift::isDifferentiableFuncComponent(
516523
getFunction(), swift::AutoDiffFunctionComponent::VJP);

0 commit comments

Comments
 (0)