Skip to content

Commit b6cdc0a

Browse files
committed
Redo the pass manager
1 parent 3d65498 commit b6cdc0a

File tree

4 files changed

+508
-65
lines changed

4 files changed

+508
-65
lines changed

Sources/LLVM/PassManager.swift

Lines changed: 8 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import cllvm
33
#endif
44

55
/// A subset of supported LLVM IR optimizer passes.
6-
public enum FunctionPass {
6+
public enum Pass {
77
/// This pass uses the SSA based Aggressive DCE algorithm. This algorithm
88
/// assumes instructions are dead until proven otherwise, which makes
99
/// it more successful are removing non-obviously dead instructions.
@@ -106,8 +106,6 @@ public enum FunctionPass {
106106
case scalarReplAggregates
107107
/// Replace aggregates or pieces of aggregates with scalar SSA values.
108108
case scalarReplAggregatesSSA
109-
/// Tries to inline the fast path of library calls such as sqrt.
110-
case simplifyLibCalls
111109
/// This pass eliminates call instructions to the current function which occur
112110
/// immediately before return instructions.
113111
case tailCallElimination
@@ -186,69 +184,10 @@ public enum FunctionPass {
186184
/// A `FunctionPassManager` is an object that collects a sequence of passes
187185
/// which run over a particular IR construct, and runs each of them in sequence
188186
/// over each such construct.
187+
@available(*, deprecated, message: "Use the PassPipeliner instead")
189188
public class FunctionPassManager {
190189
internal let llvm: LLVMPassManagerRef
191190

192-
private static let passMapping: [FunctionPass: (LLVMPassManagerRef) -> Void] = [
193-
.aggressiveDCE: LLVMAddAggressiveDCEPass,
194-
.bitTrackingDCE: LLVMAddBitTrackingDCEPass,
195-
.alignmentFromAssumptions: LLVMAddAlignmentFromAssumptionsPass,
196-
.cfgSimplification: LLVMAddCFGSimplificationPass,
197-
.deadStoreElimination: LLVMAddDeadStoreEliminationPass,
198-
.scalarizer: LLVMAddScalarizerPass,
199-
.mergedLoadStoreMotion: LLVMAddMergedLoadStoreMotionPass,
200-
.gvn: LLVMAddGVNPass,
201-
.indVarSimplify: LLVMAddIndVarSimplifyPass,
202-
.instructionCombining: LLVMAddInstructionCombiningPass,
203-
.jumpThreading: LLVMAddJumpThreadingPass,
204-
.licm: LLVMAddLICMPass,
205-
.loopDeletion: LLVMAddLoopDeletionPass,
206-
.loopIdiom: LLVMAddLoopIdiomPass,
207-
.loopRotate: LLVMAddLoopRotatePass,
208-
.loopReroll: LLVMAddLoopRerollPass,
209-
.loopUnroll: LLVMAddLoopUnrollPass,
210-
.loopUnrollAndJam: LLVMAddLoopUnrollAndJamPass,
211-
.loopUnswitch: LLVMAddLoopUnswitchPass,
212-
.lowerAtomic: LLVMAddLowerAtomicPass,
213-
.memCpyOpt: LLVMAddMemCpyOptPass,
214-
.partiallyInlineLibCalls: LLVMAddPartiallyInlineLibCallsPass,
215-
.lowerSwitch: LLVMAddLowerSwitchPass,
216-
.promoteMemoryToRegister: LLVMAddPromoteMemoryToRegisterPass,
217-
.reassociate: LLVMAddReassociatePass,
218-
.sccp: LLVMAddSCCPPass,
219-
.scalarReplAggregates: LLVMAddScalarReplAggregatesPass,
220-
.scalarReplAggregatesSSA: LLVMAddScalarReplAggregatesPassSSA,
221-
.simplifyLibCalls: LLVMAddSimplifyLibCallsPass,
222-
.tailCallElimination: LLVMAddTailCallEliminationPass,
223-
.constantPropagation: LLVMAddConstantPropagationPass,
224-
.demoteMemoryToRegister: LLVMAddDemoteMemoryToRegisterPass,
225-
.verifier: LLVMAddVerifierPass,
226-
.correlatedValuePropagation: LLVMAddCorrelatedValuePropagationPass,
227-
.earlyCSE: LLVMAddEarlyCSEPass,
228-
.lowerExpectIntrinsic: LLVMAddLowerExpectIntrinsicPass,
229-
.typeBasedAliasAnalysis: LLVMAddTypeBasedAliasAnalysisPass,
230-
.scopedNoAliasAA: LLVMAddScopedNoAliasAAPass,
231-
.basicAliasAnalysis: LLVMAddBasicAliasAnalysisPass,
232-
.unifyFunctionExitNodes: LLVMAddUnifyFunctionExitNodesPass,
233-
.alwaysInliner: LLVMAddAlwaysInlinerPass,
234-
.argumentPromotion: LLVMAddArgumentPromotionPass,
235-
.constantMerge: LLVMAddConstantMergePass,
236-
.deadArgElimination: LLVMAddDeadArgEliminationPass,
237-
.functionAttrs: LLVMAddFunctionAttrsPass,
238-
.functionInlining: LLVMAddFunctionInliningPass,
239-
.globalDCE: LLVMAddGlobalDCEPass,
240-
.globalOptimizer: LLVMAddGlobalOptimizerPass,
241-
.ipConstantPropagation: LLVMAddIPConstantPropagationPass,
242-
.ipscc: LLVMAddIPSCCPPass,
243-
.pruneEH: LLVMAddPruneEHPass,
244-
.stripDeadPrototypes: LLVMAddStripDeadPrototypesPass,
245-
.stripSymbols: LLVMAddStripSymbolsPass,
246-
.loopVectorize: LLVMAddLoopVectorizePass,
247-
.slpVectorize: LLVMAddSLPVectorizePass,
248-
// .internalize: LLVMAddInternalizePass,
249-
// .sroaWithThreshhold: LLVMAddScalarReplAggregatesPassWithThreshold,
250-
]
251-
252191
/// Creates a `FunctionPassManager` bound to the given module's IR.
253192
public init(module: Module) {
254193
llvm = LLVMCreateFunctionPassManagerForModule(module.llvm)!
@@ -259,9 +198,9 @@ public class FunctionPassManager {
259198
///
260199
/// - parameter passes: A list of function passes to add to the pass manager's
261200
/// list of passes to run.
262-
public func add(_ passes: FunctionPass...) {
201+
public func add(_ passes: Pass...) {
263202
for pass in passes {
264-
FunctionPassManager.passMapping[pass]!(llvm)
203+
PassPipeliner.passMapping[pass]!(llvm)
265204
}
266205
}
267206

@@ -272,3 +211,7 @@ public class FunctionPassManager {
272211
LLVMRunFunctionPassManager(llvm, function.asLLVM())
273212
}
274213
}
214+
215+
@available(*, deprecated, renamed: "Pass")
216+
public typealias FunctionPass = Pass
217+

Sources/LLVM/PassPipeliner.swift

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
#if SWIFT_PACKAGE
2+
import cllvm
3+
#endif
4+
5+
/// Implements a pass manager, pipeliner, and executor for a set of
6+
/// user-provided optimization passes.
7+
///
8+
/// A `PassPipeliner` handles the creation of a related set of optimization
9+
/// passes called a "pipeline". Grouping passes is done for multiple reasons,
10+
/// chief among them is that optimizer passes are extremely sensitive to their
11+
/// ordering relative to other passses. In addition, pass groupings allow for
12+
/// the clean segregation of otherwise unrelated passes. For example, a
13+
/// pipeline might consist of "mandatory" passes such as Jump Threading, LICM,
14+
/// and DCE in one pipeline and "diagnostic" passes in another.
15+
public final class PassPipeliner {
16+
private enum Pipeline {
17+
case builtinPasses([Pass])
18+
case functionPassManager(LLVMPassManagerRef)
19+
case modulePassManager(LLVMPassManagerRef)
20+
}
21+
22+
/// The module for this pass pipeline.
23+
public let module: Module
24+
/// The pipeline stages registered with this pass pipeliner.
25+
public private(set) var stages: [String]
26+
27+
private var stageMapping: [String: Pipeline]
28+
private var frozen: Bool = false
29+
30+
public final class Builder {
31+
fileprivate var passes: [Pass] = []
32+
33+
fileprivate init() {}
34+
35+
/// Appends a pass to the current pipeline.
36+
public func add(_ type: Pass) {
37+
self.passes.append(type)
38+
}
39+
}
40+
41+
/// Initializes a new, empty pipeliner.
42+
///
43+
/// - Parameter module: The module the pipeliner will run over.
44+
public init(module: Module) {
45+
self.module = module
46+
self.stages = []
47+
self.stageMapping = [:]
48+
}
49+
50+
deinit {
51+
for stage in stageMapping.values {
52+
switch stage {
53+
case let .functionPassManager(pm):
54+
LLVMDisposePassManager(pm)
55+
case let .modulePassManager(pm):
56+
LLVMDisposePassManager(pm)
57+
case .builtinPasses(_):
58+
continue
59+
}
60+
}
61+
}
62+
63+
/// Appends a stage to the pipeliner.
64+
///
65+
/// The staging function provides a `Builder` object into which the types
66+
/// of passes for a given pipeline are inserted.
67+
///
68+
/// - Parameters:
69+
/// - name: The name of the pipeline stage.
70+
/// - stager: A builder function.
71+
public func addStage(_ name: String, _ stager: (Builder) -> Void) {
72+
precondition(!self.frozen, "Cannot add new stages to a frozen pipeline!")
73+
74+
self.frozen = true
75+
defer { self.frozen = false }
76+
77+
self.stages.append(name)
78+
let builder = Builder()
79+
stager(builder)
80+
self.stageMapping[name] = .builtinPasses(builder.passes)
81+
}
82+
83+
/// Executes the entirety of the pass pipeline.
84+
///
85+
/// Execution of passes is done in a loop that is divided into two phases.
86+
/// The first phase aggregates all local passes and stops aggregation when
87+
/// it encounters a module-level pass. This group of local passes
88+
/// is then run one at a time on the same scope. The second phase is entered
89+
/// and the module pass is run. The first phase is then re-entered until all
90+
/// local passes have run on all local scopes and all intervening module
91+
/// passes have been run.
92+
///
93+
/// The same pipeline may be repeatedly re-executed, but pipeline execution
94+
/// is not re-entrancy safe.
95+
public func execute() {
96+
precondition(!self.frozen, "Cannot execute a frozen pipeline!")
97+
98+
self.frozen = true
99+
defer { self.frozen = false }
100+
101+
stageLoop: for stage in self.stages {
102+
guard let pipeline = self.stageMapping[stage] else {
103+
fatalError("Unregistered pass stage?")
104+
}
105+
106+
switch pipeline {
107+
case let .builtinPasses(passTypes):
108+
guard !passTypes.isEmpty else {
109+
continue stageLoop
110+
}
111+
self.runPasses(passTypes)
112+
case let .functionPassManager(pm):
113+
self.runFunctionPasses([], pm)
114+
case let .modulePassManager(pm):
115+
LLVMRunPassManager(pm, self.module.llvm)
116+
}
117+
}
118+
}
119+
120+
private func runFunctionPasses(_ passes: [Pass], _ pm: LLVMPassManagerRef) {
121+
LLVMInitializeFunctionPassManager(pm)
122+
123+
for pass in passes {
124+
PassPipeliner.passMapping[pass]!(pm)
125+
}
126+
127+
for function in self.module.functions {
128+
LLVMRunFunctionPassManager(pm, function.asLLVM())
129+
}
130+
}
131+
132+
private func runPasses(_ passes: [Pass]) {
133+
let pm = LLVMCreatePassManager()!
134+
for pass in passes {
135+
PassPipeliner.passMapping[pass]!(pm)
136+
}
137+
LLVMRunPassManager(pm, self.module.llvm)
138+
LLVMDisposePassManager(pm)
139+
}
140+
}
141+
142+
// MARK: Standard Pass Pipelines
143+
144+
extension PassPipeliner {
145+
public func addStandardFunctionPipeline(
146+
_ name: String,
147+
optimization: CodeGenOptLevel = .`default`,
148+
size: CodeGenOptLevel = .none
149+
) {
150+
let passBuilder = self.configurePassBuilder(optimization, size)
151+
let functionPasses =
152+
LLVMCreateFunctionPassManagerForModule(self.module.llvm)!
153+
LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
154+
functionPasses)
155+
LLVMPassManagerBuilderDispose(passBuilder)
156+
self.stages.append(name)
157+
self.stageMapping[name] = .functionPassManager(functionPasses)
158+
}
159+
160+
public func addStandardModulePipeline(
161+
_ name: String,
162+
optimization: CodeGenOptLevel = .`default`,
163+
size: CodeGenOptLevel = .none
164+
) {
165+
let passBuilder = self.configurePassBuilder(optimization, size)
166+
let modulePasses = LLVMCreatePassManager()!
167+
LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses)
168+
LLVMPassManagerBuilderDispose(passBuilder)
169+
self.stages.append(name)
170+
self.stageMapping[name] = .modulePassManager(modulePasses)
171+
}
172+
173+
private func configurePassBuilder(
174+
_ opt: CodeGenOptLevel,
175+
_ size: CodeGenOptLevel
176+
) -> LLVMPassManagerBuilderRef {
177+
let passBuilder = LLVMPassManagerBuilderCreate()!
178+
switch opt {
179+
case .none:
180+
LLVMPassManagerBuilderSetOptLevel(passBuilder, 0)
181+
case .less:
182+
LLVMPassManagerBuilderSetOptLevel(passBuilder, 1)
183+
case .default:
184+
LLVMPassManagerBuilderSetOptLevel(passBuilder, 2)
185+
case .aggressive:
186+
LLVMPassManagerBuilderSetOptLevel(passBuilder, 3)
187+
}
188+
189+
switch size {
190+
case .none:
191+
LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0)
192+
case .less:
193+
LLVMPassManagerBuilderSetSizeLevel(passBuilder, 1)
194+
case .default:
195+
LLVMPassManagerBuilderSetSizeLevel(passBuilder, 2)
196+
case .aggressive:
197+
LLVMPassManagerBuilderSetSizeLevel(passBuilder, 3)
198+
}
199+
200+
return passBuilder
201+
}
202+
}
203+
204+
205+
extension PassPipeliner {
206+
static let passMapping: [Pass: (LLVMPassManagerRef) -> Void] = [
207+
.aggressiveDCE: LLVMAddAggressiveDCEPass,
208+
.bitTrackingDCE: LLVMAddBitTrackingDCEPass,
209+
.alignmentFromAssumptions: LLVMAddAlignmentFromAssumptionsPass,
210+
.cfgSimplification: LLVMAddCFGSimplificationPass,
211+
.deadStoreElimination: LLVMAddDeadStoreEliminationPass,
212+
.scalarizer: LLVMAddScalarizerPass,
213+
.mergedLoadStoreMotion: LLVMAddMergedLoadStoreMotionPass,
214+
.gvn: LLVMAddGVNPass,
215+
.indVarSimplify: LLVMAddIndVarSimplifyPass,
216+
.instructionCombining: LLVMAddInstructionCombiningPass,
217+
.jumpThreading: LLVMAddJumpThreadingPass,
218+
.licm: LLVMAddLICMPass,
219+
.loopDeletion: LLVMAddLoopDeletionPass,
220+
.loopIdiom: LLVMAddLoopIdiomPass,
221+
.loopRotate: LLVMAddLoopRotatePass,
222+
.loopReroll: LLVMAddLoopRerollPass,
223+
.loopUnroll: LLVMAddLoopUnrollPass,
224+
.loopUnrollAndJam: LLVMAddLoopUnrollAndJamPass,
225+
.loopUnswitch: LLVMAddLoopUnswitchPass,
226+
.lowerAtomic: LLVMAddLowerAtomicPass,
227+
.memCpyOpt: LLVMAddMemCpyOptPass,
228+
.partiallyInlineLibCalls: LLVMAddPartiallyInlineLibCallsPass,
229+
.lowerSwitch: LLVMAddLowerSwitchPass,
230+
.promoteMemoryToRegister: LLVMAddPromoteMemoryToRegisterPass,
231+
.reassociate: LLVMAddReassociatePass,
232+
.sccp: LLVMAddSCCPPass,
233+
.scalarReplAggregates: LLVMAddScalarReplAggregatesPass,
234+
.scalarReplAggregatesSSA: LLVMAddScalarReplAggregatesPassSSA,
235+
.tailCallElimination: LLVMAddTailCallEliminationPass,
236+
.constantPropagation: LLVMAddConstantPropagationPass,
237+
.demoteMemoryToRegister: LLVMAddDemoteMemoryToRegisterPass,
238+
.verifier: LLVMAddVerifierPass,
239+
.correlatedValuePropagation: LLVMAddCorrelatedValuePropagationPass,
240+
.earlyCSE: LLVMAddEarlyCSEPass,
241+
.lowerExpectIntrinsic: LLVMAddLowerExpectIntrinsicPass,
242+
.typeBasedAliasAnalysis: LLVMAddTypeBasedAliasAnalysisPass,
243+
.scopedNoAliasAA: LLVMAddScopedNoAliasAAPass,
244+
.basicAliasAnalysis: LLVMAddBasicAliasAnalysisPass,
245+
.unifyFunctionExitNodes: LLVMAddUnifyFunctionExitNodesPass,
246+
.alwaysInliner: LLVMAddAlwaysInlinerPass,
247+
.argumentPromotion: LLVMAddArgumentPromotionPass,
248+
.constantMerge: LLVMAddConstantMergePass,
249+
.deadArgElimination: LLVMAddDeadArgEliminationPass,
250+
.functionAttrs: LLVMAddFunctionAttrsPass,
251+
.functionInlining: LLVMAddFunctionInliningPass,
252+
.globalDCE: LLVMAddGlobalDCEPass,
253+
.globalOptimizer: LLVMAddGlobalOptimizerPass,
254+
.ipConstantPropagation: LLVMAddIPConstantPropagationPass,
255+
.ipscc: LLVMAddIPSCCPPass,
256+
.pruneEH: LLVMAddPruneEHPass,
257+
.stripDeadPrototypes: LLVMAddStripDeadPrototypesPass,
258+
.stripSymbols: LLVMAddStripSymbolsPass,
259+
.loopVectorize: LLVMAddLoopVectorizePass,
260+
.slpVectorize: LLVMAddSLPVectorizePass,
261+
// .internalize: LLVMAddInternalizePass,
262+
// .sroaWithThreshhold: LLVMAddScalarReplAggregatesPassWithThreshold,
263+
]
264+
}
265+
266+
extension Pass {
267+
var isModulePass: Bool {
268+
switch self {
269+
case .stripSymbols,
270+
.stripDeadPrototypes,
271+
.constantMerge,
272+
.globalOptimizer,
273+
.globalDCE,
274+
.deadArgElimination,
275+
.ipConstantPropagation,
276+
.ipscc,
277+
.functionAttrs,
278+
.functionInlining:
279+
return true
280+
default:
281+
return false
282+
}
283+
}
284+
}

0 commit comments

Comments
 (0)