Skip to content

Commit b6cdc0a

Browse files
committedMay 25, 2019
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

+8-65
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

+284
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+
}
+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
import LLVM
2+
import XCTest
3+
import FileCheck
4+
import Foundation
5+
6+
class IRPassManagerSpec : XCTestCase {
7+
func testEmptyPassPipeliner() {
8+
let module = Module(name: "Test")
9+
let pipeliner = PassPipeliner(module: module)
10+
XCTAssertTrue(pipeliner.stages.isEmpty)
11+
}
12+
13+
func testAppendStages() {
14+
let module = Module(name: "Test")
15+
let pipeliner = PassPipeliner(module: module)
16+
XCTAssertTrue(pipeliner.stages.isEmpty)
17+
var rng = SystemRandomNumberGenerator()
18+
let stageCount = (rng.next() % 25)
19+
for i in 0..<stageCount {
20+
pipeliner.addStage("stage \(i)") { p in }
21+
}
22+
23+
XCTAssertEqual(pipeliner.stages.count, Int(stageCount))
24+
}
25+
26+
func testAppendStandardStages() {
27+
let module = Module(name: "Test")
28+
let pipeliner = PassPipeliner(module: module)
29+
XCTAssertTrue(pipeliner.stages.isEmpty)
30+
for i in 0...3 {
31+
let optLevel: CodeGenOptLevel
32+
switch i {
33+
case 0:
34+
optLevel = .none
35+
case 1:
36+
optLevel = .less
37+
case 2:
38+
optLevel = .`default`
39+
case 3:
40+
optLevel = .aggressive
41+
default:
42+
fatalError()
43+
}
44+
for j in 0...3 {
45+
let sizeLevel: CodeGenOptLevel
46+
switch i {
47+
case 0:
48+
sizeLevel = .none
49+
case 1:
50+
sizeLevel = .less
51+
case 2:
52+
sizeLevel = .`default`
53+
case 3:
54+
sizeLevel = .aggressive
55+
default:
56+
fatalError()
57+
}
58+
pipeliner.addStandardModulePipeline("Opt \(i) Size \(j)", optimization: optLevel, size: sizeLevel)
59+
}
60+
}
61+
62+
XCTAssertEqual(pipeliner.stages.count, 4 * 4)
63+
64+
for i in 0...3 {
65+
let optLevel: CodeGenOptLevel
66+
switch i {
67+
case 0:
68+
optLevel = .none
69+
case 1:
70+
optLevel = .less
71+
case 2:
72+
optLevel = .`default`
73+
case 3:
74+
optLevel = .aggressive
75+
default:
76+
fatalError()
77+
}
78+
for j in 0...3 {
79+
let sizeLevel: CodeGenOptLevel
80+
switch i {
81+
case 0:
82+
sizeLevel = .none
83+
case 1:
84+
sizeLevel = .less
85+
case 2:
86+
sizeLevel = .`default`
87+
case 3:
88+
sizeLevel = .aggressive
89+
default:
90+
fatalError()
91+
}
92+
pipeliner.addStandardFunctionPipeline("Opt \(i) Size \(j)", optimization: optLevel, size: sizeLevel)
93+
}
94+
}
95+
96+
XCTAssertEqual(pipeliner.stages.count, (4 * 4) + (4 * 4))
97+
}
98+
99+
func testExecute() {
100+
let module = self.createModule()
101+
let pipeliner = PassPipeliner(module: module)
102+
103+
pipeliner.addStandardFunctionPipeline("Standard", optimization: .aggressive)
104+
pipeliner.addStandardModulePipeline("Module", optimization: .aggressive)
105+
106+
XCTAssertTrue(fileCheckOutput(of: .stderr, withPrefixes: [ "CHECK-EXECUTE-STDOPT" ]) {
107+
module.dump()
108+
109+
// CHECK-EXECUTE-STDOPT: ; ModuleID = 'Test'
110+
// CHECK-EXECUTE-STDOPT: source_filename = "Test"
111+
112+
// CHECK-EXECUTE-STDOPT: define i32 @fun(i32, i32) {
113+
// CHECK-EXECUTE-STDOPT: entry:
114+
// CHECK-EXECUTE-STDOPT: %2 = alloca i32, align 4
115+
// CHECK-EXECUTE-STDOPT: %3 = alloca i32, align 4
116+
// CHECK-EXECUTE-STDOPT: %4 = alloca i32, align 4
117+
// CHECK-EXECUTE-STDOPT: store i32 %0, i32* %2
118+
// CHECK-EXECUTE-STDOPT: store i32 %1, i32* %3
119+
// CHECK-EXECUTE-STDOPT: store i32 4, i32* %4
120+
// CHECK-EXECUTE-STDOPT: %5 = load i32, i32* %2, align 4
121+
// CHECK-EXECUTE-STDOPT: %6 = icmp eq i32 %5, 1
122+
// CHECK-EXECUTE-STDOPT: br i1 %6, label %block1, label %block2
123+
124+
// CHECK-EXECUTE-STDOPT: block1:
125+
// CHECK-EXECUTE-STDOPT: %7 = load i32, i32* %2, align 4
126+
// CHECK-EXECUTE-STDOPT: %8 = load i32, i32* %4, align 4
127+
// CHECK-EXECUTE-STDOPT: %9 = add nsw i32 %7, %8
128+
// CHECK-EXECUTE-STDOPT: store i32 %9, i32* %4
129+
// CHECK-EXECUTE-STDOPT: br label %merge
130+
131+
// CHECK-EXECUTE-STDOPT: block2:
132+
// CHECK-EXECUTE-STDOPT: %10 = load i32, i32* %3, align 4
133+
// CHECK-EXECUTE-STDOPT: %11 = load i32, i32* %4, align 4
134+
// CHECK-EXECUTE-STDOPT: %12 = add nsw i32 %10, %11
135+
// CHECK-EXECUTE-STDOPT: store i32 %12, i32* %4
136+
// CHECK-EXECUTE-STDOPT: br label %merge
137+
138+
// CHECK-EXECUTE-STDOPT: merge:
139+
// CHECK-EXECUTE-STDOPT: %13 = load i32, i32* %4, align 4
140+
// CHECK-EXECUTE-STDOPT: ret i32 %13
141+
// CHECK-EXECUTE-STDOPT }
142+
143+
pipeliner.execute()
144+
145+
module.dump()
146+
147+
// CHECK-EXECUTE-STDOPT: ; ModuleID = 'Test'
148+
// CHECK-EXECUTE-STDOPT: source_filename = "Test"
149+
150+
// CHECK-EXECUTE-STDOPT: ; Function Attrs: norecurse nounwind readnone
151+
// CHECK-EXECUTE-STDOPT: define i32 @fun(i32, i32) local_unnamed_addr #0 {
152+
// CHECK-EXECUTE-STDOPT: entry:
153+
// CHECK-EXECUTE-STDOPT: %2 = icmp eq i32 %0, 1
154+
// CHECK-EXECUTE-STDOPT: %3 = add nsw i32 %1, 4
155+
// CHECK-EXECUTE-STDOPT: %.0 = select i1 %2, i32 5, i32 %3
156+
// CHECK-EXECUTE-STDOPT: ret i32 %.0
157+
// CHECK-EXECUTE-STDOPT: }
158+
})
159+
}
160+
161+
private func createModule() -> Module {
162+
let module = Module(name: "Test")
163+
164+
let builder = IRBuilder(module: module)
165+
let fun = builder.addFunction("fun",
166+
type: FunctionType([
167+
IntType.int32,
168+
IntType.int32,
169+
], IntType.int32))
170+
let entry = fun.appendBasicBlock(named: "entry")
171+
let block1 = fun.appendBasicBlock(named: "block1")
172+
let block2 = fun.appendBasicBlock(named: "block2")
173+
let merge = fun.appendBasicBlock(named: "merge")
174+
175+
builder.positionAtEnd(of: entry)
176+
let val1 = builder.buildAlloca(type: IntType.int32, alignment: Alignment(4))
177+
let val2 = builder.buildAlloca(type: IntType.int32, alignment: Alignment(4))
178+
let val3 = builder.buildAlloca(type: IntType.int32, alignment: Alignment(4))
179+
builder.buildStore(fun.parameters[0], to: val1)
180+
builder.buildStore(fun.parameters[1], to: val2)
181+
builder.buildStore(IntType.int32.constant(4), to: val3)
182+
let reloadVal1 = builder.buildLoad(val1, alignment: Alignment(4))
183+
let cmpVal = builder.buildICmp(reloadVal1, IntType.int32.constant(1), .equal)
184+
builder.buildCondBr(condition: cmpVal, then: block1, else: block2)
185+
186+
builder.positionAtEnd(of: block1)
187+
let reloadVal2 = builder.buildLoad(val1, alignment: Alignment(4))
188+
let reloadVal3 = builder.buildLoad(val3, alignment: Alignment(4))
189+
let sum1 = builder.buildAdd(reloadVal2, reloadVal3, overflowBehavior: .noSignedWrap)
190+
builder.buildStore(sum1, to: val3)
191+
builder.buildBr(merge)
192+
193+
builder.positionAtEnd(of: block2)
194+
let reloadVal4 = builder.buildLoad(val2, alignment: Alignment(4))
195+
let reloadVal5 = builder.buildLoad(val3, alignment: Alignment(4))
196+
let sum2 = builder.buildAdd(reloadVal4, reloadVal5, overflowBehavior: .noSignedWrap)
197+
builder.buildStore(sum2, to: val3)
198+
builder.buildBr(merge)
199+
200+
builder.positionAtEnd(of: merge)
201+
let reloadVal6 = builder.buildLoad(val3, alignment: Alignment(4))
202+
builder.buildRet(reloadVal6)
203+
204+
return module
205+
}
206+
207+
#if !os(macOS)
208+
static var allTests = testCase([
209+
("testEmptyPassPipeliner", testEmptyPassPipeliner),
210+
("testAppendStages", testAppendStages),
211+
("testAppendStandardStages", testAppendStandardStages),
212+
("testExecute", testExecute),
213+
])
214+
#endif
215+
}

‎Tests/LinuxMain.swift

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ XCTMain([
1717
IRInstructionSpec.allTests,
1818
IRMetadataSpec.allTests,
1919
IROperationSpec.allTests,
20+
IRPassManagerSpec.allTests,
2021
JITSpec.allTests,
2122
ModuleLinkSpec.allTests,
2223
ModuleMetadataSpec.allTests,

0 commit comments

Comments
 (0)
Please sign in to comment.