Skip to content

Commit 87f2f41

Browse files
committed
Swift Optimizer: add infrastructure for module passes.
To add a module pass in `Passes.def` use the new `SWIFT_MODULE_PASS` macro. On the swift side, create a `ModulePass`. It’s run function receives a `ModulePassContext`, which provides access to all functions of a module. But it doesn't provide any APIs to modify functions. In order to modify a function, a module pass must use `ModulePassContext.transform(function:)`.
1 parent 7b9b97f commit 87f2f41

File tree

9 files changed

+199
-4
lines changed

9 files changed

+199
-4
lines changed

SwiftCompilerSources/Sources/Optimizer/PassManager/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
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+
ModulePassContext.swift
1011
Passes.swift
1112
PassContext.swift
1213
PassRegistration.swift)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===--- ModulePassContext.swift ------------------------------------------===//
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+
/// The context which is passed to a `ModulePass`'s run-function.
17+
///
18+
/// It provides access to all functions of a module, but it doesn't provide any
19+
/// APIs to modify functions.
20+
/// In order to modify a function, a module pass must use `transform(function:)`.
21+
struct ModulePassContext {
22+
let _bridged: BridgedPassContext
23+
24+
struct FunctionList : CollectionLikeSequence, IteratorProtocol {
25+
private var currentFunction: Function?
26+
27+
fileprivate init(first: Function?) { currentFunction = first }
28+
29+
mutating func next() -> Function? {
30+
if let f = currentFunction {
31+
currentFunction = PassContext_nextFunctionInModule(f.bridged).function
32+
return f
33+
}
34+
return nil
35+
}
36+
}
37+
38+
var functions: FunctionList {
39+
FunctionList(first: PassContext_firstFunctionInModule(_bridged).function)
40+
}
41+
42+
/// Run a closure with a `PassContext` for a function, which allows to modify that function.
43+
///
44+
/// Only a single `transform` can be alive at the same time, i.e. it's not allowed to nest
45+
/// calls to `transform`.
46+
func transform(function: Function, _ runOnFunction: (PassContext) -> ()) {
47+
PassContext_beginTransformFunction(function.bridged, _bridged)
48+
runOnFunction(PassContext(_bridged: _bridged))
49+
PassContext_endTransformFunction(_bridged);
50+
}
51+
}

SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ public func initializeSwiftModules() {
2121
initializeSwiftParseModules()
2222
}
2323

24+
private func registerPass(
25+
_ pass: ModulePass,
26+
_ runFn: @escaping (@convention(c) (BridgedPassContext) -> ())) {
27+
pass.name._withStringRef { nameStr in
28+
SILPassManager_registerModulePass(nameStr, runFn)
29+
}
30+
}
31+
2432
private func registerPass(
2533
_ pass: FunctionPass,
2634
_ runFn: @escaping (@convention(c) (BridgedFunctionPassCtxt) -> ())) {

SwiftCompilerSources/Sources/Optimizer/PassManager/Passes.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212
import SIL
13+
import OptimizerBridging
1314

1415
struct FunctionPass {
1516

@@ -47,3 +48,19 @@ struct InstructionPass<InstType: Instruction> {
4748
}
4849
}
4950

51+
struct ModulePass {
52+
53+
let name: String
54+
let runFunction: (ModulePassContext) -> ()
55+
56+
public init(name: String,
57+
_ runFunction: @escaping (ModulePassContext) -> ()) {
58+
self.name = name
59+
self.runFunction = runFunction
60+
}
61+
62+
func run(_ bridgedCtxt: BridgedPassContext) {
63+
let context = ModulePassContext(_bridged: bridgedCtxt)
64+
runFunction(context)
65+
}
66+
}

include/swift/SILOptimizer/OptimizerBridging.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,14 @@ typedef struct {
7777
void * _Nonnull functionInfo;
7878
} BridgedRCIdentityFunctionInfo;
7979

80+
typedef void (* _Nonnull BridgedModulePassRunFn)(BridgedPassContext);
8081
typedef void (* _Nonnull BridgedFunctionPassRunFn)(BridgedFunctionPassCtxt);
8182
typedef void (* _Nonnull BridgedInstructionPassRunFn)(BridgedInstructionPassCtxt);
8283

84+
void SILPassManager_registerModulePass(llvm::StringRef name,
85+
BridgedModulePassRunFn runFn);
8386
void SILPassManager_registerFunctionPass(llvm::StringRef name,
8487
BridgedFunctionPassRunFn runFn);
85-
8688
void SILCombine_registerInstructionPass(llvm::StringRef name,
8789
BridgedInstructionPassRunFn runFn);
8890

@@ -156,6 +158,15 @@ BridgedSubstitutionMap
156158
PassContext_getContextSubstitutionMap(BridgedPassContext context,
157159
BridgedType bridgedType);
158160

161+
void PassContext_beginTransformFunction(BridgedFunction function,
162+
BridgedPassContext ctxt);
163+
void PassContext_endTransformFunction(BridgedPassContext ctxt);
164+
165+
OptionalBridgedFunction
166+
PassContext_firstFunctionInModule(BridgedPassContext context);
167+
OptionalBridgedFunction
168+
PassContext_nextFunctionInModule(BridgedFunction function);
169+
159170
OptionalBridgedFunction
160171
PassContext_loadFunction(BridgedPassContext context, llvm::StringRef name);
161172

include/swift/SILOptimizer/PassManager/PassManager.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,17 +108,35 @@ class SwiftPassInvocation {
108108
/// Called by the pass when changes are made to the SIL.
109109
void notifyChanges(SILAnalysis::InvalidationKind invalidationKind);
110110

111+
/// Called by the pass manager before the pass starts running.
112+
void startModulePassRun(SILModuleTransform *transform);
113+
111114
/// Called by the pass manager before the pass starts running.
112115
void startFunctionPassRun(SILFunctionTransform *transform);
113116

114117
/// Called by the SILCombiner before the instruction pass starts running.
115118
void startInstructionPassRun(SILInstruction *inst);
116119

120+
/// Called by the pass manager when the pass has finished.
121+
void finishedModulePassRun();
122+
117123
/// Called by the pass manager when the pass has finished.
118124
void finishedFunctionPassRun();
119125

120126
/// Called by the SILCombiner when the instruction pass has finished.
121127
void finishedInstructionPassRun();
128+
129+
void beginTransformFunction(SILFunction *function) {
130+
assert(!this->function && transform && "not running a module pass");
131+
this->function = function;
132+
}
133+
134+
void endTransformFunction() {
135+
assert(function && "beginTransformFunction not called");
136+
function = nullptr;
137+
assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated");
138+
assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated");
139+
}
122140
};
123141

124142
/// The SIL pass manager.

include/swift/SILOptimizer/PassManager/Passes.def

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,17 @@
4343
#define IRGEN_PASS(Id, Tag, Description) PASS(Id, Tag, Description)
4444
#endif
4545

46+
/// SWIFT_MODULE_PASS(Id, Tag, Description)
47+
/// This macro follows the same conventions as PASS(Id, Tag, Description),
48+
/// but is used for module passes which are implemented in Swift.
49+
///
50+
/// No further code is need on the C++ side. On the swift swift a module
51+
/// pass with the same name must be registered with 'registerPass()'.
52+
///
53+
#ifndef SWIFT_MODULE_PASS
54+
#define SWIFT_MODULE_PASS(Id, Tag, Description) PASS(Id, Tag, Description)
55+
#endif
56+
4657
/// SWIFT_FUNCTION_PASS(Id, Tag, Description)
4758
/// This macro follows the same conventions as PASS(Id, Tag, Description),
4859
/// but is used for function passes which are implemented in Swift.
@@ -468,6 +479,7 @@ SWIFT_INSTRUCTION_PASS_WITH_LEGACY(StrongRetainInst, "simplify-strong_retain")
468479
SWIFT_INSTRUCTION_PASS_WITH_LEGACY(StrongReleaseInst, "simplify-strong_release")
469480

470481
#undef IRGEN_PASS
482+
#undef SWIFT_MODULE_PASS
471483
#undef SWIFT_FUNCTION_PASS
472484
#undef SWIFT_FUNCTION_PASS_WITH_LEGACY
473485
#undef SWIFT_INSTRUCTION_PASS

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,11 +727,14 @@ void SILPassManager::runModulePass(unsigned TransIdx) {
727727
verifyAnalyses();
728728
}
729729

730+
swiftPassInvocation.startModulePassRun(SMT);
731+
730732
llvm::sys::TimePoint<> StartTime = std::chrono::system_clock::now();
731733
assert(analysesUnlocked() && "Expected all analyses to be unlocked!");
732734
SMT->run();
733735
assert(analysesUnlocked() && "Expected all analyses to be unlocked!");
734736
Mod->flushDeletedInsts();
737+
swiftPassInvocation.finishedModulePassRun();
735738

736739
std::chrono::nanoseconds duration = std::chrono::system_clock::now() - StartTime;
737740
totalPassRuntime += duration;
@@ -1279,6 +1282,12 @@ void SwiftPassInvocation::freeNodeSet(NodeSet *set) {
12791282
}
12801283
}
12811284

1285+
void SwiftPassInvocation::startModulePassRun(SILModuleTransform *transform) {
1286+
assert(!this->function && !this->transform && "a pass is already running");
1287+
this->function = nullptr;
1288+
this->transform = transform;
1289+
}
1290+
12821291
void SwiftPassInvocation::startFunctionPassRun(SILFunctionTransform *transform) {
12831292
assert(!this->function && !this->transform && "a pass is already running");
12841293
this->function = transform->getFunction();
@@ -1290,6 +1299,12 @@ void SwiftPassInvocation::startInstructionPassRun(SILInstruction *inst) {
12901299
"running instruction pass on wrong function");
12911300
}
12921301

1302+
void SwiftPassInvocation::finishedModulePassRun() {
1303+
endPassRunChecks();
1304+
assert(!function && transform && "not running a pass");
1305+
transform = nullptr;
1306+
}
1307+
12931308
void SwiftPassInvocation::finishedFunctionPassRun() {
12941309
endPassRunChecks();
12951310
assert(function && transform && "not running a pass");
@@ -1533,6 +1548,31 @@ PassContext_getContextSubstitutionMap(BridgedPassContext context,
15331548
return {type.getASTType()->getContextSubstitutionMap(m, ntd).getOpaqueValue()};
15341549
}
15351550

1551+
void PassContext_beginTransformFunction(BridgedFunction function, BridgedPassContext ctxt) {
1552+
castToPassInvocation(ctxt)->beginTransformFunction(castToFunction(function));
1553+
}
1554+
1555+
void PassContext_endTransformFunction(BridgedPassContext ctxt) {
1556+
castToPassInvocation(ctxt)->endTransformFunction();
1557+
}
1558+
1559+
OptionalBridgedFunction
1560+
PassContext_firstFunctionInModule(BridgedPassContext context) {
1561+
SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule();
1562+
if (mod->getFunctions().empty())
1563+
return {nullptr};
1564+
return {&*mod->getFunctions().begin()};
1565+
}
1566+
1567+
OptionalBridgedFunction
1568+
PassContext_nextFunctionInModule(BridgedFunction function) {
1569+
auto *f = castToFunction(function);
1570+
auto nextIter = std::next(f->getIterator());
1571+
if (nextIter == f->getModule().getFunctions().end())
1572+
return {nullptr};
1573+
return {&*nextIter};
1574+
}
1575+
15361576
OptionalBridgedFunction
15371577
PassContext_loadFunction(BridgedPassContext context, StringRef name) {
15381578
SILModule *mod = castToPassInvocation(context)->getPassManager()->getModule();

lib/SILOptimizer/PassManager/Passes.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,30 @@ void swift::runSILLoweringPasses(SILModule &Module) {
217217
}
218218

219219
/// Registered briged pass run functions.
220-
static llvm::StringMap<BridgedFunctionPassRunFn> bridgedPassRunFunctions;
220+
static llvm::StringMap<BridgedModulePassRunFn> bridgedModulePassRunFunctions;
221+
static llvm::StringMap<BridgedFunctionPassRunFn> bridgedFunctionPassRunFunctions;
221222
static bool passesRegistered = false;
222223

224+
/// Runs a bridged module pass.
225+
///
226+
/// \p runFunction is a cache for the run function, so that it has to be looked
227+
/// up only once in bridgedPassRunFunctions.
228+
static void runBridgedModulePass(BridgedModulePassRunFn &runFunction,
229+
SILPassManager *passManager,
230+
StringRef passName) {
231+
if (!runFunction) {
232+
runFunction = bridgedModulePassRunFunctions[passName];
233+
if (!runFunction) {
234+
if (passesRegistered) {
235+
llvm::errs() << "Swift pass " << passName << " is not registered\n";
236+
abort();
237+
}
238+
return;
239+
}
240+
}
241+
runFunction({passManager->getSwiftPassInvocation()});
242+
}
243+
223244
/// Runs a bridged function pass.
224245
///
225246
/// \p runFunction is a cache for the run function, so that it has to be looked
@@ -228,7 +249,7 @@ static void runBridgedFunctionPass(BridgedFunctionPassRunFn &runFunction,
228249
SILPassManager *passManager,
229250
SILFunction *f, StringRef passName) {
230251
if (!runFunction) {
231-
runFunction = bridgedPassRunFunctions[passName];
252+
runFunction = bridgedFunctionPassRunFunctions[passName];
232253
if (!runFunction) {
233254
if (passesRegistered) {
234255
llvm::errs() << "Swift pass " << passName << " is not registered\n";
@@ -245,9 +266,15 @@ static void runBridgedFunctionPass(BridgedFunctionPassRunFn &runFunction,
245266
}
246267

247268
// Called from initializeSwiftModules().
269+
void SILPassManager_registerModulePass(llvm::StringRef name,
270+
BridgedModulePassRunFn runFn) {
271+
bridgedModulePassRunFunctions[name] = runFn;
272+
passesRegistered = true;
273+
}
274+
248275
void SILPassManager_registerFunctionPass(llvm::StringRef name,
249276
BridgedFunctionPassRunFn runFn) {
250-
bridgedPassRunFunctions[name] = runFn;
277+
bridgedFunctionPassRunFunctions[name] = runFn;
251278
passesRegistered = true;
252279
}
253280

@@ -263,6 +290,16 @@ BridgedFunctionPassRunFn ID##Pass::runFunction = nullptr; \
263290
#define PASS(ID, TAG, DESCRIPTION)
264291
#define SWIFT_INSTRUCTION_PASS(INST, TAG)
265292

293+
#define SWIFT_MODULE_PASS(ID, TAG, DESCRIPTION) \
294+
class ID##Pass : public SILModuleTransform { \
295+
static BridgedModulePassRunFn runFunction; \
296+
void run() override { \
297+
runBridgedModulePass(runFunction, PM, TAG); \
298+
} \
299+
}; \
300+
BridgedModulePassRunFn ID##Pass::runFunction = nullptr; \
301+
SILTransform *swift::create##ID() { return new ID##Pass(); } \
302+
266303
#define SWIFT_FUNCTION_PASS(ID, TAG, DESCRIPTION) \
267304
SWIFT_FUNCTION_PASS_COMMON(ID, TAG) \
268305
SILTransform *swift::create##ID() { return new ID##Pass(); } \

0 commit comments

Comments
 (0)