Skip to content

Commit bce9817

Browse files
committed
SwiftCompilerSources: add ForwardingInstruction
1 parent 139c573 commit bce9817

File tree

9 files changed

+395
-32
lines changed

9 files changed

+395
-32
lines changed

SwiftCompilerSources/Sources/SIL/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_swift_compiler_module(SIL
1515
BasicBlock.swift
1616
Builder.swift
1717
Effects.swift
18+
ForwardingInstruction.swift
1819
Function.swift
1920
GlobalVariable.swift
2021
Instruction.swift
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
//===--- ForwardingInstruction.swift - forwarding instruction protocols ---===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import SILBridging
14+
15+
/// An instruction that forwards ownership from operands to results.
16+
public protocol ForwardingInstruction : Instruction {
17+
var singleForwardedOperand: Operand? { get }
18+
19+
/// Return true if the forwarded value has the same representation. If true, then the result can be mapped to the same storage without a move or copy.
20+
var preservesRepresentation: Bool { get }
21+
}
22+
23+
extension ForwardingInstruction {
24+
public var forwardedOperands: OperandArray {
25+
// Some instructions have multiple real operands but only forward one.
26+
if let singleForwardingOp = singleForwardedOperand {
27+
return OperandArray(base: singleForwardingOp, count: 1)
28+
}
29+
// All others forward all operands (for enum, this may be zero operands).
30+
return operands
31+
}
32+
33+
public var forwardedResults: ForwardedResults {
34+
ForwardedResults(inst: self)
35+
}
36+
37+
/// If forwarding ownership is owned, then the instruction moves an owned operand to its result, ending its lifetime. If forwarding ownership is guaranteed, then the instruction propagates the lifetime of its borrows operand through its result.
38+
///
39+
/// The resulting forwarded value's ownership (Value.ownership) is not identical to the instruction's forwarding ownership property. It differs when the result is trivial type. e.g. an owned or guaranteed value can be cast to a trivial type using owned or guaranteed forwarding.
40+
public var forwardingOwnership: Ownership {
41+
Ownership(bridged: bridged.ForwardingInst_forwardingOwnership())
42+
}
43+
44+
/// A forwarding instruction preserves reference counts if it has a dynamically non-trivial result in which all references are forwarded from the operand.
45+
///
46+
/// A cast can only forward guaranteed values if it preserves reference counts. Such casts cannot release any references within their operand's value and cannot retain any references owned by their result.
47+
public var preservesReferenceCounts: Bool {
48+
bridged.ForwardingInst_preservesOwnership()
49+
}
50+
}
51+
52+
// An instruction that forwards a single value to a single result.
53+
//
54+
// For legacy reasons, some ForwardingInstructions that fit the SingleValueInstruction and UnaryInstruction requirements are not considered ConversionInstructions because certain routines do not want to see through them (InitExistentialValueInst, InitExistentialValueInst, OpenExistentialValueInst, OpenExistentialValueInst). This most likely has to do with type-dependent operands, although any ConversionInstruction should support type-dependent operands.
55+
public protocol ConversionInstruction : SingleValueInstruction,
56+
UnaryInstruction,
57+
ForwardingInstruction
58+
{}
59+
60+
extension Value {
61+
// If this value is produced by a ForwardingInstruction, return that instruction. This is convenient for following the forwarded value chain.
62+
// Unlike definingInstruction, a value's forwardingInstruction is not necessarily a valid insertion point.
63+
public var forwardingInstruction: ForwardingInstruction? {
64+
if let inst = definingInstruction {
65+
return inst as? ForwardingInstruction
66+
}
67+
if let termResult = TerminatorResult(self) {
68+
return termResult.terminator as? ForwardingInstruction
69+
}
70+
return nil
71+
}
72+
}
73+
74+
//===----------------------------------------------------------------------===//
75+
// singleForwardedOperand
76+
//===----------------------------------------------------------------------===//
77+
78+
extension ForwardingInstruction {
79+
// See ForwardingOperation::getSingleForwardingOperand().
80+
public var singleForwardedOperand: Operand? {
81+
let definedOps = self.definedOperands
82+
assert(definedOps.count == 1);
83+
return definedOps[0];
84+
}
85+
}
86+
87+
extension ConversionInstruction {
88+
public var singleForwardedOperand: Operand? { operand }
89+
}
90+
91+
extension EnumInst {
92+
public var singleForwardedOperand: Operand? {
93+
return operand // nil for an enum with no payload
94+
}
95+
}
96+
97+
// -----------------------------------------------------------------------------
98+
// Instructions with multiple forwarded operands have nil singleForwardedOperand.
99+
100+
extension StructInst {
101+
public var singleForwardedOperand: Operand? { nil }
102+
}
103+
104+
extension TupleInst {
105+
public var singleForwardedOperand: Operand? { nil }
106+
}
107+
108+
extension LinearFunctionInst {
109+
public var singleForwardedOperand: Operand? { nil }
110+
}
111+
112+
extension DifferentiableFunctionInst {
113+
public var singleForwardedOperand: Operand? { nil }
114+
}
115+
116+
// -----------------------------------------------------------------------------
117+
// Instructions with a singleForwardedOperand and additional operands.
118+
119+
extension MarkDependenceInst {
120+
public var singleForwardedOperand: Operand {
121+
return valueOperand
122+
}
123+
}
124+
125+
extension RefToBridgeObjectInst {
126+
public var singleForwardedOperand: Operand {
127+
return convertedOperand
128+
}
129+
}
130+
131+
extension TuplePackExtractInst {
132+
public var singleForwardedOperand: Operand {
133+
return tupleOperand
134+
}
135+
}
136+
137+
extension SelectEnumInst {
138+
public var singleForwardedOperand: Operand {
139+
return enumOperand
140+
}
141+
}
142+
143+
//===----------------------------------------------------------------------===//
144+
// forwardedResults
145+
//===----------------------------------------------------------------------===//
146+
147+
public struct ForwardedResults : Collection {
148+
private let inst: Instruction
149+
private let maxResults: Int
150+
151+
fileprivate init(inst: ForwardingInstruction) {
152+
self.inst = inst
153+
if let ti = inst as? TermInst {
154+
self.maxResults = ti.successors.count
155+
} else {
156+
self.maxResults = inst.results.count
157+
}
158+
}
159+
160+
public var startIndex: Int { skipEmptyResults(at: 0) }
161+
162+
public var endIndex: Int { maxResults }
163+
164+
public func index(after index: Int) -> Int {
165+
return skipEmptyResults(at: index + 1)
166+
}
167+
168+
public subscript(_ index: Int) -> Value {
169+
if let ti = inst as? TermInst {
170+
return getTerminatorResult(termInst: ti, index: index)!
171+
}
172+
return inst.results[index]
173+
}
174+
175+
private func skipEmptyResults(at index: Int) -> Int {
176+
guard let ti = inst as? TermInst else { return index }
177+
var next = index
178+
while next != endIndex {
179+
if getTerminatorResult(termInst: ti, index: next) != nil { break }
180+
next += 1
181+
}
182+
return next
183+
}
184+
185+
// Forwarding terminators have a zero or one result per successor.
186+
private func getTerminatorResult(termInst: TermInst,
187+
index: Int) -> Argument? {
188+
let succ = termInst.successors[index]
189+
guard succ.arguments.count == 1 else {
190+
// The default enum payload may be empty.
191+
assert(succ.arguments.count == 0, "terminator must forward a single value")
192+
return nil
193+
}
194+
return succ.arguments[0]
195+
}
196+
}
197+
198+
//===----------------------------------------------------------------------===//
199+
// preservesRepresentation
200+
//===----------------------------------------------------------------------===//
201+
202+
extension ForwardingInstruction {
203+
// Conservatively assume that a conversion changes representation.
204+
// Operations can be added as needed to participate in SIL opaque values.
205+
// See ForwardingOperation::hasSameRepresentation().
206+
public var preservesRepresentation: Bool { false }
207+
}
208+
209+
extension ConvertFunctionInst {
210+
public var preservesRepresentation: Bool { true }
211+
}
212+
213+
extension DestructureTupleInst {
214+
public var preservesRepresentation: Bool { true }
215+
}
216+
217+
extension DestructureStructInst {
218+
public var preservesRepresentation: Bool { true }
219+
}
220+
221+
extension InitExistentialRefInst {
222+
public var preservesRepresentation: Bool { true }
223+
}
224+
225+
extension ObjectInst {
226+
public var preservesRepresentation: Bool { true }
227+
}
228+
229+
extension OpenExistentialBoxValueInst {
230+
public var preservesRepresentation: Bool { true }
231+
}
232+
233+
extension OpenExistentialRefInst {
234+
public var preservesRepresentation: Bool { true }
235+
}
236+
237+
extension OpenExistentialValueInst {
238+
public var preservesRepresentation: Bool { true }
239+
}
240+
241+
extension MarkUnresolvedNonCopyableValueInst {
242+
public var preservesRepresentation: Bool { true }
243+
}
244+
245+
extension MarkUninitializedInst {
246+
public var preservesRepresentation: Bool { true }
247+
}
248+
249+
extension SelectEnumInst {
250+
public var preservesRepresentation: Bool { true }
251+
}
252+
253+
extension StructExtractInst {
254+
public var preservesRepresentation: Bool { true }
255+
}
256+
257+
extension TupleExtractInst {
258+
public var preservesRepresentation: Bool { true }
259+
}
260+
261+
extension TuplePackExtractInst {
262+
public var preservesRepresentation: Bool { true }
263+
}

0 commit comments

Comments
 (0)