forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFunctionConvention.swift
404 lines (344 loc) · 13.4 KB
/
FunctionConvention.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
//===--- FunctionConvention.swift - function conventions ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
import AST
import SILBridging
/// SIL function parameter and result conventions based on the AST
/// function type and SIL stage.
///
/// Provides Results and Parameters collections. This does not know
/// anything about FunctionArguments. Use ArgumentConventions instead to
/// maps FunctionArguments down to these conventions.
///
/// The underlying FunctionType must be contextual and expanded. SIL
/// has no use for interface types or unexpanded types.
public struct FunctionConvention : CustomStringConvertible {
let functionType: CanonicalType
let hasLoweredAddresses: Bool
init(for functionType: CanonicalType, in function: Function) {
assert(!functionType.hasTypeParameter, "requires contextual type")
self.functionType = functionType
self.hasLoweredAddresses = function.hasLoweredAddresses
}
/// All results including the error.
public var results: Results {
Results(bridged: SILFunctionType_getResultsWithError(functionType.bridged),
hasLoweredAddresses: hasLoweredAddresses)
}
public var errorResult: ResultInfo? {
return ResultInfo(
bridged: SILFunctionType_getErrorResult(functionType.bridged),
hasLoweredAddresses: hasLoweredAddresses)
}
/// Number of indirect results including the error.
/// This avoids quadratic lazy iteration on indirectResults.count.
public var indirectSILResultCount: Int {
// TODO: Return packs directly in lowered-address mode
return hasLoweredAddresses
? SILFunctionType_getNumIndirectFormalResultsWithError(functionType.bridged)
: SILFunctionType_getNumPackResults(functionType.bridged)
}
/// Indirect results including the error.
public var indirectSILResults: LazyFilterSequence<Results> {
hasLoweredAddresses
? results.lazy.filter { $0.isSILIndirect }
: results.lazy.filter { $0.convention == .pack }
}
public var parameters: Parameters {
Parameters(bridged: SILFunctionType_getParameters(functionType.bridged),
hasLoweredAddresses: hasLoweredAddresses)
}
public var hasSelfParameter: Bool {
SILFunctionType_hasSelfParam(functionType.bridged)
}
public var yields: Yields {
Yields(bridged: SILFunctionType_getYields(functionType.bridged),
hasLoweredAddresses: hasLoweredAddresses)
}
/// If the function result depends on any parameters, return a Collection of LifetimeDependenceConventions for the
/// dependence source parameters.
public var resultDependencies: LifetimeDependencies? {
lifetimeDependencies(for: parameters.count)
}
/// If the parameter indexed by 'targetParameterIndex' is the target of any dependencies on other parameters, return a
/// Collection of LifetimeDependenceConventions for the dependence source parameters.
public func parameterDependencies(for targetParameterIndex: Int) -> LifetimeDependencies? {
lifetimeDependencies(for: targetParameterIndex)
}
public func hasLifetimeDependencies() -> Bool {
return SILFunctionType_getLifetimeDependencies(functionType.bridged).count() != 0
}
public var description: String {
var str = functionType.description
for paramIdx in 0..<parameters.count {
str += "\nparameter: " + parameters[paramIdx].description
if let deps = parameterDependencies(for: paramIdx) {
str += "\n lifetime: \(deps)"
}
}
results.forEach { str += "\n result: " + $0.description }
if let deps = resultDependencies {
str += "\n lifetime: \(deps)"
}
return str
}
}
/// A function result type and the rules for returning it in SIL.
public struct ResultInfo : CustomStringConvertible {
/// The unsubstituted parameter type that describes the abstract
/// calling convention of the parameter.
///
/// TODO: For most purposes, you probably want \c returnValueType.
public let type: BridgedASTType
public let convention: ResultConvention
public let hasLoweredAddresses: Bool
/// Is this result returned indirectly in SIL? Most formally
/// indirect results can be returned directly in SIL. This depends
/// on whether the calling function has lowered addresses.
public var isSILIndirect: Bool {
switch convention {
case .indirect:
return hasLoweredAddresses || type.isOpenedExistentialWithError()
case .pack:
return true
case .owned, .unowned, .unownedInnerPointer, .autoreleased:
return false
}
}
public var description: String {
convention.description + ": "
+ String(taking: type.getDebugDescription())
}
}
extension FunctionConvention {
public struct Results : Collection {
let bridged: BridgedResultInfoArray
let hasLoweredAddresses: Bool
public var startIndex: Int { 0 }
public var endIndex: Int { bridged.count() }
public func index(after index: Int) -> Int {
return index + 1
}
public subscript(_ index: Int) -> ResultInfo {
return ResultInfo(bridged: bridged.at(index),
hasLoweredAddresses: hasLoweredAddresses)
}
}
}
public struct ParameterInfo : CustomStringConvertible {
/// The parameter type that describes the abstract calling
/// convention of the parameter.
public let type: CanonicalType
public let convention: ArgumentConvention
public let options: UInt8
public let hasLoweredAddresses: Bool
public init(type: CanonicalType, convention: ArgumentConvention, options: UInt8, hasLoweredAddresses: Bool) {
self.type = type
self.convention = convention
self.options = options
self.hasLoweredAddresses = hasLoweredAddresses
}
/// Is this parameter passed indirectly in SIL? Most formally
/// indirect results can be passed directly in SIL (opaque values
/// mode). This depends on whether the calling function has lowered
/// addresses.
public var isSILIndirect: Bool {
switch convention {
case .indirectIn, .indirectInGuaranteed:
return hasLoweredAddresses || type.isOpenedExistentialWithError
case .indirectInout, .indirectInoutAliasable, .indirectInCXX:
return true
case .directOwned, .directUnowned, .directGuaranteed:
return false
case .packInout, .packOwned, .packGuaranteed:
return true
case .indirectOut, .packOut:
fatalError("invalid parameter convention")
}
}
public var description: String {
"\(convention): \(type)"
}
}
extension FunctionConvention {
public struct Parameters : Collection {
let bridged: BridgedParameterInfoArray
let hasLoweredAddresses: Bool
public var startIndex: Int { 0 }
public var endIndex: Int { bridged.count() }
public func index(after index: Int) -> Int {
return index + 1
}
public subscript(_ index: Int) -> ParameterInfo {
return ParameterInfo(bridged: bridged.at(index),
hasLoweredAddresses: hasLoweredAddresses)
}
}
}
extension FunctionConvention {
public struct Yields : Collection {
let bridged: BridgedYieldInfoArray
let hasLoweredAddresses: Bool
public var startIndex: Int { 0 }
public var endIndex: Int { bridged.count() }
public func index(after index: Int) -> Int {
return index + 1
}
public subscript(_ index: Int) -> ParameterInfo {
return ParameterInfo(bridged: bridged.at(index),
hasLoweredAddresses: hasLoweredAddresses)
}
}
}
public enum LifetimeDependenceConvention : CustomStringConvertible {
case inherit
case scope
public var description: String {
switch self {
case .inherit:
return "inherit"
case .scope:
return "scope"
}
}
}
extension FunctionConvention {
// 'targetIndex' is either the parameter index or parameters.count for the function result.
private func lifetimeDependencies(for targetIndex: Int) -> LifetimeDependencies? {
let bridgedDependenceInfoArray = SILFunctionType_getLifetimeDependencies(functionType.bridged)
for infoIndex in 0..<bridgedDependenceInfoArray.count() {
let bridgedDependenceInfo = bridgedDependenceInfoArray.at(infoIndex)
if bridgedDependenceInfo.targetIndex == targetIndex {
return LifetimeDependencies(bridged: bridgedDependenceInfo,
parameterCount: parameters.count,
hasSelfParameter: hasSelfParameter)
}
}
return nil
}
/// Collection of LifetimeDependenceConvention? that parallels parameters.
public struct LifetimeDependencies : Collection, CustomStringConvertible {
let bridged: BridgedLifetimeDependenceInfo
let paramCount: Int
let hasSelfParam: Bool
init(bridged: BridgedLifetimeDependenceInfo, parameterCount: Int,
hasSelfParameter: Bool) {
assert(!bridged.empty())
self.bridged = bridged
self.paramCount = parameterCount
self.hasSelfParam = hasSelfParameter
}
public var startIndex: Int { 0 }
public var endIndex: Int { paramCount }
public func index(after index: Int) -> Int {
return index + 1
}
public subscript(_ index: Int) -> LifetimeDependenceConvention? {
let inherit = bridged.checkInherit(bridgedIndex(parameterIndex: index))
let scope = bridged.checkScope(bridgedIndex(parameterIndex: index))
if inherit {
assert(!scope, "mutualy exclusive lifetime specifiers")
return .inherit
}
if scope {
return .scope
}
return nil
}
private func bridgedIndex(parameterIndex: Int) -> Int {
return parameterIndex
}
public var description: String {
String(taking: bridged.getDebugDescription()) +
"\nparamCount: \(paramCount) self: \(hasSelfParam)"
}
}
}
public enum ResultConvention : CustomStringConvertible {
/// This result is returned indirectly, i.e. by passing the address of an uninitialized object in memory. The callee is responsible for leaving an initialized object at this address. The callee may assume that the address does not alias any valid object.
case indirect
/// The caller is responsible for destroying this return value. Its type is non-trivial.
case owned
/// 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.
case unowned
/// The caller is not responsible for destroying this return value. The validity of the return value is dependent on the 'self' parameter, so it may be invalidated if that parameter is released.
case unownedInnerPointer
/// This value has been (or may have been) returned autoreleased. The caller should make an effort to reclaim the autorelease. The type must be a class or class existential type, and this must be the only return value.
case autoreleased
/// This value is a pack that is returned indirectly by passing a pack address (which may or may not be further indirected, depending on the pact type). The callee is responsible for leaving an initialized object in each element of the pack.
case pack
/// Does this result convention require indirect storage? This reflects a FunctionType's conventions, as opposed to the SIL conventions that dictate SILValue types.
public var isASTIndirect: Bool {
switch self {
case .indirect, .pack:
return true
default:
return false
}
}
public var isASTDirect: Bool {
return !isASTIndirect
}
public var description: String {
switch self {
case .indirect:
return "indirect"
case .owned:
return "owned"
case .unowned:
return "unowned"
case .unownedInnerPointer:
return "unownedInnerPointer"
case .autoreleased:
return "autoreleased"
case .pack:
return "pack"
}
}
}
// Bridging utilities
extension ResultInfo {
init(bridged: BridgedResultInfo, hasLoweredAddresses: Bool) {
self.type = BridgedASTType(type: bridged.type)
self.convention = ResultConvention(bridged: bridged.convention)
self.hasLoweredAddresses = hasLoweredAddresses
}
init(bridged: OptionalBridgedResultInfo, hasLoweredAddresses: Bool) {
self.type = BridgedASTType(type: bridged.type!)
self.convention = ResultConvention(bridged: bridged.convention)
self.hasLoweredAddresses = hasLoweredAddresses
}
}
extension ResultConvention {
init(bridged: BridgedResultConvention) {
switch bridged {
case .Indirect: self = .indirect
case .Owned: self = .owned
case .Unowned: self = .unowned
case .UnownedInnerPointer: self = .unownedInnerPointer
case .Autoreleased: self = .autoreleased
case .Pack: self = .pack
default:
fatalError("unsupported result convention")
}
}
}
extension ParameterInfo {
init(bridged: BridgedParameterInfo, hasLoweredAddresses: Bool) {
self.type = CanonicalType(bridged: bridged.type)
self.convention = bridged.convention.convention
self.options = bridged.options
self.hasLoweredAddresses = hasLoweredAddresses
}
public var _bridged: BridgedParameterInfo {
BridgedParameterInfo(type.bridged, convention.bridged, options)
}
}