Skip to content

Commit 7dc3d72

Browse files
authored
Merge pull request #70485 from atrick/bridge-util
[NFC] Bridging and utilities for SwiftCompilerSources required by lifetime dependence utilities.
2 parents 1057441 + d0b47b8 commit 7dc3d72

File tree

14 files changed

+398
-16
lines changed

14 files changed

+398
-16
lines changed

SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,19 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
5959
self.inExclusiveRange.insert(beginInst)
6060
}
6161

62+
init(for value: Value, _ context: some Context) {
63+
var begin: Instruction
64+
if let def = value.definingInstruction {
65+
begin = def
66+
} else if let result = TerminatorResult(value) {
67+
begin = result.terminator
68+
} else {
69+
assert(Phi(value) != nil || value is FunctionArgument)
70+
begin = value.parentBlock.instructions.first!
71+
}
72+
self = InstructionRange(begin: begin, context)
73+
}
74+
6275
/// Insert a potential end instruction.
6376
mutating func insert(_ inst: Instruction) {
6477
insertedInsts.insert(inst)
@@ -103,12 +116,21 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
103116
}
104117

105118
/// Returns the end instructions.
119+
///
120+
/// Warning: this returns `begin` if no instructions were inserted.
106121
var ends: LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>, Instruction> {
107122
blockRange.ends.map {
108123
$0.instructions.reversed().first(where: { insertedInsts.contains($0)})!
109124
}
110125
}
111126

127+
// Returns the exit blocks.
128+
var exitBlocks: LazySequence<FlattenSequence<
129+
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,
130+
LazyFilterSequence<SuccessorArray>>>> {
131+
blockRange.exits
132+
}
133+
112134
/// Returns the exit instructions.
113135
var exits: LazyMapSequence<LazySequence<FlattenSequence<
114136
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import ASTBridging
1314
import SIL
1415
import OptimizerBridging
1516

SwiftCompilerSources/Sources/SIL/ApplySite.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ extension ApplySite {
120120
return nil
121121
}
122122

123+
/// Get the conventions of the callee without the applied substitutions.
124+
public var originalCalleeConvention: FunctionConvention {
125+
FunctionConvention(for: callee.type.bridged.getASTType(),
126+
in: parentFunction)
127+
}
128+
123129
public func hasSemanticsAttribute(_ attr: StaticString) -> Bool {
124130
if let callee = referencedFunction {
125131
return callee.hasSemanticsAttribute(attr)

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public class Argument : Value, Hashable {
2828
public var index: Int {
2929
return parentBlock.arguments.firstIndex(of: self)!
3030
}
31+
32+
public var isReborrow: Bool { bridged.isReborrow() }
3133

3234
public static func ==(lhs: Argument, rhs: Argument) -> Bool {
3335
lhs === rhs
@@ -85,30 +87,39 @@ public struct Phi {
8587
return value.parentBlock
8688
}
8789

88-
public var incomingOperands: LazyMapSequence<PredecessorList, Operand> {
90+
public func incomingOperand(inPredecessor predecessor: BasicBlock)
91+
-> Operand {
8992
let blockArgIdx = value.index
90-
return predecessors.lazy.map {
91-
switch $0.terminator {
92-
case let br as BranchInst:
93-
return br.operands[blockArgIdx]
94-
case let condBr as CondBranchInst:
95-
if condBr.trueBlock == successor {
96-
assert(condBr.falseBlock != successor)
97-
return condBr.trueOperands[blockArgIdx]
98-
} else {
99-
assert(condBr.falseBlock == successor)
100-
return condBr.falseOperands[blockArgIdx]
101-
}
102-
default:
103-
fatalError("wrong terminator for phi-argument")
93+
switch predecessor.terminator {
94+
case let br as BranchInst:
95+
return br.operands[blockArgIdx]
96+
case let condBr as CondBranchInst:
97+
if condBr.trueBlock == successor {
98+
assert(condBr.falseBlock != successor)
99+
return condBr.trueOperands[blockArgIdx]
100+
} else {
101+
assert(condBr.falseBlock == successor)
102+
return condBr.falseOperands[blockArgIdx]
104103
}
104+
default:
105+
fatalError("wrong terminator for phi-argument")
105106
}
106107
}
107108

109+
public var incomingOperands: LazyMapSequence<PredecessorList, Operand> {
110+
predecessors.lazy.map { incomingOperand(inPredecessor: $0) }
111+
}
112+
108113
public var incomingValues: LazyMapSequence<LazyMapSequence<PredecessorList, Operand>, Value> {
109114
incomingOperands.lazy.map { $0.value }
110115
}
111116

117+
public var isReborrow: Bool { value.isReborrow }
118+
119+
public var endsLifetime: Bool {
120+
value.ownership == .owned || value.isReborrow
121+
}
122+
112123
public static func ==(lhs: Phi, rhs: Phi) -> Bool {
113124
lhs.value === rhs.value
114125
}

SwiftCompilerSources/Sources/SIL/BasicBlock.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ final public class BasicBlock : CustomStringConvertible, HasShortDescription, Eq
5353

5454
public var hasSinglePredecessor: Bool { singlePredecessor != nil }
5555

56+
public var singleSuccessor: BasicBlock? {
57+
successors.count == 1 ? successors[0] : nil
58+
}
59+
5660
/// The index of the basic block in its function.
5761
/// This has O(n) complexity. Only use it for debugging
5862
public var index: Int {

SwiftCompilerSources/Sources/SIL/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_swift_compiler_module(SIL
1717
Effects.swift
1818
ForwardingInstruction.swift
1919
Function.swift
20+
FunctionConvention.swift
2021
GlobalVariable.swift
2122
Instruction.swift
2223
Location.swift

SwiftCompilerSources/Sources/SIL/Function.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
3333

3434
public var hasOwnership: Bool { bridged.hasOwnership() }
3535

36+
public var hasLoweredAddresses: Bool { bridged.hasLoweredAddresses() }
37+
3638
/// Returns true if the function is a definition and not only an external declaration.
3739
///
3840
/// This is the case if the functioun contains a body, i.e. some basic blocks.
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
//===--- FunctionConvention.swift - function conventions ------------------===//
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+
/// SIL function convention based on the AST function type and SIL stage.
16+
public struct FunctionConvention {
17+
let bridgedFunctionType: BridgedASTType
18+
let hasLoweredAddresses: Bool
19+
20+
init(for bridgedFunctionType: BridgedASTType, in function: Function) {
21+
self.bridgedFunctionType = bridgedFunctionType
22+
self.hasLoweredAddresses = function.hasLoweredAddresses
23+
}
24+
25+
struct Results : Collection {
26+
let bridged: BridgedResultInfoArray
27+
let hasLoweredAddresses: Bool
28+
29+
public var startIndex: Int { 0 }
30+
31+
public var endIndex: Int { bridged.count() }
32+
33+
public func index(after index: Int) -> Int {
34+
return index + 1
35+
}
36+
37+
public subscript(_ index: Int) -> ResultInfo {
38+
return ResultInfo(bridged: bridged.at(index),
39+
hasLoweredAddresses: hasLoweredAddresses)
40+
}
41+
}
42+
43+
var results: Results {
44+
Results(bridged: bridgedFunctionType.SILFunctionType_getResults(),
45+
hasLoweredAddresses: hasLoweredAddresses)
46+
}
47+
48+
/// Number of SIL arguments for indirect results, not including error results.
49+
var indirectSILResultCount: UInt {
50+
// TODO: Return packs directly in lowered-address mode
51+
return hasLoweredAddresses
52+
? bridgedFunctionType.SILFunctionType_getNumIndirectFormalResults()
53+
: bridgedFunctionType.SILFunctionType_getNumPackResults()
54+
}
55+
56+
var errorResult: ResultInfo? {
57+
guard bridgedFunctionType.SILFunctionType_hasErrorResult() else {
58+
return nil
59+
}
60+
return results[0]
61+
}
62+
63+
/// The number of SIL error results passed as address-typed arguments.
64+
var indirectSILErrorResultCount: UInt {
65+
guard hasLoweredAddresses else { return 0 }
66+
return errorResult?.convention == .indirect ? 1 : 0
67+
}
68+
69+
var parameterCount: UInt {
70+
bridgedFunctionType.SILFunctionType_getNumParameters()
71+
}
72+
73+
/// The SIL argument index of the function type's first parameter.
74+
var firstParameterIndex: UInt {
75+
indirectSILResultCount + indirectSILErrorResultCount
76+
}
77+
78+
// The SIL argument index of the 'self' paramter.
79+
var selfIndex: UInt? {
80+
guard bridgedFunctionType.SILFunctionType_hasSelfParam() else { return nil }
81+
return firstParameterIndex + parameterCount - 1
82+
}
83+
}
84+
85+
/// A function result type and the rules for returning it in SIL.
86+
struct ResultInfo {
87+
/// The unsubstituted parameter type that describes the abstract calling convention of the parameter.
88+
///
89+
/// TODO: For most purposes, you probably want \c returnValueType.
90+
let interfaceType: BridgedASTType
91+
let convention: ResultConvention
92+
let hasLoweredAddresses: Bool
93+
94+
/// Is this result returned indirectly in SIL? Most formally indirect results can be returned directly in SIL. This depends on the calling function.
95+
var isSILIndirect: Bool {
96+
switch convention {
97+
case .indirect:
98+
return hasLoweredAddresses || interfaceType.isOpenedExistentialWithError()
99+
case .pack:
100+
return true
101+
case .owned, .unowned, .unownedInnerPointer, .autoreleased:
102+
return false
103+
}
104+
}
105+
}
106+
107+
public enum ResultConvention {
108+
/// 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.
109+
case indirect
110+
111+
/// The caller is responsible for destroying this return value. Its type is non-trivial.
112+
case owned
113+
114+
/// 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.
115+
case unowned
116+
117+
/// 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.
118+
case unownedInnerPointer
119+
120+
/// 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.
121+
case autoreleased
122+
123+
/// 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.
124+
case pack
125+
126+
/// Does this result convention require indirect storage? This reflects a FunctionType's conventions, as opposed to the SIL conventions that dictate SILValue types.
127+
public var isASTIndirect: Bool {
128+
switch self {
129+
case .indirect, .pack:
130+
return true
131+
default:
132+
return false
133+
}
134+
}
135+
public var isASTDirect: Bool {
136+
return !isASTIndirect
137+
}
138+
}
139+
140+
// Bridging utilities
141+
142+
extension ResultInfo {
143+
init(bridged: BridgedResultInfo, hasLoweredAddresses: Bool) {
144+
self.interfaceType = BridgedASTType(type: bridged.type)
145+
self.convention = ResultConvention(bridged: bridged.convention)
146+
self.hasLoweredAddresses = hasLoweredAddresses
147+
}
148+
}
149+
150+
extension ResultConvention {
151+
init(bridged: BridgedResultConvention) {
152+
switch bridged {
153+
case .Indirect: self = .indirect
154+
case .Owned: self = .owned
155+
case .Unowned: self = .unowned
156+
case .UnownedInnerPointer: self = .unownedInnerPointer
157+
case .Autoreleased: self = .autoreleased
158+
case .Pack: self = .pack
159+
default:
160+
fatalError("unsupported result convention")
161+
}
162+
}
163+
}

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,8 @@ final public class BeginApplyInst : MultipleValueInstruction, FullApplySite {
10711071

10721072
public var singleDirectResult: Value? { nil }
10731073

1074+
public var token: Value { getResult(index: resultCount - 1) }
1075+
10741076
public var yieldedValues: Results {
10751077
Results(inst: self, numResults: resultCount - 1)
10761078
}

SwiftCompilerSources/Sources/SIL/Operand.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ extension Sequence where Element == Operand {
153153
public func getSingleUser<I: Instruction>(notOfType: I.Type) -> Instruction? {
154154
ignoreUsers(ofType: I.self).singleUse?.instruction
155155
}
156+
157+
public var lifetimeEndingUses: LazyFilterSequence<Self> {
158+
return self.lazy.filter { $0.endsLifetime }
159+
}
156160
}
157161

158162
extension OptionalBridgedOperand {

0 commit comments

Comments
 (0)