Skip to content

Commit 4abca2b

Browse files
committed
Merge tag 'swift-DEVELOPMENT-SNAPSHOT-2022-09-12-a' of github.com:apple/swift into cal--implicit-weak-self
Tag build swift-DEVELOPMENT-SNAPSHOT-2022-09-12-a
2 parents 95949ce + 9ab055a commit 4abca2b

Some content is hidden

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

52 files changed

+4750
-390
lines changed

SwiftCompilerSources/Sources/SIL/Effects.swift

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
1616
public typealias Path = SmallProjectionPath
1717

1818
public enum Kind {
19-
/// The selected argument value does not escape.
19+
/// The argument value does not escape.
2020
///
2121
/// Syntax examples:
22-
/// !%0 // argument 0 does not escape
23-
/// !%0.** // argument 0 and all transitively contained values do not escape
22+
/// [%0: noescape] // argument 0 does not escape
23+
/// [%0: noescape **] // argument 0 and all transitively contained values do not escape
2424
///
2525
case notEscaping
2626

27-
/// The selected argument value escapes to the specified selection (= first payload).
27+
/// The argument value escapes to the function return value.
2828
///
2929
/// Syntax examples:
30-
/// %0.s1 => %r // field 2 of argument 0 exclusively escapes via return.
31-
/// %0.s1 -> %1 // field 2 of argument 0 - and other values - escape to argument 1.
30+
/// [%0: escape s1 => %r] // field 2 of argument 0 exclusively escapes via return.
31+
/// [%0: escape s1 -> %r] // field 2 of argument 0 - and other values - escape via return
3232
///
33-
/// The "exclusive" flag (= second payload) is true if only the selected argument escapes
34-
/// to the specified selection, but nothing else escapes to it.
33+
/// The "exclusive" flag (= second payload) is true if only the argument escapes,
34+
/// but nothing else escapes to the return value.
3535
/// For example, "exclusive" is true for the following function:
3636
///
3737
/// @_effect(escaping c => return)
@@ -46,6 +46,14 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
4646
///
4747
case escapingToReturn(Path, Bool) // toPath, exclusive
4848

49+
/// Like `escapingToReturn`, but the argument escapes to another argument.
50+
///
51+
/// Example: The argument effects of
52+
/// func argToArgEscape(_ r: inout Class, _ c: Class) { r = c }
53+
///
54+
/// would be
55+
/// [%1: escape => %0] // Argument 1 escapes to argument 0
56+
///
4957
case escapingToArgument(Int, Path, Bool) // toArgumentIndex, toPath, exclusive
5058
}
5159

@@ -111,21 +119,28 @@ public struct ArgumentEffect : CustomStringConvertible, CustomReflectable {
111119
return argumentIndex == rhsArgIdx && rhsPath.matches(pattern: pathPattern)
112120
}
113121

114-
public var description: String {
115-
let selectedArg = "%\(argumentIndex)" + (pathPattern.isEmpty ? "" : ".\(pathPattern)")
122+
public var headerDescription: String {
123+
"%\(argumentIndex)\(isDerived ? "" : "!"): "
124+
}
116125

126+
public var bodyDescription: String {
127+
let patternStr = pathPattern.isEmpty ? "" : " \(pathPattern)"
117128
switch kind {
118129
case .notEscaping:
119-
return "!\(selectedArg)"
130+
return "noescape\(patternStr)"
120131
case .escapingToReturn(let toPath, let exclusive):
121-
let pathStr = (toPath.isEmpty ? "" : ".\(toPath)")
122-
return "\(selectedArg) \(exclusive ? "=>" : "->") %r\(pathStr)"
132+
let toPathStr = (toPath.isEmpty ? "" : ".\(toPath)")
133+
return "escape\(patternStr) \(exclusive ? "=>" : "->") %r\(toPathStr)"
123134
case .escapingToArgument(let toArgIdx, let toPath, let exclusive):
124-
let pathStr = (toPath.isEmpty ? "" : ".\(toPath)")
125-
return "\(selectedArg) \(exclusive ? "=>" : "->") %\(toArgIdx)\(pathStr)"
135+
let toPathStr = (toPath.isEmpty ? "" : ".\(toPath)")
136+
return "escape\(patternStr) \(exclusive ? "=>" : "->") %\(toArgIdx)\(toPathStr)"
126137
}
127138
}
128139

140+
public var description: String {
141+
headerDescription + bodyDescription
142+
}
143+
129144
public var customMirror: Mirror { Mirror(self, children: []) }
130145
}
131146

@@ -164,8 +179,27 @@ public struct FunctionEffects : CustomStringConvertible, CustomReflectable {
164179
argumentEffects = argumentEffects.filter { !$0.isDerived }
165180
}
166181

182+
public var argumentEffectsDescription: String {
183+
var currentArgIdx = -1
184+
var currentIsDerived = false
185+
var result = ""
186+
for effect in argumentEffects {
187+
if effect.argumentIndex != currentArgIdx || effect.isDerived != currentIsDerived {
188+
if currentArgIdx >= 0 { result += "]\n" }
189+
result += "[\(effect.headerDescription)"
190+
currentArgIdx = effect.argumentIndex
191+
currentIsDerived = effect.isDerived
192+
} else {
193+
result += ", "
194+
}
195+
result += effect.bodyDescription
196+
}
197+
if currentArgIdx >= 0 { result += "]\n" }
198+
return result
199+
}
200+
167201
public var description: String {
168-
return "[" + argumentEffects.map { $0.description }.joined(separator: ", ") + "]"
202+
return argumentEffectsDescription
169203
}
170204

171205
public var customMirror: Mirror { Mirror(self, children: []) }
@@ -237,24 +271,37 @@ extension StringParser {
237271
return ArgumentEffect.Path()
238272
}
239273

240-
mutating func parseEffectFromSIL(for function: Function, isDerived: Bool) throws -> ArgumentEffect {
241-
if consume("!") {
242-
let argIdx = try parseArgumentIndexFromSIL()
243-
let path = try parsePathPatternFromSIL()
244-
return ArgumentEffect(.notEscaping, argumentIndex: argIdx, pathPattern: path, isDerived: isDerived)
274+
mutating func parseEffectsFromSIL(to effects: inout FunctionEffects) throws {
275+
let argumentIndex = try parseArgumentIndexFromSIL()
276+
let isDerived = !consume("!")
277+
if !consume(":") {
278+
try throwError("expected ':'")
245279
}
246-
let fromArgIdx = try parseArgumentIndexFromSIL()
247-
let fromPath = try parsePathPatternFromSIL()
248-
let exclusive = try parseEscapingArrow()
249-
if consume("%r") {
250-
let toPath = try parsePathPatternFromSIL()
251-
return ArgumentEffect(.escapingToReturn(toPath, exclusive),
252-
argumentIndex: fromArgIdx, pathPattern: fromPath, isDerived: isDerived)
280+
repeat {
281+
let effect = try parseEffectFromSIL(argumentIndex: argumentIndex, isDerived: isDerived)
282+
effects.argumentEffects.append(effect)
283+
} while consume(",")
284+
}
285+
286+
mutating func parseEffectFromSIL(argumentIndex: Int, isDerived: Bool) throws -> ArgumentEffect {
287+
if consume("noescape") {
288+
let path = try parseProjectionPathFromSIL()
289+
return ArgumentEffect(.notEscaping, argumentIndex: argumentIndex, pathPattern: path, isDerived: isDerived)
290+
}
291+
if consume("escape") {
292+
let fromPath = try parseProjectionPathFromSIL()
293+
let exclusive = try parseEscapingArrow()
294+
if consume("%r") {
295+
let toPath = consume(".") ? try parseProjectionPathFromSIL() : ArgumentEffect.Path()
296+
return ArgumentEffect(.escapingToReturn(toPath, exclusive),
297+
argumentIndex: argumentIndex, pathPattern: fromPath, isDerived: isDerived)
298+
}
299+
let toArgIdx = try parseArgumentIndexFromSIL()
300+
let toPath = consume(".") ? try parseProjectionPathFromSIL() : ArgumentEffect.Path()
301+
return ArgumentEffect(.escapingToArgument(toArgIdx, toPath, exclusive),
302+
argumentIndex: argumentIndex, pathPattern: fromPath, isDerived: isDerived)
253303
}
254-
let toArgIdx = try parseArgumentIndexFromSIL()
255-
let toPath = try parsePathPatternFromSIL()
256-
return ArgumentEffect(.escapingToArgument(toArgIdx, toPath, exclusive),
257-
argumentIndex: fromArgIdx, pathPattern: fromPath, isDerived: isDerived)
304+
try throwError("unknown effect")
258305
}
259306

260307
mutating func parseArgumentIndexFromSIL() throws -> Int {
@@ -267,13 +314,6 @@ extension StringParser {
267314
try throwError("expected parameter")
268315
}
269316

270-
mutating func parsePathPatternFromSIL() throws -> ArgumentEffect.Path {
271-
if consume(".") {
272-
return try parseProjectionPathFromSIL()
273-
}
274-
return ArgumentEffect.Path()
275-
}
276-
277317
private mutating func parseEscapingArrow() throws -> Bool {
278318
if consume("=>") { return true }
279319
if consume("->") { return false }

SwiftCompilerSources/Sources/SIL/Function.swift

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -133,27 +133,36 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
133133
},
134134
// writeFn
135135
{ (f: BridgedFunction, os: BridgedOStream, idx: Int) in
136-
let s = f.function.effects.argumentEffects[idx].description
136+
let s: String
137+
if idx >= 0 {
138+
s = f.function.effects.argumentEffects[idx].bodyDescription
139+
} else {
140+
s = f.function.effects.argumentEffectsDescription
141+
}
137142
s._withStringRef { OStream_write(os, $0) }
138143
},
139144
// parseFn:
140-
{ (f: BridgedFunction, str: llvm.StringRef, fromSIL: Int, isDerived: Int, paramNames: BridgedArrayRef) -> BridgedParsingError in
145+
{ (f: BridgedFunction, str: llvm.StringRef, fromSIL: Int, argumentIndex: Int, isDerived: Int, paramNames: BridgedArrayRef) -> BridgedParsingError in
141146
do {
142147
var parser = StringParser(str.string)
143-
let effect: ArgumentEffect
144-
if fromSIL != 0 {
145-
effect = try parser.parseEffectFromSIL(for: f.function, isDerived: isDerived != 0)
148+
149+
if fromSIL != 0 && argumentIndex < 0 {
150+
try parser.parseEffectsFromSIL(to: &f.function.effects)
146151
} else {
147-
let paramToIdx = paramNames.withElements(ofType: llvm.StringRef.self) {
148-
(buffer: UnsafeBufferPointer<llvm.StringRef>) -> Dictionary<String, Int> in
149-
let keyValPairs = buffer.enumerated().lazy.map { ($0.1.string, $0.0) }
150-
return Dictionary(uniqueKeysWithValues: keyValPairs)
152+
let effect: ArgumentEffect
153+
if fromSIL != 0 {
154+
effect = try parser.parseEffectFromSIL(argumentIndex: argumentIndex, isDerived: isDerived != 0)
155+
} else {
156+
let paramToIdx = paramNames.withElements(ofType: llvm.StringRef.self) {
157+
(buffer: UnsafeBufferPointer<llvm.StringRef>) -> Dictionary<String, Int> in
158+
let keyValPairs = buffer.enumerated().lazy.map { ($0.1.string, $0.0) }
159+
return Dictionary(uniqueKeysWithValues: keyValPairs)
160+
}
161+
effect = try parser.parseEffectFromSource(for: f.function, params: paramToIdx)
151162
}
152-
effect = try parser.parseEffectFromSource(for: f.function, params: paramToIdx)
163+
f.function.effects.argumentEffects.append(effect)
153164
}
154165
if !parser.isEmpty() { try parser.throwError("syntax error") }
155-
156-
f.function.effects.argumentEffects.append(effect)
157166
} catch let error as ParsingError {
158167
return BridgedParsingError(message: error.message.utf8Start, position: error.position)
159168
} catch {
@@ -179,20 +188,14 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
179188
resultArgDelta: destResultArgs - srcResultArgs)
180189
return 1
181190
},
182-
// getEffectFlags
183-
{ (f: BridgedFunction, idx: Int) -> Int in
191+
// getEffectInfo
192+
{ (f: BridgedFunction, idx: Int) -> BridgedEffectInfo in
184193
let argEffects = f.function.effects.argumentEffects
185-
if idx >= argEffects.count { return 0 }
186-
let effect = argEffects[idx]
187-
var flags = 0
188-
switch effect.kind {
189-
case .notEscaping, .escapingToArgument, .escapingToReturn:
190-
flags |= Int(EffectsFlagEscape)
191-
}
192-
if effect.isDerived {
193-
flags |= Int(EffectsFlagDerived)
194+
if idx >= argEffects.count {
195+
return BridgedEffectInfo(argumentIndex: -1, isDerived: false)
194196
}
195-
return flags
197+
let effect = argEffects[idx]
198+
return BridgedEffectInfo(argumentIndex: effect.argumentIndex, isDerived: effect.isDerived)
196199
}
197200
)
198201
}

SwiftCompilerSources/Sources/SIL/SmallProjectionPath.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ extension StringParser {
471471

472472
mutating func parseProjectionPathFromSIL() throws -> SmallProjectionPath {
473473
var entries: [(SmallProjectionPath.FieldKind, Int)] = []
474-
repeat {
474+
while true {
475475
if consume("**") {
476476
entries.append((.anything, 0))
477477
} else if consume("c*") {
@@ -497,12 +497,10 @@ extension StringParser {
497497
entries.append((.structField, idx))
498498
} else if let tupleElemIdx = consumeInt() {
499499
entries.append((.tupleField, tupleElemIdx))
500-
} else {
501-
try throwError("expected selection path component")
500+
} else if !consume(".") {
501+
return try createPath(from: entries)
502502
}
503-
} while consume(".")
504-
505-
return try createPath(from: entries)
503+
}
506504
}
507505

508506
private func createPath(from entries: [(SmallProjectionPath.FieldKind, Int)]) throws -> SmallProjectionPath {

docs/SIL.rst

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ Functions
956956
decl ::= sil-function
957957
sil-function ::= 'sil' sil-linkage? sil-function-attribute+
958958
sil-function-name ':' sil-type
959-
'{' sil-basic-block+ '}'
959+
'{' argument-effect* sil-basic-block* '}'
960960
sil-function-name ::= '@' [A-Za-z_0-9]+
961961

962962
SIL functions are defined with the ``sil`` keyword. SIL function names
@@ -966,6 +966,8 @@ and is usually the mangled name of the originating Swift declaration.
966966
The ``sil`` syntax declares the function's name and SIL type, and
967967
defines the body of the function inside braces. The declared type must
968968
be a function type, which may be generic.
969+
If there are no `sil-basic-block`s contained in the body, the function
970+
is an external declaration.
969971

970972

971973
Function Attributes
@@ -1094,30 +1096,6 @@ from the command line.
10941096
sil-function-effects ::= 'releasenone'
10951097

10961098
The specified memory effects of the function.
1097-
::
1098-
1099-
sil-function-attribute ::= '[' 'escapes' escape-list ']'
1100-
sil-function-attribute ::= '[' 'defined_escapes' escape-list ']'
1101-
escape-list ::= (escape-list ',')? escape
1102-
escape ::= '!' arg-selection // not-escaping
1103-
escape ::= arg-selection '=>' arg-selection // exclusive escaping
1104-
escape ::= arg-selection '->' arg-selection // not-exclusive escaping
1105-
arg-selection ::= arg-or-return ('.' projection-path)?
1106-
arg-or-return ::= '%' [0-9]+
1107-
arg-or-return ::= '%r'
1108-
projection-path ::= (projection-path '.')? path-component
1109-
path-component ::= 's' [0-9]+ // struct field
1110-
path-component ::= 'c' [0-9]+ // class field
1111-
path-component ::= 'ct' // class tail element
1112-
path-component ::= 'e' [0-9]+ // enum case
1113-
path-component ::= [0-9]+ // tuple element
1114-
path-component ::= 'v**' // any value fields
1115-
path-component ::= 'c*' // any class field
1116-
path-component ::= '**' // anything
1117-
1118-
The escaping effects for function arguments. For details see the documentation
1119-
in ``SwiftCompilerSources/Sources/SIL/Effects.swift``.
1120-
11211099
::
11221100

11231101
sil-function-attribute ::= '[_semantics "' [A-Za-z._0-9]+ '"]'
@@ -1147,6 +1125,34 @@ Specifies the performance constraints for the function, which defines which type
11471125
of runtime functions are allowed to be called from the function.
11481126

11491127

1128+
Argument Effects
1129+
````````````````
1130+
1131+
The effects for function arguments. For details see the documentation
1132+
in ``SwiftCompilerSources/Sources/SIL/Effects.swift``.
1133+
::
1134+
1135+
argument-effect ::= '[' argument-name defined-effect? ':' effect (',' effect)*]'
1136+
argument-name ::= '%' [0-9]+
1137+
defined-effect ::= '!' // the effect is defined in the source code and not
1138+
// derived by the optimizer
1139+
1140+
effect ::= 'noescape' projection-path?
1141+
effect ::= 'escape' projection-path? '=>' arg-or-return // exclusive escape
1142+
effect ::= 'escape' projection-path? '->' arg-or-return // not-exclusive escape
1143+
arg-or-return ::= argument-name ('.' projection-path)?
1144+
arg-or-return ::= '%r' ('.' projection-path)?
1145+
1146+
projection-path ::= path-component ('.' path-component)*
1147+
path-component ::= 's' [0-9]+ // struct field
1148+
path-component ::= 'c' [0-9]+ // class field
1149+
path-component ::= 'ct' // class tail element
1150+
path-component ::= 'e' [0-9]+ // enum case
1151+
path-component ::= [0-9]+ // tuple element
1152+
path-component ::= 'v**' // any value fields
1153+
path-component ::= 'c*' // any class field
1154+
path-component ::= '**' // anything
1155+
11501156
Basic Blocks
11511157
~~~~~~~~~~~~
11521158
::
@@ -2593,9 +2599,9 @@ only values" that are guaranteed to never be copied. This is enforced by:
25932599
* Having SILGen emit copies as it normally does.
25942600

25952601
* Use OSSA canonicalization to eliminate copies that aren't needed semantically
2596-
due to consuming uses of the value. This is implemented by the pass guaranteed
2597-
pass "MoveOnlyChecker". Emit errors on any of the consuming uses that we found
2598-
in said pass.
2602+
due to consuming uses of the value. This is implemented by the guaranteed
2603+
passes "MoveOnlyObjectChecker" and "MoveOnlyAddressChecker". We will emit
2604+
errors on any of the consuming uses that we found in said pass.
25992605

26002606
Assuming that no errors are emitted, we can then conclude before we reach
26012607
canonical SIL that the value was never copied and thus is a "move only value"
@@ -2667,7 +2673,7 @@ rather than a viral type level annotation that would constrain the type system.
26672673
As mentioned above trivial move only wrapped types are actually
26682674
non-trivial. This is because in SIL ownership is tied directly to
26692675
non-trivialness so unless we did that we could not track ownership
2670-
accurately. This is loss of triviality is not an issue for most of the pipeline
2676+
accurately. This loss of triviality is not an issue for most of the pipeline
26712677
since we eliminate all move only wrapper types for trivial types during the
26722678
guaranteed optimizations after we have run various ownership checkers but before
26732679
we have run diagnostics for trivial types (e.x.: DiagnosticConstantPropagation).

0 commit comments

Comments
 (0)