Skip to content

Commit c764244

Browse files
authored
Merge pull request #84180 from meg-gupta/borrowandmutatepr
Add preliminary support for borrow accessors
2 parents 926fc78 + aeac529 commit c764244

File tree

97 files changed

+2410
-193
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+2410
-193
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,11 @@ private struct CollectedEffects {
254254
// effect, it would not give any significant benefit in any of our current optimizations.
255255
addEffects(.destroy, to: inst.operands[0].value, fromInitialPath: SmallProjectionPath(.anyValueFields))
256256

257+
case is ReturnInst:
258+
if inst.parentFunction.convention.hasGuaranteedAddressResult {
259+
addEffects(.read, to: inst.operands[0].value)
260+
}
261+
257262
default:
258263
if inst.mayRelease {
259264
globalEffects = .worstEffects

SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -806,6 +806,10 @@ extension InteriorUseWalker {
806806
if let inst = operand.instruction as? ForwardingInstruction {
807807
return inst.forwardedResults.walk { walkDownUses(of: $0) }
808808
}
809+
// TODO: Represent apply of borrow accessors as ForwardingOperation and use that over ForwardingInstruction
810+
if let apply = operand.instruction as? FullApplySite, apply.hasGuaranteedResult {
811+
return walkDownUses(of: apply.singleDirectResult!)
812+
}
809813
// TODO: verify that ForwardInstruction handles all .forward operand ownership and assert that only phis can be
810814
// reached: assert(Phi(using: operand) != nil)
811815
return .continueWalk

SwiftCompilerSources/Sources/SIL/ApplySite.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,14 @@ extension ApplySite {
299299
public func calleeArgumentIndex(of operand: Operand) -> Int? {
300300
operandConventions.calleeArgumentIndex(of: operand)
301301
}
302+
303+
public var hasGuaranteedResult: Bool {
304+
functionConvention.hasGuaranteedResult
305+
}
306+
307+
public var hasGuaranteedAddressResult: Bool {
308+
functionConvention.hasGuaranteedAddressResult
309+
}
302310
}
303311

304312
extension ApplySite {

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ public enum ArgumentConvention : CustomStringConvertible {
488488
self = .directUnowned
489489
case .pack:
490490
self = .packOut
491+
case .guaranteed, .guaranteedAddress:
492+
fatalError("Result conventions @guaranteed and @guaranteed_addr are always returned directly")
491493
}
492494
}
493495

SwiftCompilerSources/Sources/SIL/FunctionConvention.swift

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ public struct FunctionConvention : CustomStringConvertible {
9898
return SILFunctionType_getLifetimeDependencies(functionType.bridged).count() != 0
9999
}
100100

101+
public var hasGuaranteedResult: Bool {
102+
if results.count != 1 {
103+
return false
104+
}
105+
return results[0].convention == .guaranteed
106+
}
107+
108+
public var hasGuaranteedAddressResult: Bool {
109+
if results.count != 1 {
110+
return false
111+
}
112+
return results[0].convention == .guaranteedAddress
113+
}
114+
101115
public var description: String {
102116
var str = functionType.description
103117
for paramIdx in 0..<parameters.count {
@@ -133,7 +147,7 @@ public struct ResultInfo : CustomStringConvertible {
133147
return hasLoweredAddresses || type.isExistentialArchetypeWithError()
134148
case .pack:
135149
return true
136-
case .owned, .unowned, .unownedInnerPointer, .autoreleased:
150+
case .owned, .unowned, .unownedInnerPointer, .autoreleased, .guaranteed, .guaranteedAddress:
137151
return false
138152
}
139153
}
@@ -358,6 +372,14 @@ public enum ResultConvention : CustomStringConvertible {
358372
/// The caller is responsible for destroying this return value. Its type is non-trivial.
359373
case owned
360374

375+
/// The caller is responsible for using the returned address within a valid
376+
/// scope. This is valid only for borrow and mutate accessors.
377+
case guaranteedAddress
378+
379+
/// The caller is responsible for using the returned value within a valid
380+
/// scope. This is valid only for borrow accessors.
381+
case guaranteed
382+
361383
/// The caller is not responsible for destroying this return value. Its type may be trivial, or it may simply be offered unsafely. It is valid at the instant of the return, but further operations may invalidate it.
362384
case unowned
363385

@@ -397,6 +419,10 @@ public enum ResultConvention : CustomStringConvertible {
397419
return "autoreleased"
398420
case .pack:
399421
return "pack"
422+
case .guaranteed:
423+
return "guaranteed"
424+
case .guaranteedAddress:
425+
return "guaranteedAddress"
400426
}
401427
}
402428
}
@@ -428,6 +454,8 @@ extension ResultConvention {
428454
case .UnownedInnerPointer: self = .unownedInnerPointer
429455
case .Autoreleased: self = .autoreleased
430456
case .Pack: self = .pack
457+
case .Guaranteed: self = .guaranteed
458+
case .GuaranteedAddress: self = .guaranteedAddress
431459
default:
432460
fatalError("unsupported result convention")
433461
}

SwiftCompilerSources/Sources/SIL/Utilities/BorrowUtils.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,9 @@ public final class EnclosingValueIterator : IteratorProtocol {
535535
// Recurse through guaranteed forwarding non-phi instructions.
536536
let ops = forwardingInst.forwardedOperands
537537
worklist.pushIfNotVisited(contentsOf: ops.lazy.map { $0.value })
538+
} else if value.isGuaranteedApplyResult {
539+
let selfArgument = (value as! ApplyInst).arguments.last!
540+
worklist.pushIfNotVisited(selfArgument)
538541
} else {
539542
fatalError("cannot get borrow introducers for unknown guaranteed value")
540543
}
@@ -617,6 +620,19 @@ extension Value {
617620
}
618621
return self
619622
}
623+
624+
public var isGuaranteedApplyResult: Bool {
625+
guard let definingInstruction = self.definingInstruction else {
626+
return false
627+
}
628+
guard let apply = definingInstruction as? ApplyInst else {
629+
return false
630+
}
631+
guard apply.singleDirectResult != nil else {
632+
return false
633+
}
634+
return apply.functionConvention.results[0].convention == .guaranteed
635+
}
620636
}
621637

622638
extension Phi {

SwiftCompilerSources/Sources/SIL/Utilities/Verifier.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ private extension Instruction {
6161

6262
func checkGuaranteedResults() {
6363
for result in results where result.ownership == .guaranteed {
64-
require(BeginBorrowValue(result) != nil || self is ForwardingInstruction,
64+
require(BeginBorrowValue(result) != nil || self is ForwardingInstruction || result.isGuaranteedApplyResult,
6565
"\(result) must either be a BeginBorrowValue or a ForwardingInstruction")
6666
}
6767
}

docs/ABI/Mangling.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ Entities
401401
ACCESSOR ::= 'p' // pseudo accessor referring to the storage itself
402402
ACCESSOR ::= 'x' // modify
403403
ACCESSOR ::= 'y' // read
404+
ACCESSOR ::= 'b' // borrow
405+
ACCESSOR ::= 'z' // mutate
404406

405407
ADDRESSOR-KIND ::= 'u' // unsafe addressor (no owner)
406408
ADDRESSOR-KIND ::= 'O' // owning addressor (non-native owner), not used anymore

docs/SIL/Ownership.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,11 @@ SILValue. Instead, it constrains the lifetime of an addressable
814814
variable. Since the constraint is applied to the in-memory
815815
representation, no additional lexical SILValue is required.
816816
817+
The `self` function argument in a borrow accessor is not lexical.
818+
`self` is already borrowed for the duration of the borrow accessor and the
819+
dependency between borrowed return value and `self` will be represented in SIL,
820+
making lexical lifetime unnecessary.
821+
817822
### Deinit Barriers
818823
819824
Deinit barriers (see Instruction.isDeinitBarrier(_:)) are instructions

include/swift/AST/AccessorKinds.def

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@
116116
#define INIT_ACCESSOR(ID, KEYWORD) SINGLETON_ACCESSOR(ID, KEYWORD)
117117
#endif
118118

119+
#ifndef BORROW_ACCESSOR
120+
#define BORROW_ACCESSOR(ID, KEYWORD) SINGLETON_ACCESSOR(ID, KEYWORD)
121+
#endif
122+
123+
#ifndef MUTATE_ACCESSOR
124+
#define MUTATE_ACCESSOR(ID, KEYWORD) SINGLETON_ACCESSOR(ID, KEYWORD)
125+
#endif
126+
119127
/// This is a getter: a function that is called when a value is loaded
120128
/// from the storage. It returns an owned value of the storage type.
121129
///
@@ -217,8 +225,12 @@ MUTABLE_ADDRESSOR(MutableAddress, unsafeMutableAddress)
217225
/// re-writes assignment to initialization.
218226
INIT_ACCESSOR(Init, init)
219227

228+
BORROW_ACCESSOR(Borrow, borrow)
229+
230+
MUTATE_ACCESSOR(Mutate, mutate)
231+
220232
#ifdef LAST_ACCESSOR
221-
LAST_ACCESSOR(Init)
233+
LAST_ACCESSOR(Mutate)
222234
#undef LAST_ACCESSOR
223235
#endif
224236

0 commit comments

Comments
 (0)