Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions SwiftCompilerSources/Sources/AST/Type.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,8 @@ extension TypeProperties {
public var isDynamicSelf: Bool { rawType.bridged.isDynamicSelf()}
public var isBox: Bool { rawType.bridged.isBox() }

/// True if this is the type which represents an integer literal used in a type position.
/// For example `N` in `struct T<let N: Int> {}`
public var isInteger: Bool { rawType.bridged.isInteger() }

public var canBeClass: Type.TraitResult { rawType.bridged.canBeClass().result }

/// True if this the nominal type `Swift.Optional`.
public var isOptional: Bool { rawType.bridged.isOptional() }

/// True if this type is a value type (struct/enum) that defines a `deinit`.
public var isValueTypeWithDeinit: Bool {
if let nominal = nominal, nominal.valueTypeDestructor != nil {
Expand All @@ -164,6 +157,34 @@ extension TypeProperties {
return false
}

//===--------------------------------------------------------------------===//
// Checks for stdlib types
//===--------------------------------------------------------------------===//

/// True if this is the type which represents an integer literal used in a type position.
/// For example `N` in `struct T<let N: Int> {}`
public var isInteger: Bool { rawType.bridged.isInteger() }

/// True if this the nominal type `Swift.Optional`.
public var isOptional: Bool { rawType.bridged.isOptional() }

/// A non-nil result type implies isUnsafe[Raw][Mutable]Pointer. A raw
/// pointer has a `void` element type.
public var unsafePointerElementType: Type? {
Type(bridgedOrNil: rawType.bridged.getAnyPointerElementType())
}

public var isAnyUnsafePointer: Bool {
unsafePointerElementType != nil
}

public var isAnyUnsafeBufferPointer: Bool {
rawType.bridged.isUnsafeBufferPointerType()
|| rawType.bridged.isUnsafeMutableBufferPointerType()
|| rawType.bridged.isUnsafeRawBufferPointerType()
|| rawType.bridged.isUnsafeMutableRawBufferPointerType()
}

//===--------------------------------------------------------------------===//
// Properties of lowered `SILFunctionType`s
//===--------------------------------------------------------------------===//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,7 @@ extension LifetimeDependenceDefUseWalker {
return walkDownUses(of: value, using: operand)
}

// copy_addr
// copy_addr %operand to %address; %_newAddr = mark_dependence %address on %operand
mutating func loadedAddressUse(of operand: Operand, intoAddress address: Operand) -> WalkResult {
if leafUse(of: operand) == .abortWalk {
return .abortWalk
Expand Down Expand Up @@ -971,7 +971,29 @@ extension LifetimeDependenceDefUseWalker {
break
case .yield:
return storeToYieldDependence(address: address, of: operand)
case .global, .class, .tail, .storeBorrow, .pointer, .index, .unidentified:
case let .pointer(p2a):
if !address.isEscapable, let base = p2a.isResultOfUnsafeAddressor() {
let selfValue = base.value
if selfValue.type.isAddress {
// Normally an unsafeMutableAddressor is mutating, so this is the common case (address-type
// 'selfValue'). Treat the store to this pointer-to-address projection just like any store to the local
// variable holding 'selfValue'.
return visitStoredUses(of: operand, into: selfValue)
}
// selfValue.type might not an be address:
// (1) mark_dependence on unsafeAddress is handled like a storedUse
// (2) nonmutating unsafeMutableAddress (e.g. UnsafeMutable[Buffer]Pointer).
// A nonmutating unsafeMutableAddress is only expected to happen for UnsafeMutable[Buffer]Pointer, in which case

// If selfValue is trivial (UnsafeMutable[Buffer]Pointer), its uses can be ignored.
if selfValue.type.isTrivial(in: selfValue.parentFunction) {
return .continueWalk
}
// Otherwise a store to indirect memory is conservatively escaping.
return escapingDependence(on: operand)
}
break
case .global, .class, .tail, .storeBorrow, .index, .unidentified:
// An address produced by .storeBorrow should never be stored into.
//
// TODO: allow storing an immortal value into a global.
Expand Down Expand Up @@ -1045,7 +1067,7 @@ extension LifetimeDependenceDefUseWalker {
}
case .dependenceDest:
// Simply a marker that indicates the start of an in-memory dependent value. If this was a mark_dependence, uses
// of its forwarded address has were visited by LocalVariableAccessWalker and recorded as separate local accesses.
// of its forwarded address were visited by LocalVariableAccessWalker and recorded as separate local accesses.
return .continueWalk
case .store, .storeBorrow:
// A store does not use the previous in-memory value.
Expand Down
2 changes: 2 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Function.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash

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

public var isAddressor: Bool { bridged.isAddressor() }

public var specializationLevel: Int { bridged.specializationLevel() }

public var isSpecialization: Bool { bridged.isSpecialization() }
Expand Down
16 changes: 16 additions & 0 deletions SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,22 @@ public extension PointerToAddressInst {
}
return nil
}

// If this address is the result of a call to unsafe[Mutable]Address, return the 'self' operand of the apply. This
// represents the base value into which this address projects.
func isResultOfUnsafeAddressor() -> Operand? {
if isStrict,
let extract = pointer as? StructExtractInst,
extract.`struct`.type.isAnyUnsafePointer,
let addressorApply = extract.`struct` as? ApplyInst,
let addressorFunc = addressorApply.referencedFunction,
addressorFunc.isAddressor
{
let selfArgIdx = addressorFunc.selfArgumentIndex!
return addressorApply.argumentOperands[selfArgIdx]
}
return nil
}
}

/// TODO: migrate AccessBase to use this instead of GlobalVariable because many utilities need to get back to a
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -2955,6 +2955,11 @@ struct BridgedASTType {
BRIDGED_INLINE bool isBuiltinFixedWidthInteger(SwiftInt width) const;
BRIDGED_INLINE bool isOptional() const;
BRIDGED_INLINE bool isBuiltinType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType getAnyPointerElementType() const;
BRIDGED_INLINE bool isUnsafeBufferPointerType() const;
BRIDGED_INLINE bool isUnsafeMutableBufferPointerType() const;
BRIDGED_INLINE bool isUnsafeRawBufferPointerType() const;
BRIDGED_INLINE bool isUnsafeMutableRawBufferPointerType() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDeclObj getNominalOrBoundGenericNominal() const;
BRIDGED_INLINE TraitResult canBeClass() const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDeclObj getAnyNominal() const;
Expand Down
20 changes: 20 additions & 0 deletions include/swift/AST/ASTBridgingImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,26 @@ bool BridgedASTType::isBuiltinType() const {
return unbridged()->isBuiltinType();
}

BridgedASTType BridgedASTType::getAnyPointerElementType() const {
return {unbridged()->getCanonicalType()->getAnyPointerElementType().getPointer()};
}

bool BridgedASTType::isUnsafeBufferPointerType() const {
return unbridged()->isUnsafeBufferPointer();
}

bool BridgedASTType::isUnsafeMutableBufferPointerType() const {
return unbridged()->isUnsafeMutableBufferPointer();
}

bool BridgedASTType::isUnsafeRawBufferPointerType() const {
return unbridged()->isUnsafeRawBufferPointer();
}

bool BridgedASTType::isUnsafeMutableRawBufferPointerType() const {
return unbridged()->isUnsafeMutableRawBufferPointer();
}

OptionalBridgedDeclObj BridgedASTType::getNominalOrBoundGenericNominal() const {
return {unbridged()->getNominalOrBoundGenericNominal()};
}
Expand Down
1 change: 1 addition & 0 deletions include/swift/SIL/SILBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,7 @@ struct BridgedFunction {
BRIDGED_INLINE bool isSpecialization() const;
bool isTrapNoReturn() const;
bool isConvertPointerToPointerArgument() const;
bool isAddressor() const;
bool isAutodiffVJP() const;
SwiftInt specializationLevel() const;
SWIFT_IMPORT_UNSAFE BridgedSubstitutionMap getMethodSubstitutions(BridgedSubstitutionMap contextSubs,
Expand Down
7 changes: 7 additions & 0 deletions lib/SILOptimizer/Utils/OptimizerBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,13 @@ bool BridgedFunction::isConvertPointerToPointerArgument() const {
return false;
}

bool BridgedFunction::isAddressor() const {
if (auto declRef = dyn_cast_or_null<AccessorDecl>(getFunction()->getDeclRef().getDecl())) {
return declRef->isAnyAddressor();
}
return false;
}

bool BridgedFunction::isAutodiffVJP() const {
return swift::isDifferentiableFuncComponent(
getFunction(), swift::AutoDiffFunctionComponent::VJP);
Expand Down