Skip to content

Commit 81f5e2f

Browse files
committed
libswift: Infrastructure to call libswift function passes from the SILOptimizer's PassManager
With the macro SWIFT_FUNCTION_PASS a new libswift function pass can be defined in Passes.def. The SWIFT_FUNCTION_PASS_WITH_LEGACY is similar, but it allows to keep an original C++ “legacy” implementation of the pass, which is used if the compiler is not built with libswift.
1 parent b82173e commit 81f5e2f

File tree

14 files changed

+345
-3
lines changed

14 files changed

+345
-3
lines changed

include/swift/SIL/SILBridging.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ enum ChangeNotificationKind {
4040
branchesChanged
4141
};
4242

43+
typedef struct {
44+
const void * _Nonnull opaqueCtxt;
45+
} BridgedPassContext;
46+
4347
typedef struct {
4448
void * _Null_unspecified word0;
4549
void * _Null_unspecified word1;
@@ -113,6 +117,11 @@ void registerBridgedClass(BridgedStringRef className, SwiftMetatype metatype);
113117

114118
void freeBridgedStringRef(BridgedStringRef str);
115119

120+
void PassContext_notifyChanges(BridgedPassContext passContext,
121+
enum ChangeNotificationKind changeKind);
122+
void PassContext_eraseInstruction(BridgedPassContext passContext,
123+
BridgedInstruction inst);
124+
116125
BridgedStringRef SILFunction_getName(BridgedFunction function);
117126
BridgedStringRef SILFunction_debugDescription(BridgedFunction function);
118127
OptionalBridgedBasicBlock SILFunction_firstBlock(BridgedFunction function);

include/swift/SIL/SILInstruction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,15 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
365365
SILInstructionResultArray getResultsImpl() const;
366366

367367
protected:
368+
friend class LibswiftPassInvocation;
369+
368370
SILInstruction() {
369371
NumCreatedInstructions++;
370372
}
371373

374+
/// This method unlinks 'self' from the containing basic block.
375+
void removeFromParent();
376+
372377
~SILInstruction() {
373378
NumDeletedInstructions++;
374379
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//===--- OptimizerBridging.h - header for the OptimizerBridging module ----===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2021 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+
#ifndef SWIFT_SILOPTIMIZER_OPTIMIZERBRIDGING_H
14+
#define SWIFT_SILOPTIMIZER_OPTIMIZERBRIDGING_H
15+
16+
#include "../SIL/SILBridging.h"
17+
18+
#ifdef __cplusplus
19+
extern "C" {
20+
#endif
21+
22+
typedef struct {
23+
BridgedFunction function;
24+
BridgedPassContext passContext;
25+
} BridgedFunctionPassCtxt;
26+
27+
typedef void (*BridgedFunctionPassRunFn)(BridgedFunctionPassCtxt);
28+
void SILPassManager_registerFunctionPass(BridgedStringRef name,
29+
BridgedFunctionPassRunFn runFn);
30+
31+
#ifdef __cplusplus
32+
} // extern "C"
33+
#endif
34+
35+
#endif

include/swift/SILOptimizer/PassManager/PassManager.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/SIL/Notifications.h"
14+
#include "swift/SIL/InstructionUtils.h"
1415
#include "swift/SILOptimizer/Analysis/Analysis.h"
1516
#include "swift/SILOptimizer/PassManager/PassPipeline.h"
1617
#include "swift/SILOptimizer/PassManager/Passes.h"
@@ -31,6 +32,8 @@ class SILModule;
3132
class SILModuleTransform;
3233
class SILOptions;
3334
class SILTransform;
35+
class SILPassManager;
36+
class SILCombiner;
3437

3538
namespace irgen {
3639
class IRGenModule;
@@ -41,6 +44,28 @@ void executePassPipelinePlan(SILModule *SM, const SILPassPipelinePlan &plan,
4144
bool isMandatory = false,
4245
irgen::IRGenModule *IRMod = nullptr);
4346

47+
/// Utility class to invoke passes in libswift.
48+
class LibswiftPassInvocation {
49+
/// Backlink to the pass manager.
50+
SILPassManager *passManager;
51+
52+
/// Non-null if this is an instruction pass, invoked from SILCombine.
53+
SILCombiner *silCombiner;
54+
55+
public:
56+
LibswiftPassInvocation(SILPassManager *passManager, SILCombiner *silCombiner) :
57+
passManager(passManager), silCombiner(silCombiner) {}
58+
59+
/// The top-level API to erase an instruction, called from the Swift pass.
60+
void eraseInstruction(SILInstruction *inst);
61+
62+
/// Called by the pass when changes are made to the SIL.
63+
void notifyChanges(SILAnalysis::InvalidationKind invalidationKind);
64+
65+
/// Called by the pass manager when the pass has finished.
66+
void finishedPassRun();
67+
};
68+
4469
/// The SIL pass manager.
4570
class SILPassManager {
4671
friend class ExecuteSILPipelineRequest;
@@ -79,6 +104,13 @@ class SILPassManager {
79104
/// The number of passes run so far.
80105
unsigned NumPassesRun = 0;
81106

107+
/// For invoking Swift passes in libswift.
108+
LibswiftPassInvocation libswiftPassInvocation;
109+
110+
/// Change notifications, collected during a bridged pass run.
111+
SILAnalysis::InvalidationKind changeNotifications =
112+
SILAnalysis::InvalidationKind::Nothing;
113+
82114
/// A mask which has one bit for each pass. A one for a pass-bit means that
83115
/// the pass doesn't need to run, because nothing has changed since the
84116
/// previous run of that pass.
@@ -148,6 +180,10 @@ class SILPassManager {
148180
/// pass manager.
149181
irgen::IRGenModule *getIRGenModule() { return IRMod; }
150182

183+
LibswiftPassInvocation *getLibswiftPassInvocation() {
184+
return &libswiftPassInvocation;
185+
}
186+
151187
/// Restart the function pass pipeline on the same function
152188
/// that is currently being processed.
153189
void restartWithCurrentFunction(SILTransform *T);
@@ -226,6 +262,11 @@ class SILPassManager {
226262
CompletedPassesMap[F].reset();
227263
}
228264

265+
void notifyPassChanges(SILAnalysis::InvalidationKind invalidationKind) {
266+
changeNotifications = (SILAnalysis::InvalidationKind)
267+
(changeNotifications | invalidationKind);
268+
}
269+
229270
/// Reset the state of the pass manager and remove all transformation
230271
/// owned by the pass manager. Analysis passes will be kept.
231272
void resetAndRemoveTransformations();
@@ -315,6 +356,11 @@ class SILPassManager {
315356
void viewCallGraph();
316357
};
317358

359+
inline void LibswiftPassInvocation::
360+
notifyChanges(SILAnalysis::InvalidationKind invalidationKind) {
361+
passManager->notifyPassChanges(invalidationKind);
362+
}
363+
318364
} // end namespace swift
319365

320366
#endif

include/swift/SILOptimizer/PassManager/Passes.def

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

46+
/// SWIFT_FUNCTION_PASS(Id, Tag, Description)
47+
/// This macro follows the same conventions as PASS(Id, Tag, Description),
48+
/// but is used for function passes which are implemented in libswift.
49+
///
50+
/// No further code is need on the C++ side. In libswift a function pass with
51+
/// the same name must be registered with 'registerPass()'.
52+
///
53+
#ifndef SWIFT_FUNCTION_PASS
54+
#define SWIFT_FUNCTION_PASS(Id, Tag, Description) PASS(Id, Tag, Description)
55+
#endif
56+
57+
/// SWIFT_FUNCTION_PASS_WITH_LEGACY(Id, Tag, Description)
58+
/// Like SWIFT_FUNCTION_PASS, but the a C++ legacy pass is used if the not
59+
/// built with libswift.
60+
/// The C++ legacy creation function must be named 'createLegacy<Id>'
61+
///
62+
#ifndef SWIFT_FUNCTION_PASS_WITH_LEGACY
63+
#define SWIFT_FUNCTION_PASS_WITH_LEGACY(Id, Tag, Description) \
64+
SWIFT_FUNCTION_PASS(Id, Tag, Description)
65+
#endif
66+
4667
/// PASS_RANGE(RANGE_ID, START, END)
4768
/// Pass IDs between PassKind::START and PassKind::END, inclusive,
4869
/// fall within the set known as
@@ -374,5 +395,7 @@ PASS(PruneVTables, "prune-vtables",
374395
PASS_RANGE(AllPasses, AADumper, PruneVTables)
375396

376397
#undef IRGEN_PASS
398+
#undef SWIFT_FUNCTION_PASS
399+
#undef SWIFT_FUNCTION_PASS_WITH_LEGACY
377400
#undef PASS
378401
#undef PASS_RANGE

include/swift/SILOptimizer/PassManager/Passes.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,11 @@ namespace swift {
7474
StringRef PassKindID(PassKind Kind);
7575
StringRef PassKindTag(PassKind Kind);
7676

77-
#define PASS(ID, TAG, NAME) SILTransform *create##ID();
77+
#define PASS(ID, TAG, NAME) \
78+
SILTransform *create##ID();
79+
#define SWIFT_FUNCTION_PASS_WITH_LEGACY(ID, TAG, NAME) \
80+
PASS(ID, TAG, NAME) \
81+
SILTransform *createLegacy##ID();
7882
#define IRGEN_PASS(ID, TAG, NAME)
7983
#include "Passes.def"
8084

include/swift/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,8 @@ module SILBridging {
33
export *
44
}
55

6+
module OptimizerBridging {
7+
header "SILOptimizer/OptimizerBridging.h"
8+
export *
9+
}
10+

lib/SIL/IR/SILInstruction.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,16 @@ SILModule &SILInstruction::getModule() const {
103103
return getFunction()->getModule();
104104
}
105105

106+
void SILInstruction::removeFromParent() {
107+
#ifndef NDEBUG
108+
for (auto result : getResults()) {
109+
assert(result->use_empty() && "Uses of SILInstruction remain at deletion.");
110+
}
111+
#endif
112+
getParent()->remove(this);
113+
ParentBB = nullptr;
114+
}
115+
106116
/// eraseFromParent - This method unlinks 'self' from the containing basic
107117
/// block and deletes it.
108118
///

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
#include "swift/AST/SILOptimizerRequests.h"
1717
#include "swift/Demangling/Demangle.h"
1818
#include "swift/SIL/ApplySite.h"
19+
#include "swift/SIL/SILBridgingUtils.h"
1920
#include "swift/SIL/SILFunction.h"
2021
#include "swift/SIL/SILModule.h"
2122
#include "swift/SILOptimizer/Analysis/BasicCalleeAnalysis.h"
2223
#include "swift/SILOptimizer/Analysis/FunctionOrder.h"
24+
#include "swift/SILOptimizer/OptimizerBridging.h"
2325
#include "swift/SILOptimizer/PassManager/PrettyStackTrace.h"
2426
#include "swift/SILOptimizer/PassManager/Transforms.h"
2527
#include "swift/SILOptimizer/Utils/OptimizerStatsUtils.h"
@@ -318,8 +320,9 @@ void swift::executePassPipelinePlan(SILModule *SM,
318320

319321
SILPassManager::SILPassManager(SILModule *M, bool isMandatory,
320322
irgen::IRGenModule *IRMod)
321-
: Mod(M), IRMod(IRMod), isMandatory(isMandatory),
322-
deserializationNotificationHandler(nullptr) {
323+
: Mod(M), IRMod(IRMod),
324+
libswiftPassInvocation(this, /*SILCombiner*/ nullptr),
325+
isMandatory(isMandatory), deserializationNotificationHandler(nullptr) {
323326
#define ANALYSIS(NAME) \
324327
Analyses.push_back(create##NAME##Analysis(Mod));
325328
#include "swift/SILOptimizer/Analysis/Analysis.def"
@@ -462,7 +465,19 @@ void SILPassManager::runPassOnFunction(unsigned TransIdx, SILFunction *F) {
462465
SILForceVerifyAroundPass.end(), MatchFun)) {
463466
forcePrecomputeAnalyses(F);
464467
}
468+
469+
assert(changeNotifications == SILAnalysis::InvalidationKind::Nothing
470+
&& "change notifications not cleared");
471+
472+
// Run it!
465473
SFT->run();
474+
475+
if (changeNotifications != SILAnalysis::InvalidationKind::Nothing) {
476+
invalidateAnalysis(F, changeNotifications);
477+
changeNotifications = SILAnalysis::InvalidationKind::Nothing;
478+
}
479+
libswiftPassInvocation.finishedPassRun();
480+
466481
if (SILForceVerifyAll ||
467482
SILForceVerifyAroundPass.end() !=
468483
std::find_if(SILForceVerifyAroundPass.begin(),
@@ -1059,3 +1074,49 @@ void SILPassManager::viewCallGraph() {
10591074
llvm::ViewGraph(&OCG, "callgraph");
10601075
#endif
10611076
}
1077+
1078+
//===----------------------------------------------------------------------===//
1079+
// LibswiftPassInvocation
1080+
//===----------------------------------------------------------------------===//
1081+
1082+
void LibswiftPassInvocation::eraseInstruction(SILInstruction *inst) {
1083+
if (silCombiner) {
1084+
// TODO
1085+
} else {
1086+
inst->eraseFromParent();
1087+
}
1088+
}
1089+
1090+
void LibswiftPassInvocation::finishedPassRun() {
1091+
}
1092+
1093+
//===----------------------------------------------------------------------===//
1094+
// Swift Bridging
1095+
//===----------------------------------------------------------------------===//
1096+
1097+
inline LibswiftPassInvocation *castToPassInvocation(BridgedPassContext ctxt) {
1098+
return const_cast<LibswiftPassInvocation *>(
1099+
static_cast<const LibswiftPassInvocation *>(ctxt.opaqueCtxt));
1100+
}
1101+
1102+
void PassContext_notifyChanges(BridgedPassContext passContext,
1103+
enum ChangeNotificationKind changeKind) {
1104+
LibswiftPassInvocation *inv = castToPassInvocation(passContext);
1105+
switch (changeKind) {
1106+
case instructionsChanged:
1107+
inv->notifyChanges(SILAnalysis::InvalidationKind::Instructions);
1108+
break;
1109+
case callsChanged:
1110+
inv->notifyChanges(SILAnalysis::InvalidationKind::CallsAndInstructions);
1111+
break;
1112+
case branchesChanged:
1113+
inv->notifyChanges(SILAnalysis::InvalidationKind::BranchesAndInstructions);
1114+
break;
1115+
}
1116+
}
1117+
1118+
void PassContext_eraseInstruction(BridgedPassContext passContext,
1119+
BridgedInstruction inst) {
1120+
castToPassInvocation(passContext)->eraseInstruction(castToInst(inst));
1121+
}
1122+

0 commit comments

Comments
 (0)