Skip to content

Commit 81c6575

Browse files
authored
Merge pull request #78059 from eeckstein/destroy-hoisting
Optimizer: add a new destroy-hoisting optimization
2 parents 5fb3578 + 5be781a commit 81c6575

File tree

19 files changed

+826
-57
lines changed

19 files changed

+826
-57
lines changed

SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ import SIL
4040
/// destruct this data structure, e.g. in a `defer {}` block.
4141
struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
4242

43-
/// The dominating begin instruction.
44-
let begin: Instruction
45-
4643
/// The underlying block range.
4744
private(set) var blockRange: BasicBlockRange
4845

@@ -52,10 +49,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
5249
private var inExclusiveRange: InstructionSet
5350

5451
init(begin beginInst: Instruction, _ context: some Context) {
55-
self.begin = beginInst
56-
self.blockRange = BasicBlockRange(begin: beginInst.parentBlock, context)
57-
self.insertedInsts = InstructionSet(context)
58-
self.inExclusiveRange = InstructionSet(context)
52+
self = InstructionRange(beginBlock: beginInst.parentBlock, context)
5953
self.inExclusiveRange.insert(beginInst)
6054
}
6155

@@ -65,28 +59,32 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
6559
}
6660

6761
init(for value: Value, _ context: some Context) {
68-
self = InstructionRange(begin: InstructionRange.beginningInstruction(for: value), context)
62+
if let inst = value.definingInstruction {
63+
self = InstructionRange(begin: inst, context)
64+
} else if let arg = value as? Argument {
65+
self = InstructionRange(beginBlock: arg.parentBlock, context)
66+
} else {
67+
fatalError("cannot build an instruction range for \(value)")
68+
}
6969
}
7070

71-
static func beginningInstruction(for value: Value) -> Instruction {
72-
if let def = value.definingInstructionOrTerminator {
73-
return def
74-
}
75-
assert(Phi(value) != nil || value is FunctionArgument)
76-
return value.parentBlock.instructions.first!
71+
private init(beginBlock: BasicBlock, _ context: some Context) {
72+
self.blockRange = BasicBlockRange(begin: beginBlock, context)
73+
self.insertedInsts = InstructionSet(context)
74+
self.inExclusiveRange = InstructionSet(context)
7775
}
7876

7977
/// Insert a potential end instruction.
8078
mutating func insert(_ inst: Instruction) {
8179
insertedInsts.insert(inst)
8280
insertIntoRange(instructions: ReverseInstructionList(first: inst.previous))
8381
blockRange.insert(inst.parentBlock)
84-
if inst.parentBlock != begin.parentBlock {
82+
if inst.parentBlock != blockRange.begin {
8583
// The first time an instruction is inserted in another block than the begin-block we need to insert
8684
// instructions from the begin instruction to the end of the begin block.
8785
// For subsequent insertions this is a no-op: `insertIntoRange` will return immediately because those
8886
// instruction are already inserted.
89-
insertIntoRange(instructions: begin.parentBlock.instructions.reversed())
87+
insertIntoRange(instructions: blockRange.begin.instructions.reversed())
9088
}
9189
}
9290

@@ -103,22 +101,14 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
103101
return true
104102
}
105103
let block = inst.parentBlock
106-
return block != begin.parentBlock && blockRange.contains(block)
104+
return block != blockRange.begin && blockRange.contains(block)
107105
}
108106

109107
/// Returns true if the inclusive range contains `inst`.
110108
func inclusiveRangeContains (_ inst: Instruction) -> Bool {
111109
contains(inst) || insertedInsts.contains(inst)
112110
}
113111

114-
/// Returns true if the range is valid and that's iff the begin instruction
115-
/// dominates all instructions of the range.
116-
var isValid: Bool {
117-
blockRange.isValid &&
118-
// Check if there are any inserted instructions before the begin instruction in its block.
119-
!ReverseInstructionList(first: begin).dropFirst().contains { insertedInsts.contains($0) }
120-
}
121-
122112
/// Returns the end instructions.
123113
///
124114
/// Warning: this returns `begin` if no instructions were inserted.
@@ -160,6 +150,10 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
160150
}
161151
}
162152

153+
var begin: Instruction? {
154+
blockRange.begin.instructions.first(where: inExclusiveRange.contains)
155+
}
156+
163157
private mutating func insertIntoRange(instructions: ReverseInstructionList) {
164158
for inst in instructions {
165159
if !inExclusiveRange.insert(inst) {
@@ -169,9 +163,9 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
169163
}
170164

171165
var description: String {
172-
return (isValid ? "" : "<invalid>\n") +
166+
return (blockRange.isValid ? "" : "<invalid>\n") +
173167
"""
174-
begin: \(begin)
168+
begin: \(begin?.description ?? blockRange.begin.name)
175169
ends: \(ends.map { $0.description }.joined(separator: "\n "))
176170
exits: \(exits.map { $0.description }.joined(separator: "\n "))
177171
interiors:\(interiors.map { $0.description }.joined(separator: "\n "))

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ swift_compiler_sources(Optimizer
1818
CopyToBorrowOptimization.swift
1919
DeadStoreElimination.swift
2020
DeinitDevirtualizer.swift
21+
DestroyHoisting.swift
2122
InitializeStaticGlobals.swift
2223
LetPropertyLowering.swift
2324
LifetimeDependenceDiagnostics.swift

0 commit comments

Comments
 (0)