forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathValue.swift
313 lines (263 loc) · 11 KB
/
Value.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
//===--- Value.swift - the Value protocol ---------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 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 Basic
import SILBridging
@_semantics("arc.immortal")
public protocol Value : AnyObject, CustomStringConvertible {
var uses: UseList { get }
var type: Type { get }
var ownership: Ownership { get }
/// The instruction which defines the value.
///
/// This is nil if the value is not defined by an instruction, e.g. an `Argument`.
var definingInstruction: Instruction? { get }
/// The block where the value is defined.
var parentBlock: BasicBlock { get }
/// The function where the value lives in.
///
/// It's not legal to get the parentFunction of an instruction in a global initializer.
var parentFunction: Function { get }
/// True if the value has a trivial type.
var hasTrivialType: Bool { get }
/// True if the value has a trivial type which is and does not contain a Builtin.RawPointer.
var hasTrivialNonPointerType: Bool { get }
var isLexical: Bool { get }
}
public enum Ownership {
/// A Value with `unowned` ownership kind is an independent value that
/// has a lifetime that is only guaranteed to last until the next program
/// visible side-effect. To maintain the lifetime of an unowned value, it
/// must be converted to an owned representation via a copy_value.
///
/// Unowned ownership kind occurs mainly along method/function boundaries in
/// between Swift and Objective-C code.
case unowned
/// A Value with `owned` ownership kind is an independent value that has
/// an ownership independent of any other ownership imbued within it. The
/// Value must be paired with a consuming operation that ends the SSA
/// value's lifetime exactly once along all paths through the program.
case owned
/// A Value with `guaranteed` ownership kind is an independent value that
/// is guaranteed to be live over a specific region of the program. This
/// region can come in several forms:
///
/// 1. @guaranteed function argument. This guarantees that a value will
/// outlive a function.
///
/// 2. A shared borrow region. This is a region denoted by a
/// begin_borrow/load_borrow instruction and an end_borrow instruction. The
/// SSA value must not be destroyed or taken inside the borrowed region.
///
/// Any value with guaranteed ownership must be paired with an end_borrow
/// instruction exactly once along any path through the program.
case guaranteed
/// A Value with `none` ownership kind is an independent value outside of
/// the ownership system. It is used to model values that are statically
/// determined to be trivial. This includes trivially typed values as well
/// as trivial cases of non-trivial enums. Naturally `none` can be merged with
/// any ownership, allowing us to naturally model merge and branch
/// points in the SSA graph, where more information about the value is
/// statically available on some control flow paths.
case none
public var hasLifetime: Bool {
switch self {
case .owned, .guaranteed:
return true
case .unowned, .none:
return false
}
}
public init(bridged: BridgedValue.Ownership) {
switch bridged {
case .Unowned: self = .unowned
case .Owned: self = .owned
case .Guaranteed: self = .guaranteed
case .None: self = .none
default:
fatalError("unsupported ownership")
}
}
public var _bridged: BridgedValue.Ownership {
switch self {
case .unowned: return BridgedValue.Ownership.Unowned
case .owned: return BridgedValue.Ownership.Owned
case .guaranteed: return BridgedValue.Ownership.Guaranteed
case .none: return BridgedValue.Ownership.None
}
}
}
extension Value {
public var description: String {
return String(taking: bridged.getDebugDescription())
}
public var uses: UseList { UseList(bridged.getFirstUse()) }
// Default implementation for all values which have a parent block, like instructions and arguments.
public var parentFunction: Function { parentBlock.parentFunction }
public var type: Type { bridged.getType().type }
/// True if the value has a trivial type.
public var hasTrivialType: Bool { type.isTrivial(in: parentFunction) }
/// True if the value has a trivial type which is and does not contain a Builtin.RawPointer.
public var hasTrivialNonPointerType: Bool { type.isTrivialNonPointer(in: parentFunction) }
public var ownership: Ownership {
switch bridged.getOwnership() {
case .Unowned: return .unowned
case .Owned: return .owned
case .Guaranteed: return .guaranteed
case .None: return .none
default:
fatalError("unsupported ownership")
}
}
public var definingInstructionOrTerminator: Instruction? {
if let def = definingInstruction {
return def
} else if let result = TerminatorResult(self) {
return result.terminator
}
return nil
}
public var nextInstruction: Instruction {
if self is Argument {
return parentBlock.instructions.first!
}
// Block terminators do not directly produce values.
return definingInstruction!.next!
}
public var hashable: HashableValue { ObjectIdentifier(self) }
public var bridged: BridgedValue {
BridgedValue(obj: SwiftObject(self as AnyObject))
}
}
public typealias HashableValue = ObjectIdentifier
// We can't make `Value` inherit from `Equatable`, since `Equatable` is a PAT,
// and we do use `Value` existentials around the codebase. Thus functions from
// `Equatable` are declared separately.
public func ==(_ lhs: Value, _ rhs: Value) -> Bool {
return lhs === rhs
}
public func !=(_ lhs: Value, _ rhs: Value) -> Bool {
return !(lhs === rhs)
}
extension CollectionLikeSequence where Element == Value {
public func contains(_ element: Element) -> Bool {
return self.contains { $0 == element }
}
}
/// A projected value, which is defined by the original value and a projection path.
///
/// For example, if the `value` is of type `struct S { var x: Int }` and `path` is `s0`,
/// then the projected value represents field `x` of the original value.
/// An empty path means represents the "whole" original value.
///
public struct ProjectedValue {
public let value: Value
public let path: SmallProjectionPath
}
extension Value {
/// Returns a projected value, defined by this value and `path`.
public func at(_ path: SmallProjectionPath) -> ProjectedValue {
ProjectedValue(value: self, path: path)
}
/// Returns a projected value, defined by this value and path containing a single field of `kind` and `index`.
public func at(_ kind: SmallProjectionPath.FieldKind, index: Int = 0) -> ProjectedValue {
ProjectedValue(value: self, path: SmallProjectionPath(kind, index: index))
}
/// Projects all "contained" addresses of this value.
///
/// If this value is an address, projects all sub-fields of the address, e.g. struct fields.
///
/// If this value is not an address, projects all "interior" pointers of the value:
/// If this value is a class, "interior" pointer means: an address of any stored property of the class instance.
/// If this value is a struct or another value type, "interior" pointers refer to any stored propery addresses of
/// any class references in the struct or value type. For example:
///
/// class C { var x: Int; var y: Int }
/// struct S { var c1: C; var c2: C }
/// let s: S
///
/// `s.allContainedAddresss` refers to `s.c1.x`, `s.c1.y`, `s.c2.x` and `s.c2.y`
///
public var allContainedAddresss: ProjectedValue {
if type.isAddress {
// This is the regular case: the path selects any sub-fields of an address.
return at(SmallProjectionPath(.anyValueFields))
}
if type.isClass {
// If the value is a (non-address) reference it means: all addresses within the class instance.
return at(SmallProjectionPath(.anyValueFields).push(.anyClassField))
}
// Any other non-address value means: all addresses of any referenced class instances within the value.
return at(SmallProjectionPath(.anyValueFields).push(.anyClassField).push(.anyValueFields))
}
}
extension BridgedValue {
public var value: Value {
// Doing the type check in C++ is much faster than a conformance lookup with `as! Value`.
// And it makes a difference because this is a time critical function.
switch getKind() {
case .SingleValueInstruction:
return obj.getAs(SingleValueInstruction.self)
case .Argument:
return obj.getAs(Argument.self)
case .MultipleValueInstructionResult:
return obj.getAs(MultipleValueInstructionResult.self)
case .Undef:
return obj.getAs(Undef.self)
default:
fatalError("unknown Value type")
}
}
}
public final class Undef : Value {
public var definingInstruction: Instruction? { nil }
public var parentFunction: Function { bridged.SILUndef_getParentFunction().function }
public var parentBlock: BasicBlock {
// By convention, undefs are considered to be defined at the entry of the function.
parentFunction.entryBlock
}
/// Undef has not parent function, therefore the default `hasTrivialType` does not work.
/// Return the conservative default in this case.
public var hasTrivialType: Bool { false }
/// Undef has not parent function, therefore the default `hasTrivialNonPointerType` does not work.
/// Return the conservative default in this case.
public var hasTrivialNonPointerType: Bool { false }
public var isLexical: Bool { false }
}
final class PlaceholderValue : Value {
public var definingInstruction: Instruction? { nil }
public var parentBlock: BasicBlock {
fatalError("PlaceholderValue has no defining block")
}
public var isLexical: Bool { false }
public var parentFunction: Function { bridged.PlaceholderValue_getParentFunction().function }
}
extension OptionalBridgedValue {
public var value: Value? { obj.getAs(AnyObject.self) as? Value }
}
extension Optional where Wrapped == Value {
public var bridged: OptionalBridgedValue {
OptionalBridgedValue(obj: self?.bridged.obj)
}
}
//===----------------------------------------------------------------------===//
// Bridging Utilities
//===----------------------------------------------------------------------===//
extension Array where Element == Value {
public func withBridgedValues<T>(_ c: (BridgedValueArray) -> T) -> T {
return self.withUnsafeBufferPointer { bufPtr in
assert(bufPtr.count == self.count)
return bufPtr.withMemoryRebound(to: BridgeValueExistential.self) { valPtr in
return c(BridgedValueArray(base: valPtr.baseAddress, count: self.count))
}
}
}
}