Skip to content

Commit bd40059

Browse files
authored
Merge pull request #42099 from eeckstein/sil-infrastructure
swift SIL: add some Instruction, Value and Type APIs
2 parents fee26b6 + 4824d6d commit bd40059

File tree

21 files changed

+594
-86
lines changed

21 files changed

+594
-86
lines changed

SwiftCompilerSources/Sources/Optimizer/DataStructures/BasicBlockRange.swift

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -51,47 +51,62 @@ struct BasicBlockRange : CustomStringConvertible, CustomReflectable {
5151
/// The dominating begin block.
5252
let begin: BasicBlock
5353

54-
/// The exclusive range, i.e. not containing the end blocks.
55-
private(set) var range: Stack<BasicBlock>
54+
/// The inclusive range, i.e. the exclusive range plus the end blocks.
55+
private(set) var inclusiveRange: Stack<BasicBlock>
5656

57+
/// The exclusive range, i.e. not containing the end blocks.
58+
var range: LazyFilterSequence<Stack<BasicBlock>> {
59+
inclusiveRange.lazy.filter { contains($0) }
60+
}
61+
5762
/// All inserted blocks.
5863
private(set) var inserted: Stack<BasicBlock>
5964

60-
private var insertedSet: BasicBlockSet
65+
private var wasInserted: BasicBlockSet
66+
private var inExclusiveRange: BasicBlockSet
6167
private var worklist: BasicBlockWorklist
6268

6369
init(begin: BasicBlock, _ context: PassContext) {
6470
self.begin = begin
65-
self.range = Stack(context)
71+
self.inclusiveRange = Stack(context)
6672
self.inserted = Stack(context)
67-
self.insertedSet = BasicBlockSet(context)
73+
self.wasInserted = BasicBlockSet(context)
74+
self.inExclusiveRange = BasicBlockSet(context)
6875
self.worklist = BasicBlockWorklist(context)
76+
worklist.pushIfNotVisited(begin)
6977
}
7078

7179
/// Insert a potential end block.
7280
mutating func insert(_ block: BasicBlock) {
73-
if !insertedSet.contains(block) {
74-
insertedSet.insert(block)
81+
if !wasInserted.contains(block) {
82+
wasInserted.insert(block)
7583
inserted.append(block)
7684
}
77-
if block != begin {
78-
worklist.pushIfNotVisited(contentsOf: block.predecessors)
79-
80-
while let b = worklist.pop() {
81-
range.append(b)
82-
if b != begin {
83-
worklist.pushIfNotVisited(contentsOf: b.predecessors)
85+
worklist.pushIfNotVisited(block)
86+
while let b = worklist.pop() {
87+
inclusiveRange.append(b)
88+
if b != begin {
89+
for pred in b.predecessors {
90+
worklist.pushIfNotVisited(pred)
91+
inExclusiveRange.insert(pred)
8492
}
8593
}
8694
}
8795
}
8896

97+
/// Insert a sequence of potential end blocks.
98+
mutating func insert<S: Sequence>(contentsOf other: S) where S.Element == BasicBlock {
99+
for block in other {
100+
insert(block)
101+
}
102+
}
103+
89104
/// Returns true if the exclusive range contains `block`.
90-
func contains(_ block: BasicBlock) -> Bool { worklist.hasBeenPushed(block) }
105+
func contains(_ block: BasicBlock) -> Bool { inExclusiveRange.contains(block) }
91106

92107
/// Returns true if the inclusive range contains `block`.
93108
func inclusiveRangeContains (_ block: BasicBlock) -> Bool {
94-
contains(block) || insertedSet.contains(block)
109+
worklist.hasBeenPushed(block)
95110
}
96111

97112
/// Returns true if the range is valid and that's iff the begin block dominates all blocks of the range.
@@ -104,14 +119,14 @@ struct BasicBlockRange : CustomStringConvertible, CustomReflectable {
104119

105120
/// Returns the end blocks.
106121
var ends: LazyFilterSequence<Stack<BasicBlock>> {
107-
inserted.lazy.filter { !worklist.hasBeenPushed($0) }
122+
inserted.lazy.filter { !contains($0) }
108123
}
109124

110125
/// Returns the exit blocks.
111126
var exits: LazySequence<FlattenSequence<
112-
LazyMapSequence<Stack<BasicBlock>,
127+
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,
113128
LazyFilterSequence<SuccessorArray>>>> {
114-
range.lazy.flatMap {
129+
range.flatMap {
115130
$0.successors.lazy.filter {
116131
!inclusiveRangeContains($0) || $0 == begin
117132
}
@@ -124,22 +139,25 @@ struct BasicBlockRange : CustomStringConvertible, CustomReflectable {
124139
}
125140

126141
var description: String {
127-
"""
128-
begin: \(begin.name)
129-
range: \(range)
130-
ends: \(ends)
131-
exits: \(exits)
132-
interiors: \(interiors)
133-
"""
142+
return (isValid ? "" : "<invalid>\n") +
143+
"""
144+
begin: \(begin.name)
145+
range: \(range)
146+
inclrange: \(inclusiveRange)
147+
ends: \(ends)
148+
exits: \(exits)
149+
interiors: \(interiors)
150+
"""
134151
}
135152

136153
var customMirror: Mirror { Mirror(self, children: []) }
137154

138155
/// TODO: once we have move-only types, make this a real deinit.
139156
mutating func deinitialize() {
140157
worklist.deinitialize()
158+
inExclusiveRange.deinitialize()
159+
wasInserted.deinitialize()
141160
inserted.deinitialize()
142-
insertedSet.deinitialize()
143-
range.deinitialize()
161+
inclusiveRange.deinitialize()
144162
}
145163
}

SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import SIL
1414

15-
/// A range of basic blocks.
15+
/// A range of instructions.
1616
///
1717
/// The `InstructionRange` defines a range from a dominating "begin" instruction to one or more "end" instructions.
1818
/// The range is "exclusive", which means that the "end" instructions are not part of the range.
@@ -60,6 +60,13 @@ struct InstructionRange : CustomStringConvertible, CustomReflectable {
6060
blockRange.insert(inst.block)
6161
}
6262

63+
/// Insert a sequence of potential end instructions.
64+
mutating func insert<S: Sequence>(contentsOf other: S) where S.Element == Instruction {
65+
for inst in other {
66+
insert(inst)
67+
}
68+
}
69+
6370
/// Returns true if the exclusive range contains `inst`.
6471
func contains(_ inst: Instruction) -> Bool {
6572
let block = inst.block
@@ -99,7 +106,7 @@ struct InstructionRange : CustomStringConvertible, CustomReflectable {
99106

100107
/// Returns the exit instructions.
101108
var exits: LazyMapSequence<LazySequence<FlattenSequence<
102-
LazyMapSequence<Stack<BasicBlock>,
109+
LazyMapSequence<LazyFilterSequence<Stack<BasicBlock>>,
103110
LazyFilterSequence<SuccessorArray>>>>,
104111
Instruction> {
105112
blockRange.exits.lazy.map { $0.instructions.first! }
@@ -116,21 +123,20 @@ struct InstructionRange : CustomStringConvertible, CustomReflectable {
116123
let isInterior = include
117124
include = true
118125
return isInterior
119-
120126
}
121127
return false
122128
}
123129
}
124130
}
125131

126132
var description: String {
127-
"""
128-
begin: \(begin)
129-
range: \(blockRange.range)
130-
ends: \(ends.map { $0.description }.joined(separator: "\n "))
131-
exits: \(exits.map { $0.description }.joined(separator: "\n "))
132-
interiors:\(interiors.map { $0.description }.joined(separator: "\n "))
133-
"""
133+
return (isValid ? "" : "<invalid>\n") +
134+
"""
135+
begin: \(begin)
136+
ends: \(ends.map { $0.description }.joined(separator: "\n "))
137+
exits: \(exits.map { $0.description }.joined(separator: "\n "))
138+
interiors:\(interiors.map { $0.description }.joined(separator: "\n "))
139+
"""
134140
}
135141

136142
var customMirror: Mirror { Mirror(self, children: []) }

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ swift_compiler_sources(Optimizer
1010
AssumeSingleThreaded.swift
1111
SILPrinter.swift
1212
MergeCondFails.swift
13+
RangeDumper.swift
1314
ReleaseDevirtualizer.swift
1415
RunUnitTests.swift
1516
)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===--- RangeDumper.swift - Dumps escape information ----------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2022 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 SIL
14+
15+
let rangeDumper = FunctionPass(name: "dump-ranges", {
16+
(function: Function, context: PassContext) in
17+
18+
var begin: Instruction?
19+
var ends = Stack<Instruction>(context)
20+
defer { ends.deinitialize() }
21+
var interiors = Stack<Instruction>(context)
22+
defer { interiors.deinitialize() }
23+
var ins = Stack<Instruction>(context)
24+
defer { ins.deinitialize() }
25+
var outs = Stack<Instruction>(context)
26+
defer { outs.deinitialize() }
27+
28+
for block in function.blocks {
29+
for inst in block.instructions {
30+
if let sli = inst as? StringLiteralInst {
31+
switch sli.string {
32+
case "begin":
33+
precondition(begin == nil, "more than one begin instruction")
34+
begin = sli
35+
case "end":
36+
ends.append(sli)
37+
case "interior":
38+
interiors.append(sli)
39+
case "inside":
40+
ins.append(sli)
41+
case "outside":
42+
outs.append(sli)
43+
default:
44+
break
45+
}
46+
}
47+
}
48+
}
49+
50+
guard let begin = begin else { return }
51+
52+
var instRange = InstructionRange(begin: begin, context)
53+
defer { instRange.deinitialize() }
54+
55+
instRange.insert(contentsOf: ends)
56+
instRange.insert(contentsOf: interiors)
57+
58+
print("Instruction range in \(function.name):")
59+
print(instRange)
60+
print("Block range in \(function.name):")
61+
print(instRange.blockRange)
62+
print("End function \(function.name)\n")
63+
64+
verify(instRange.blockRange, context)
65+
66+
for i in ins {
67+
precondition(instRange.contains(i))
68+
precondition(instRange.inclusiveRangeContains(i))
69+
}
70+
for e in ends {
71+
precondition(!instRange.contains(e))
72+
precondition(instRange.inclusiveRangeContains(e))
73+
}
74+
for o in outs {
75+
precondition(!instRange.contains(o))
76+
precondition(!instRange.inclusiveRangeContains(o))
77+
}
78+
})
79+
80+
private func verify(_ blockRange: BasicBlockRange, _ context: PassContext) {
81+
var inRange = BasicBlockSet(context)
82+
defer { inRange.deinitialize() }
83+
for b in blockRange.range {
84+
inRange.insert(b)
85+
}
86+
87+
var inInclusiveRange = BasicBlockSet(context)
88+
defer { inInclusiveRange.deinitialize() }
89+
for b in blockRange.inclusiveRange {
90+
inInclusiveRange.insert(b)
91+
}
92+
93+
for b in blockRange.begin.function.blocks {
94+
precondition(blockRange.contains(b) == inRange.contains(b))
95+
precondition(blockRange.inclusiveRangeContains(b) == inInclusiveRange.contains(b))
96+
}
97+
}
98+

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/SILPrinter.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ func runSILPrinter(function: Function, context: PassContext) {
2929
for use in arg.uses {
3030
print(" user: \(use.instruction)")
3131
}
32+
if let blockArg = arg as? BlockArgument, blockArg.isPhiArgument {
33+
for incoming in blockArg.incomingPhiValues {
34+
print(" incoming: \(incoming)")
35+
}
36+
}
3237
}
3338

3439
print(" instructions:")

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ private func registerSwiftPasses() {
5151
registerPass(simplifyStrongRetainPass, { simplifyStrongRetainPass.run($0) })
5252
registerPass(simplifyStrongReleasePass, { simplifyStrongReleasePass.run($0) })
5353
registerPass(assumeSingleThreadedPass, { assumeSingleThreadedPass.run($0) })
54+
registerPass(rangeDumper, { rangeDumper.run($0) })
5455
registerPass(runUnitTests, { runUnitTests.run($0) })
5556
registerPass(releaseDevirtualizerPass, { releaseDevirtualizerPass.run($0) })
5657
}

SwiftCompilerSources/Sources/SIL/ApplySite.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public struct ApplyOperands {
1818
public protocol ApplySite : AnyObject {
1919
var operands: OperandArray { get }
2020
var numArguments: Int { get }
21+
func calleeArgIndex(callerArgIndex: Int) -> Int
22+
func callerArgIndex(calleeArgIndex: Int) -> Int?
2123
}
2224

2325
extension ApplySite {
@@ -47,3 +49,8 @@ extension ApplySite {
4749
public protocol FullApplySite : ApplySite {
4850
var singleDirectResult: Value? { get }
4951
}
52+
53+
extension FullApplySite {
54+
public func calleeArgIndex(callerArgIndex: Int) -> Int { callerArgIndex }
55+
public func callerArgIndex(calleeArgIndex: Int) -> Int? { calleeArgIndex }
56+
}

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,42 @@ public class Argument : Value, Equatable {
3535
}
3636

3737
final public class FunctionArgument : Argument {
38+
public var isExclusiveIndirectParameter: Bool {
39+
SILArgument_isExclusiveIndirectParameter(bridged) != 0
40+
}
3841
}
3942

4043
final public class BlockArgument : Argument {
41-
/// Note: critical edges are not supported, i.e. this is false if there is
42-
/// a cond_br in the predecessors.
4344
public var isPhiArgument: Bool {
44-
block.predecessors.allSatisfy { $0.terminator is BranchInst }
45+
block.predecessors.allSatisfy {
46+
let term = $0.terminator
47+
return term is BranchInst || term is CondBranchInst
48+
}
4549
}
4650

4751
public var incomingPhiOperands: LazyMapSequence<PredecessorList, Operand> {
4852
assert(isPhiArgument)
4953
let idx = index
50-
return block.predecessors.lazy.map { $0.terminator.operands[idx] }
54+
return block.predecessors.lazy.map {
55+
switch $0.terminator {
56+
case let br as BranchInst:
57+
return br.operands[idx]
58+
case let condBr as CondBranchInst:
59+
if condBr.trueBlock == self.block {
60+
assert(condBr.falseBlock != self.block)
61+
return condBr.trueOperands[idx]
62+
} else {
63+
assert(condBr.falseBlock == self.block)
64+
return condBr.falseOperands[idx]
65+
}
66+
default:
67+
fatalError("wrong terminator for phi-argument")
68+
}
69+
}
5170
}
5271

53-
public var incomingPhiValues: LazyMapSequence<PredecessorList, Value> {
54-
assert(isPhiArgument)
55-
let idx = index
56-
return block.predecessors.lazy.map { $0.terminator.operands[idx].value }
72+
public var incomingPhiValues: LazyMapSequence<LazyMapSequence<PredecessorList, Operand>, Value> {
73+
incomingPhiOperands.lazy.map { $0.value }
5774
}
5875
}
5976

0 commit comments

Comments
 (0)