Skip to content

Commit 3b43da9

Browse files
committed
Swift Optimizer: improve ergonomics of Builder and PassContext
* split the PassUtils.swift file into PassContext.swift and Passes.swift * rework `Builder` bridging allowing more insertion point variations, e.g. inserting at the end of a block. * add Builder.create functions for more instructions * add `PassContext.splitBlock` * move SIL modification functions from PassContext to extensions of the relevant types (e.g. instructions). * rename `Location.bridgedLocation` -> `Location.bridged`
1 parent 14b985d commit 3b43da9

File tree

18 files changed

+576
-280
lines changed

18 files changed

+576
-280
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AssumeSingleThreaded.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ let assumeSingleThreadedPass = FunctionPass(
3333
for inst in block.instructions {
3434
guard let rcInst = inst as? RefCountingInst else { continue }
3535

36-
context.setAtomicity(of: rcInst, isAtomic: false)
36+
rcInst.setAtomicity(isAtomic: false, context)
3737
}
3838
}
3939
}

SwiftCompilerSources/Sources/Optimizer/InstructionPasses/SimplifyBeginCOWMutation.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ private func optimizeEmptySingleton(_ beginCOW: BeginCOWMutationInst,
6767
}
6868
let builder = Builder(at: beginCOW, location: beginCOW.location, context)
6969
let zero = builder.createIntegerLiteral(0, type: beginCOW.uniquenessResult.type);
70-
context.replaceAllUses(of: beginCOW.uniquenessResult, with: zero)
70+
beginCOW.uniquenessResult.uses.replaceAll(with: zero, context)
7171
}
7272

7373
private func isEmptyCOWSingleton(_ value: Value) -> Bool {
@@ -103,7 +103,7 @@ private func optimizeEmptyBeginEndPair(_ beginCOW: BeginCOWMutationInst,
103103

104104
for use in buffer.nonDebugUses {
105105
let endCOW = use.instruction as! EndCOWMutationInst
106-
context.replaceAllUses(of: endCOW, with: beginCOW.operand)
106+
endCOW.uses.replaceAll(with: beginCOW.operand, context)
107107
context.erase(instruction: endCOW)
108108
}
109109
context.erase(instruction: beginCOW, .includingDebugUses)
@@ -122,7 +122,7 @@ private func optimizeEmptyEndBeginPair(_ beginCOW: BeginCOWMutationInst,
122122
return false
123123
}
124124

125-
context.replaceAllUses(of: beginCOW.bufferResult, with: endCOW.operand)
125+
beginCOW.bufferResult.uses.replaceAll(with: endCOW.operand, context)
126126
context.erase(instruction: beginCOW, .includingDebugUses)
127127
context.erase(instruction: endCOW, .includingDebugUses)
128128
return true

SwiftCompilerSources/Sources/Optimizer/InstructionPasses/SimplifyStrongRetainRelease.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ let simplifyStrongReleasePass = InstructionPass<StrongReleaseInst>(
5959
// release of the class, squish the conversion.
6060
if let ier = op as? InitExistentialRefInst {
6161
if ier.uses.isSingleUse {
62-
context.setOperand(of: release, at: 0, to: ier.operand)
62+
release.setOperand(at: 0, to: ier.operand, context)
6363
context.erase(instruction: ier)
6464
return
6565
}

SwiftCompilerSources/Sources/Optimizer/PassManager/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# See http://swift.org/CONTRIBUTORS.txt for Swift project authors
88

99
swift_compiler_sources(Optimizer
10-
PassUtils.swift
10+
Passes.swift
11+
PassContext.swift
1112
PassRegistration.swift)
1213

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
//===--- PassContext.swift - defines the PassContext type -----------------===//
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+
import OptimizerBridging
15+
16+
public typealias BridgedFunctionPassCtxt =
17+
OptimizerBridging.BridgedFunctionPassCtxt
18+
public typealias BridgedInstructionPassCtxt =
19+
OptimizerBridging.BridgedInstructionPassCtxt
20+
21+
struct PassContext {
22+
23+
let _bridged: BridgedPassContext
24+
25+
func continueWithNextSubpassRun(for inst: Instruction? = nil) -> Bool {
26+
let bridgedInst = OptionalBridgedInstruction(obj: inst?.bridged.obj)
27+
return PassContext_continueWithNextSubpassRun(_bridged, bridgedInst) != 0
28+
}
29+
30+
//===--------------------------------------------------------------------===//
31+
// Analysis
32+
//===--------------------------------------------------------------------===//
33+
34+
var aliasAnalysis: AliasAnalysis {
35+
let bridgedAA = PassContext_getAliasAnalysis(_bridged)
36+
return AliasAnalysis(bridged: bridgedAA)
37+
}
38+
39+
var calleeAnalysis: CalleeAnalysis {
40+
let bridgeCA = PassContext_getCalleeAnalysis(_bridged)
41+
return CalleeAnalysis(bridged: bridgeCA)
42+
}
43+
44+
var deadEndBlocks: DeadEndBlocksAnalysis {
45+
let bridgeDEA = PassContext_getDeadEndBlocksAnalysis(_bridged)
46+
return DeadEndBlocksAnalysis(bridged: bridgeDEA)
47+
}
48+
49+
var dominatorTree: DominatorTree {
50+
let bridgedDT = PassContext_getDomTree(_bridged)
51+
return DominatorTree(bridged: bridgedDT)
52+
}
53+
54+
var postDominatorTree: PostDominatorTree {
55+
let bridgedPDT = PassContext_getPostDomTree(_bridged)
56+
return PostDominatorTree(bridged: bridgedPDT)
57+
}
58+
59+
//===--------------------------------------------------------------------===//
60+
// Interaction with AST and the SIL module
61+
//===--------------------------------------------------------------------===//
62+
63+
func getContextSubstitutionMap(for type: Type) -> SubstitutionMap {
64+
SubstitutionMap(PassContext_getContextSubstitutionMap(_bridged, type.bridged))
65+
}
66+
67+
func loadFunction(name: StaticString) -> Function? {
68+
return name.withUTF8Buffer { (nameBuffer: UnsafeBufferPointer<UInt8>) in
69+
PassContext_loadFunction(_bridged, BridgedStringRef(data: nameBuffer.baseAddress, length: nameBuffer.count)).function
70+
}
71+
}
72+
73+
//===--------------------------------------------------------------------===//
74+
// Modify SIL
75+
//===--------------------------------------------------------------------===//
76+
77+
/// Splits the basic block, which contains `inst`, before `inst` and returns the
78+
/// new block.
79+
///
80+
/// `inst` and all subsequent instructions are moved to the new block, while all
81+
/// instructions _before_ `inst` remain in the original block.
82+
func splitBlock(at inst: Instruction) -> BasicBlock {
83+
notifyBranchesChanged()
84+
return PassContext_splitBlock(inst.bridged).block
85+
}
86+
87+
enum EraseMode {
88+
case onlyInstruction, includingDebugUses
89+
}
90+
91+
func erase(instruction: Instruction, _ mode: EraseMode = .onlyInstruction) {
92+
switch mode {
93+
case .onlyInstruction:
94+
break
95+
case .includingDebugUses:
96+
for result in instruction.results {
97+
for use in result.uses {
98+
assert(use.instruction is DebugValueInst)
99+
PassContext_eraseInstruction(_bridged, use.instruction.bridged)
100+
}
101+
}
102+
}
103+
104+
if instruction is FullApplySite {
105+
notifyCallsChanged()
106+
}
107+
if instruction is TermInst {
108+
notifyBranchesChanged()
109+
}
110+
notifyInstructionsChanged()
111+
112+
PassContext_eraseInstruction(_bridged, instruction.bridged)
113+
}
114+
115+
func fixStackNesting(function: Function) {
116+
PassContext_fixStackNesting(_bridged, function.bridged)
117+
}
118+
119+
func modifyEffects(in function: Function, _ body: (inout FunctionEffects) -> ()) {
120+
function._modifyEffects(body)
121+
// TODO: do we need to notify any changes?
122+
}
123+
124+
//===--------------------------------------------------------------------===//
125+
// Private utilities
126+
//===--------------------------------------------------------------------===//
127+
128+
fileprivate func notifyInstructionsChanged() {
129+
PassContext_notifyChanges(_bridged, instructionsChanged)
130+
}
131+
132+
fileprivate func notifyCallsChanged() {
133+
PassContext_notifyChanges(_bridged, callsChanged)
134+
}
135+
136+
fileprivate func notifyBranchesChanged() {
137+
PassContext_notifyChanges(_bridged, branchesChanged)
138+
}
139+
}
140+
141+
//===----------------------------------------------------------------------===//
142+
// Builder initialization
143+
//===----------------------------------------------------------------------===//
144+
145+
extension Builder {
146+
/// Creates a builder which inserts _before_ `insPnt`, using a custom `location`.
147+
init(at insPnt: Instruction, location: Location, _ context: PassContext) {
148+
self.init(insertAt: .before(insPnt), location: location, passContext: context._bridged)
149+
}
150+
151+
/// Creates a builder which inserts _before_ `insPnt`, using the location of `insPnt`.
152+
init(at insPnt: Instruction, _ context: PassContext) {
153+
self.init(insertAt: .before(insPnt), location: insPnt.location, passContext: context._bridged)
154+
}
155+
156+
/// Creates a builder which inserts _after_ `insPnt`, using the location of `insPnt`.
157+
init(after insPnt: Instruction, _ context: PassContext) {
158+
if let nextInst = insPnt.next {
159+
self.init(insertAt: .before(nextInst), location: insPnt.location, passContext: context._bridged)
160+
} else {
161+
self.init(insertAt: .atEndOf(insPnt.block), location: insPnt.location, passContext: context._bridged)
162+
}
163+
}
164+
165+
/// Creates a builder which inserts at the end of `block`, using a custom `location`.
166+
init(atEndOf block: BasicBlock, location: Location, _ context: PassContext) {
167+
self.init(insertAt: .atEndOf(block), location: location, passContext: context._bridged)
168+
}
169+
170+
/// Creates a builder which inserts at the begin of `block`, using the location of the first
171+
/// instruction of `block`.
172+
init(atBeginOf block: BasicBlock, _ context: PassContext) {
173+
let firstInst = block.instructions.first!
174+
self.init(insertAt: .before(firstInst), location: firstInst.location, passContext: context._bridged)
175+
}
176+
}
177+
178+
//===----------------------------------------------------------------------===//
179+
// Modifying the SIL
180+
//===----------------------------------------------------------------------===//
181+
182+
extension BasicBlock {
183+
func addBlockArgument(type: Type, ownership: Ownership, _ context: PassContext) -> BlockArgument {
184+
context.notifyInstructionsChanged()
185+
return SILBasicBlock_addBlockArgument(bridged, type.bridged, ownership._bridged).blockArgument
186+
}
187+
188+
func eraseArgument(at index: Int, _ context: PassContext) {
189+
context.notifyInstructionsChanged()
190+
SILBasicBlock_eraseArgument(bridged, index)
191+
}
192+
}
193+
194+
extension AllocRefInstBase {
195+
func setIsStackAllocatable(_ context: PassContext) {
196+
context.notifyInstructionsChanged()
197+
AllocRefInstBase_setIsStackAllocatable(bridged)
198+
}
199+
}
200+
201+
extension UseList {
202+
func replaceAll(with replacement: Value, _ context: PassContext) {
203+
for use in self {
204+
use.instruction.setOperand(at: use.index, to: replacement, context)
205+
}
206+
}
207+
}
208+
209+
extension Instruction {
210+
func setOperand(at index : Int, to value: Value, _ context: PassContext) {
211+
if self is FullApplySite && index == ApplyOperands.calleeOperandIndex {
212+
context.notifyCallsChanged()
213+
}
214+
context.notifyInstructionsChanged()
215+
216+
SILInstruction_setOperand(bridged, index, value.bridged)
217+
}
218+
}
219+
220+
extension RefCountingInst {
221+
func setAtomicity(isAtomic: Bool, _ context: PassContext) {
222+
context.notifyInstructionsChanged()
223+
RefCountingInst_setIsAtomic(bridged, isAtomic)
224+
}
225+
}

0 commit comments

Comments
 (0)