Skip to content

Commit 4aeac54

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

File tree

9 files changed

+293
-32
lines changed

9 files changed

+293
-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: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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+
18+
extension ForwardingInstruction {
19+
public var singleForwardedOperand: Operand? {
20+
switch self {
21+
case is StructInst, is TupleInst, is LinearFunctionInst,
22+
is DifferentiableFunctionInst:
23+
return nil
24+
case let mdi as MarkDependenceInst:
25+
return mdi.valueOperand
26+
case let rtboi as RefToBridgeObjectInst:
27+
return rtboi.convertedOperand
28+
case let tpei as TuplePackExtractInst:
29+
return tpei.tupleOperand
30+
case let sei as SelectEnumInst:
31+
return sei.enumOperand
32+
default:
33+
let realOperands = self.realOperands
34+
if realOperands.isEmpty {
35+
// This can happen with enum instructions that have no payload.
36+
return nil
37+
}
38+
assert(realOperands.count == 1);
39+
return realOperands[0];
40+
}
41+
}
42+
43+
public var forwardedOperands: OperandArray {
44+
// Some instructions have multiple real operands but only forward one.
45+
if let singleForwardingOp = singleForwardedOperand {
46+
return OperandArray(base: singleForwardingOp, count: 1)
47+
}
48+
// All others forward all operands (for enum, this may be zero operands).
49+
return operands
50+
}
51+
52+
/// 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.
53+
///
54+
/// 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.
55+
public var forwardingOwnership: Ownership {
56+
Ownership(bridged: bridged.ForwardingInst_forwardingOwnership())
57+
}
58+
59+
/// A forwarding instruction preserves reference counts if it has a dynamically non-trivial result in which all references are forwarded from the operand.
60+
///
61+
/// 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.
62+
public var preservesReferenceCounts: Bool {
63+
bridged.ForwardingInst_preservesReferenceCounts()
64+
}
65+
66+
/// 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.
67+
public var preservesRepresentation: Bool {
68+
bridged.ForwardingInst_preservesRepresentation()
69+
}
70+
71+
/// Return true if the forwarded value is address-only either before or after forwarding.
72+
public var isAddressOnly: Bool { bridged.ForwardingInst_isAddressOnly() }
73+
}
74+
75+
extension Value {
76+
public var forwardingInstruction: ForwardingInstruction? {
77+
if let inst = definingInstruction {
78+
return inst as? ForwardingInstruction
79+
}
80+
if let termResult = TerminatorResult(self) {
81+
return termResult.terminator as? ForwardingInstruction
82+
}
83+
return nil
84+
}
85+
}
86+
87+
// An instruction that forwards a single value to a single result.
88+
//
89+
// 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.
90+
public protocol ConversionInstruction : SingleValueInstruction,
91+
UnaryInstruction,
92+
ForwardingInstruction
93+
{}
94+
95+
extension ConversionInstruction {
96+
public var singleForwardedOperand: Operand { operand }
97+
}
98+
99+
// Visit all forwarded results. Return true if all visitors return true.
100+
extension ForwardingInstruction {
101+
public var forwardedResults: ForwardedResults {
102+
ForwardedResults(inst: self)
103+
}
104+
}
105+
106+
public struct ForwardedResults : Collection {
107+
private let inst: Instruction
108+
private let maxResults: Int
109+
110+
fileprivate init(inst: ForwardingInstruction) {
111+
self.inst = inst
112+
if let ti = inst as? TermInst {
113+
self.maxResults = ti.successors.count
114+
} else {
115+
self.maxResults = inst.results.count
116+
}
117+
}
118+
119+
public var startIndex: Int { skipEmptyResults(at: 0) }
120+
121+
public var endIndex: Int { maxResults }
122+
123+
public func index(after index: Int) -> Int {
124+
return skipEmptyResults(at: index + 1)
125+
}
126+
127+
public subscript(_ index: Int) -> Value {
128+
if let ti = inst as? TermInst {
129+
return getTerminatorResult(termInst: ti, index: index)!
130+
}
131+
return inst.results[index]
132+
}
133+
134+
private func skipEmptyResults(at index: Int) -> Int {
135+
guard let ti = inst as? TermInst else { return index }
136+
var next = index
137+
while next != endIndex {
138+
if getTerminatorResult(termInst: ti, index: next) != nil { break }
139+
next += 1
140+
}
141+
return next
142+
}
143+
144+
// Forwarding terminators have a zero or one result per successor.
145+
private func getTerminatorResult(termInst: TermInst,
146+
index: Int) -> Argument? {
147+
let succ = termInst.successors[index]
148+
guard succ.arguments.count == 1 else {
149+
// The default enum payload may be empty.
150+
assert(succ.arguments.count == 0, "terminator must forward a single value")
151+
return nil
152+
}
153+
return succ.arguments[0]
154+
}
155+
}

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ public class Instruction : CustomStringConvertible, Hashable {
4747
return OperandArray(base: operands.base, count: operands.count)
4848
}
4949

50+
final public var realOperands: OperandArray {
51+
let operands = bridged.getRealOperands()
52+
return OperandArray(base: operands.base, count: operands.count)
53+
}
54+
5055
fileprivate var resultCount: Int { 0 }
5156
fileprivate func getResult(index: Int) -> Value { fatalError() }
5257

@@ -296,7 +301,7 @@ final public class EndAccessInst : Instruction, UnaryInstruction {
296301

297302
final public class EndBorrowInst : Instruction, UnaryInstruction {}
298303

299-
final public class MarkUninitializedInst : SingleValueInstruction, UnaryInstruction {
304+
final public class MarkUninitializedInst : SingleValueInstruction, ConversionInstruction {
300305

301306
/// This enum captures what the mark_uninitialized instruction is designating.
302307
///
@@ -485,12 +490,12 @@ final public class BuiltinInst : SingleValueInstruction {
485490
}
486491
}
487492

488-
final public class UpcastInst : SingleValueInstruction, UnaryInstruction {
493+
final public class UpcastInst : SingleValueInstruction, ConversionInstruction {
489494
public var fromInstance: Value { operand.value }
490495
}
491496

492497
final public
493-
class UncheckedRefCastInst : SingleValueInstruction, UnaryInstruction {
498+
class UncheckedRefCastInst : SingleValueInstruction, ConversionInstruction {
494499
public var fromInstance: Value { operand.value }
495500
}
496501

@@ -543,10 +548,10 @@ class OpenExistentialRefInst : SingleValueInstruction, UnaryInstruction {
543548
}
544549

545550
final public
546-
class InitExistentialValueInst : SingleValueInstruction, UnaryInstruction {}
551+
class InitExistentialValueInst : SingleValueInstruction, UnaryInstruction, ForwardingInstruction {}
547552

548553
final public
549-
class OpenExistentialValueInst : SingleValueInstruction, UnaryInstruction {}
554+
class OpenExistentialValueInst : SingleValueInstruction, UnaryInstruction, ForwardingInstruction {}
550555

551556
final public
552557
class InitExistentialAddrInst : SingleValueInstruction, UnaryInstruction {}
@@ -641,10 +646,10 @@ final public class StringLiteralInst : SingleValueInstruction {
641646
}
642647
}
643648

644-
final public class TupleInst : SingleValueInstruction {
649+
final public class TupleInst : SingleValueInstruction, ForwardingInstruction {
645650
}
646651

647-
final public class TupleExtractInst : SingleValueInstruction, UnaryInstruction {
652+
final public class TupleExtractInst : SingleValueInstruction, UnaryInstruction, ForwardingInstruction {
648653
public var `tuple`: Value { operand.value }
649654
public var fieldIndex: Int { bridged.TupleExtractInst_fieldIndex() }
650655
}
@@ -655,10 +660,10 @@ class TupleElementAddrInst : SingleValueInstruction, UnaryInstruction {
655660
public var fieldIndex: Int { bridged.TupleElementAddrInst_fieldIndex() }
656661
}
657662

658-
final public class StructInst : SingleValueInstruction {
663+
final public class StructInst : SingleValueInstruction, ForwardingInstruction {
659664
}
660665

661-
final public class StructExtractInst : SingleValueInstruction, UnaryInstruction {
666+
final public class StructExtractInst : SingleValueInstruction, UnaryInstruction, ForwardingInstruction {
662667
public var `struct`: Value { operand.value }
663668
public var fieldIndex: Int { bridged.StructExtractInst_fieldIndex() }
664669
}
@@ -673,14 +678,14 @@ public protocol EnumInstruction : AnyObject {
673678
var caseIndex: Int { get }
674679
}
675680

676-
final public class EnumInst : SingleValueInstruction, EnumInstruction {
681+
final public class EnumInst : SingleValueInstruction, EnumInstruction, ForwardingInstruction {
677682
public var caseIndex: Int { bridged.EnumInst_caseIndex() }
678683

679684
public var operand: Operand? { operands.first }
680685
public var payload: Value? { operand?.value }
681686
}
682687

683-
final public class UncheckedEnumDataInst : SingleValueInstruction, UnaryInstruction, EnumInstruction {
688+
final public class UncheckedEnumDataInst : SingleValueInstruction, UnaryInstruction, EnumInstruction, ForwardingInstruction {
684689
public var `enum`: Value { operand.value }
685690
public var caseIndex: Int { bridged.UncheckedEnumDataInst_caseIndex() }
686691
}
@@ -695,6 +700,10 @@ final public class UncheckedTakeEnumDataAddrInst : SingleValueInstruction, Unary
695700
public var caseIndex: Int { bridged.UncheckedTakeEnumDataAddrInst_caseIndex() }
696701
}
697702

703+
final public class SelectEnumInst : SingleValueInstruction {
704+
public var enumOperand: Operand { operands[0] }
705+
}
706+
698707
final public class RefElementAddrInst : SingleValueInstruction, UnaryInstruction {
699708
public var instance: Value { operand.value }
700709
public var fieldIndex: Int { bridged.RefElementAddrInst_fieldIndex() }
@@ -727,24 +736,24 @@ final public class KeyPathInst : SingleValueInstruction {
727736
}
728737

729738
final public
730-
class UnconditionalCheckedCastInst : SingleValueInstruction, UnaryInstruction {
739+
class UnconditionalCheckedCastInst : SingleValueInstruction, ConversionInstruction {
731740
public override var mayTrap: Bool { true }
732741
}
733742

734743
final public
735-
class ConvertFunctionInst : SingleValueInstruction, UnaryInstruction {
744+
class ConvertFunctionInst : SingleValueInstruction, ConversionInstruction {
736745
public var fromFunction: Value { operand.value }
737746
}
738747

739748
final public
740-
class ThinToThickFunctionInst : SingleValueInstruction, UnaryInstruction {}
749+
class ThinToThickFunctionInst : SingleValueInstruction, ConversionInstruction {}
741750

742751
final public
743752
class ObjCExistentialMetatypeToObjectInst : SingleValueInstruction,
744-
UnaryInstruction {}
753+
ConversionInstruction {}
745754

746755
final public
747-
class ObjCMetatypeToObjectInst : SingleValueInstruction, UnaryInstruction {}
756+
class ObjCMetatypeToObjectInst : SingleValueInstruction, ConversionInstruction {}
748757

749758
final public
750759
class ValueToBridgeObjectInst : SingleValueInstruction, UnaryInstruction {
@@ -759,19 +768,23 @@ class GetAsyncContinuationAddrInst : SingleValueInstruction, UnaryInstruction {}
759768

760769

761770
final public
762-
class MarkDependenceInst : SingleValueInstruction {
763-
public var value: Value { return operands[0].value }
764-
public var base: Value { return operands[1].value }
771+
class MarkDependenceInst : SingleValueInstruction, ForwardingInstruction {
772+
public var valueOperand: Operand { operands[0] }
773+
public var baseOperand: Operand { operands[1] }
774+
public var value: Value { return valueOperand.value }
775+
public var base: Value { return baseOperand.value }
765776
}
766777

767-
final public class RefToBridgeObjectInst : SingleValueInstruction,
768-
UnaryInstruction {}
778+
final public class RefToBridgeObjectInst : SingleValueInstruction, ForwardingInstruction {
779+
public var convertedOperand: Operand { operands[0] }
780+
public var maskOperand: Operand { operands[1] }
781+
}
769782

770783
final public class BridgeObjectToRefInst : SingleValueInstruction,
771-
UnaryInstruction {}
784+
ConversionInstruction {}
772785

773786
final public class BridgeObjectToWordInst : SingleValueInstruction,
774-
UnaryInstruction {}
787+
ConversionInstruction {}
775788

776789
public typealias AccessKind = swift.SILAccessKind
777790

@@ -907,6 +920,15 @@ final public class ObjectInst : SingleValueInstruction {
907920
}
908921
}
909922

923+
final public class TuplePackExtractInst: SingleValueInstruction, ForwardingInstruction {
924+
public var indexOperand: Operand { operands[0] }
925+
public var tupleOperand: Operand { operands[1] }
926+
}
927+
928+
final public class DifferentiableFunctionInst: SingleValueInstruction, ForwardingInstruction {}
929+
930+
final public class LinearFunctionInst: SingleValueInstruction, ForwardingInstruction {}
931+
910932
//===----------------------------------------------------------------------===//
911933
// single-value allocation instructions
912934
//===----------------------------------------------------------------------===//
@@ -961,11 +983,11 @@ final public class BeginCOWMutationInst : MultipleValueInstruction,
961983
public var instanceResult: Value { return getResult(index: 1) }
962984
}
963985

964-
final public class DestructureStructInst : MultipleValueInstruction, UnaryInstruction {
986+
final public class DestructureStructInst : MultipleValueInstruction, UnaryInstruction, ForwardingInstruction {
965987
public var `struct`: Value { operand.value }
966988
}
967989

968-
final public class DestructureTupleInst : MultipleValueInstruction, UnaryInstruction {
990+
final public class DestructureTupleInst : MultipleValueInstruction, UnaryInstruction, ForwardingInstruction {
969991
public var `tuple`: Value { operand.value }
970992
}
971993

@@ -1059,7 +1081,7 @@ final public class CondBranchInst : TermInst {
10591081
final public class SwitchValueInst : TermInst {
10601082
}
10611083

1062-
final public class SwitchEnumInst : TermInst {
1084+
final public class SwitchEnumInst : TermInst, ForwardingInstruction {
10631085

10641086
public var enumOp: Value { operands[0].value }
10651087

@@ -1102,7 +1124,7 @@ final public class DynamicMethodBranchInst : TermInst {
11021124
final public class AwaitAsyncContinuationInst : TermInst, UnaryInstruction {
11031125
}
11041126

1105-
final public class CheckedCastBranchInst : TermInst, UnaryInstruction {
1127+
final public class CheckedCastBranchInst : TermInst, UnaryInstruction, ForwardingInstruction {
11061128
public var source: Value { operand.value }
11071129
public var successBlock: BasicBlock { bridged.CheckedCastBranch_getSuccessBlock().block }
11081130
public var failureBlock: BasicBlock { bridged.CheckedCastBranch_getFailureBlock().block }

0 commit comments

Comments
 (0)