Skip to content

Commit 10dd489

Browse files
committed
Redo the pass configuration infrastructure
This finally allows us to wrap passes that require additional parameters or configuration calls. In order to do this for internalize in particular, we have to do some heroic lifetime juggling.
1 parent 913df8b commit 10dd489

File tree

1 file changed

+192
-60
lines changed

1 file changed

+192
-60
lines changed

Sources/LLVM/PassPipeliner.swift

Lines changed: 192 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#if SWIFT_PACKAGE
22
import cllvm
3+
import llvmshims
34
#endif
45

56
/// Implements a pass manager, pipeliner, and executor for a set of
@@ -125,10 +126,11 @@ public final class PassPipeliner {
125126
}
126127

127128
private func runFunctionPasses(_ passes: [Pass], _ pm: LLVMPassManagerRef) {
129+
var keepalive = [Any]()
128130
LLVMInitializeFunctionPassManager(pm)
129131

130132
for pass in passes {
131-
PassPipeliner.passMapping[pass]!(pm)
133+
PassPipeliner.configurePass(pass, passManager: pm, keepalive: &keepalive)
132134
}
133135

134136
for function in self.module.functions {
@@ -137,9 +139,10 @@ public final class PassPipeliner {
137139
}
138140

139141
private func runPasses(_ passes: [Pass]) {
142+
var keepalive = [Any]()
140143
let pm = LLVMCreatePassManager()!
141144
for pass in passes {
142-
PassPipeliner.passMapping[pass]!(pm)
145+
PassPipeliner.configurePass(pass, passManager: pm, keepalive: &keepalive)
143146
}
144147
LLVMRunPassManager(pm, self.module.llvm)
145148
LLVMDisposePassManager(pm)
@@ -149,6 +152,15 @@ public final class PassPipeliner {
149152
// MARK: Standard Pass Pipelines
150153

151154
extension PassPipeliner {
155+
/// Adds a pipeline stage populated with function passes that LLVM considers
156+
/// standard for languages like C and C++. Additional parameters are
157+
/// available to tune the overall behavior of the optimization pipeline at a
158+
/// macro level.
159+
///
160+
/// - Parameters:
161+
/// - name: The name of the pipeline stage.
162+
/// - optimization: The level of optimization.
163+
/// - size: The level of size optimization.
152164
public func addStandardFunctionPipeline(
153165
_ name: String,
154166
optimization: CodeGenOptLevel = .`default`,
@@ -164,6 +176,15 @@ extension PassPipeliner {
164176
self.stageMapping[name] = .functionPassManager(functionPasses)
165177
}
166178

179+
/// Adds a pipeline stage populated with module passes that LLVM considers
180+
/// standard for languages like C and C++. Additional parameters are
181+
/// available to tune the overall behavior of the optimization pipeline at a
182+
/// macro level.
183+
///
184+
/// - Parameters:
185+
/// - name: The name of the pipeline stage.
186+
/// - optimization: The level of optimization.
187+
/// - size: The level of size optimization.
167188
public func addStandardModulePipeline(
168189
_ name: String,
169190
optimization: CodeGenOptLevel = .`default`,
@@ -210,62 +231,173 @@ extension PassPipeliner {
210231

211232

212233
extension PassPipeliner {
213-
static let passMapping: [Pass: (LLVMPassManagerRef) -> Void] = [
214-
.aggressiveDCE: LLVMAddAggressiveDCEPass,
215-
.bitTrackingDCE: LLVMAddBitTrackingDCEPass,
216-
.alignmentFromAssumptions: LLVMAddAlignmentFromAssumptionsPass,
217-
.cfgSimplification: LLVMAddCFGSimplificationPass,
218-
.deadStoreElimination: LLVMAddDeadStoreEliminationPass,
219-
.scalarizer: LLVMAddScalarizerPass,
220-
.mergedLoadStoreMotion: LLVMAddMergedLoadStoreMotionPass,
221-
.gvn: LLVMAddGVNPass,
222-
.indVarSimplify: LLVMAddIndVarSimplifyPass,
223-
.instructionCombining: LLVMAddInstructionCombiningPass,
224-
.jumpThreading: LLVMAddJumpThreadingPass,
225-
.licm: LLVMAddLICMPass,
226-
.loopDeletion: LLVMAddLoopDeletionPass,
227-
.loopIdiom: LLVMAddLoopIdiomPass,
228-
.loopRotate: LLVMAddLoopRotatePass,
229-
.loopReroll: LLVMAddLoopRerollPass,
230-
.loopUnroll: LLVMAddLoopUnrollPass,
231-
.loopUnrollAndJam: LLVMAddLoopUnrollAndJamPass,
232-
.loopUnswitch: LLVMAddLoopUnswitchPass,
233-
.lowerAtomic: LLVMAddLowerAtomicPass,
234-
.memCpyOpt: LLVMAddMemCpyOptPass,
235-
.partiallyInlineLibCalls: LLVMAddPartiallyInlineLibCallsPass,
236-
.lowerSwitch: LLVMAddLowerSwitchPass,
237-
.promoteMemoryToRegister: LLVMAddPromoteMemoryToRegisterPass,
238-
.reassociate: LLVMAddReassociatePass,
239-
.sccp: LLVMAddSCCPPass,
240-
.scalarReplAggregates: LLVMAddScalarReplAggregatesPass,
241-
.scalarReplAggregatesSSA: LLVMAddScalarReplAggregatesPassSSA,
242-
.tailCallElimination: LLVMAddTailCallEliminationPass,
243-
.constantPropagation: LLVMAddConstantPropagationPass,
244-
.demoteMemoryToRegister: LLVMAddDemoteMemoryToRegisterPass,
245-
.verifier: LLVMAddVerifierPass,
246-
.correlatedValuePropagation: LLVMAddCorrelatedValuePropagationPass,
247-
.earlyCSE: LLVMAddEarlyCSEPass,
248-
.lowerExpectIntrinsic: LLVMAddLowerExpectIntrinsicPass,
249-
.typeBasedAliasAnalysis: LLVMAddTypeBasedAliasAnalysisPass,
250-
.scopedNoAliasAA: LLVMAddScopedNoAliasAAPass,
251-
.basicAliasAnalysis: LLVMAddBasicAliasAnalysisPass,
252-
.unifyFunctionExitNodes: LLVMAddUnifyFunctionExitNodesPass,
253-
.alwaysInliner: LLVMAddAlwaysInlinerPass,
254-
.argumentPromotion: LLVMAddArgumentPromotionPass,
255-
.constantMerge: LLVMAddConstantMergePass,
256-
.deadArgElimination: LLVMAddDeadArgEliminationPass,
257-
.functionAttrs: LLVMAddFunctionAttrsPass,
258-
.functionInlining: LLVMAddFunctionInliningPass,
259-
.globalDCE: LLVMAddGlobalDCEPass,
260-
.globalOptimizer: LLVMAddGlobalOptimizerPass,
261-
.ipConstantPropagation: LLVMAddIPConstantPropagationPass,
262-
.ipscc: LLVMAddIPSCCPPass,
263-
.pruneEH: LLVMAddPruneEHPass,
264-
.stripDeadPrototypes: LLVMAddStripDeadPrototypesPass,
265-
.stripSymbols: LLVMAddStripSymbolsPass,
266-
.loopVectorize: LLVMAddLoopVectorizePass,
267-
.slpVectorize: LLVMAddSLPVectorizePass,
268-
// .internalize: LLVMAddInternalizePass,
269-
// .sroaWithThreshhold: LLVMAddScalarReplAggregatesPassWithThreshold,
270-
]
234+
/// Configures and adds a pass to the given pass manager.
235+
///
236+
/// - Parameters:
237+
/// - pass: The pass to add to the pass manager.
238+
/// - passManager: The pass manager to which to add a pass.
239+
/// - keepalive: An array that must stay alive for as long as this pass
240+
/// manager stays alive. This array will keep Swift objects
241+
/// that may be passed into closures that will use them at
242+
/// any point in the pass execution line.
243+
static func configurePass(
244+
_ pass: Pass,
245+
passManager: LLVMPassManagerRef,
246+
keepalive: inout [Any]) {
247+
switch pass {
248+
case .invalid(let reason):
249+
fatalError("Cannot configure pass: \(reason)")
250+
case .aggressiveDCE:
251+
LLVMAddAggressiveDCEPass(passManager)
252+
case .bitTrackingDCE:
253+
LLVMAddBitTrackingDCEPass(passManager)
254+
case .alignmentFromAssumptions:
255+
LLVMAddAlignmentFromAssumptionsPass(passManager)
256+
case .cfgSimplification:
257+
LLVMAddCFGSimplificationPass(passManager)
258+
case .deadStoreElimination:
259+
LLVMAddDeadStoreEliminationPass(passManager)
260+
case .scalarizer:
261+
LLVMAddScalarizerPass(passManager)
262+
case .mergedLoadStoreMotion:
263+
LLVMAddMergedLoadStoreMotionPass(passManager)
264+
case .gvn:
265+
LLVMAddGVNPass(passManager)
266+
case .indVarSimplify:
267+
LLVMAddIndVarSimplifyPass(passManager)
268+
case .instructionCombining:
269+
LLVMAddInstructionCombiningPass(passManager)
270+
case .jumpThreading:
271+
LLVMAddJumpThreadingPass(passManager)
272+
case .licm:
273+
LLVMAddLICMPass(passManager)
274+
case .loopDeletion:
275+
LLVMAddLoopDeletionPass(passManager)
276+
case .loopIdiom:
277+
LLVMAddLoopIdiomPass(passManager)
278+
case .loopRotate:
279+
LLVMAddLoopRotatePass(passManager)
280+
case .loopReroll:
281+
LLVMAddLoopRerollPass(passManager)
282+
case .loopUnroll:
283+
LLVMAddLoopUnrollPass(passManager)
284+
case .loopUnrollAndJam:
285+
LLVMAddLoopUnrollAndJamPass(passManager)
286+
case .loopUnswitch:
287+
LLVMAddLoopUnswitchPass(passManager)
288+
case .lowerAtomic:
289+
LLVMAddLowerAtomicPass(passManager)
290+
case .memCpyOpt:
291+
LLVMAddMemCpyOptPass(passManager)
292+
case .partiallyInlineLibCalls:
293+
LLVMAddPartiallyInlineLibCallsPass(passManager)
294+
case .lowerSwitch:
295+
LLVMAddLowerSwitchPass(passManager)
296+
case .promoteMemoryToRegister:
297+
LLVMAddPromoteMemoryToRegisterPass(passManager)
298+
case .addDiscriminators:
299+
LLVMAddAddDiscriminatorsPass(passManager)
300+
case .reassociate:
301+
LLVMAddReassociatePass(passManager)
302+
case .sccp:
303+
LLVMAddSCCPPass(passManager)
304+
case .tailCallElimination:
305+
LLVMAddTailCallEliminationPass(passManager)
306+
case .constantPropagation:
307+
LLVMAddConstantPropagationPass(passManager)
308+
case .demoteMemoryToRegister:
309+
LLVMAddDemoteMemoryToRegisterPass(passManager)
310+
case .verifier:
311+
LLVMAddVerifierPass(passManager)
312+
case .correlatedValuePropagation:
313+
LLVMAddCorrelatedValuePropagationPass(passManager)
314+
case .earlyCSE:
315+
LLVMAddEarlyCSEPass(passManager)
316+
case .lowerExpectIntrinsic:
317+
LLVMAddLowerExpectIntrinsicPass(passManager)
318+
case .typeBasedAliasAnalysis:
319+
LLVMAddTypeBasedAliasAnalysisPass(passManager)
320+
case .scopedNoAliasAA:
321+
LLVMAddScopedNoAliasAAPass(passManager)
322+
case .basicAliasAnalysis:
323+
LLVMAddBasicAliasAnalysisPass(passManager)
324+
case .unifyFunctionExitNodes:
325+
LLVMAddUnifyFunctionExitNodesPass(passManager)
326+
case .alwaysInliner:
327+
LLVMAddAlwaysInlinerPass(passManager)
328+
case .argumentPromotion:
329+
LLVMAddArgumentPromotionPass(passManager)
330+
case .constantMerge:
331+
LLVMAddConstantMergePass(passManager)
332+
case .deadArgElimination:
333+
LLVMAddDeadArgEliminationPass(passManager)
334+
case .functionAttrs:
335+
LLVMAddFunctionAttrsPass(passManager)
336+
case .functionInlining:
337+
LLVMAddFunctionInliningPass(passManager)
338+
case .globalDCE:
339+
LLVMAddGlobalDCEPass(passManager)
340+
case .globalOptimizer:
341+
LLVMAddGlobalOptimizerPass(passManager)
342+
case .ipConstantPropagation:
343+
LLVMAddIPConstantPropagationPass(passManager)
344+
case .ipscc:
345+
LLVMAddIPSCCPPass(passManager)
346+
case .pruneEH:
347+
LLVMAddPruneEHPass(passManager)
348+
case .stripDeadPrototypes:
349+
LLVMAddStripDeadPrototypesPass(passManager)
350+
case .stripSymbols:
351+
LLVMAddStripSymbolsPass(passManager)
352+
case .loopVectorize:
353+
LLVMAddLoopVectorizePass(passManager)
354+
case .slpVectorize:
355+
LLVMAddSLPVectorizePass(passManager)
356+
case .internalizeAll(let preserveMain):
357+
LLVMAddInternalizePass(passManager, preserveMain == false ? 0 : 1)
358+
case .internalize(let pred):
359+
// The lifetime of this callback is must be manually managed to ensure
360+
// it remains alive across the execution of the given pass manager.
361+
362+
// Create a callback context at +1
363+
let callbackContext = InternalizeCallbackContext(pred)
364+
// Stick it in the keepalive array, now at +2
365+
keepalive.append(callbackContext)
366+
// Pass it unmanaged at +2
367+
let contextPtr = Unmanaged<InternalizeCallbackContext>.passUnretained(callbackContext).toOpaque()
368+
LLVMAddInternalizePassWithMustPreservePredicate(passManager, contextPtr) { globalValue, callbackCtx in
369+
guard let globalValue = globalValue, let callbackCtx = callbackCtx else {
370+
fatalError("Global value and context must be non-nil")
371+
}
372+
373+
let callback = Unmanaged<InternalizeCallbackContext>.fromOpaque(callbackCtx).takeUnretainedValue()
374+
return callback.block(realizeGlobalValue(globalValue)).llvm
375+
}
376+
// Context dropped, now at +1
377+
// When the keepalive array is dropped by the caller, it will drop to +0.
378+
case .scalarReplacementOfAggregates:
379+
LLVMAddScalarReplAggregatesPassWithThreshold(passManager, /*ignored*/ 0)
380+
}
381+
}
382+
}
383+
384+
private func realizeGlobalValue(_ llvm: LLVMValueRef) -> IRGlobal {
385+
precondition(llvm.isAGlobalValue, "must be a global value")
386+
if llvm.isAFunction {
387+
return Function(llvm: llvm)
388+
} else if llvm.isAGlobalAlias {
389+
return Alias(llvm: llvm)
390+
} else if llvm.isAGlobalVariable {
391+
return Global(llvm: llvm)
392+
} else {
393+
fatalError("unrecognized global value")
394+
}
395+
}
396+
397+
private class InternalizeCallbackContext {
398+
fileprivate let block: (IRGlobal) -> Bool
399+
400+
fileprivate init(_ block: @escaping (IRGlobal) -> Bool) {
401+
self.block = block
402+
}
271403
}

0 commit comments

Comments
 (0)