Skip to content

Commit cfd2d2c

Browse files
authored
Merge pull request #9186 from atrick/swift-4.0-branch
2 parents a9751ef + 410366e commit cfd2d2c

File tree

4 files changed

+100
-34
lines changed

4 files changed

+100
-34
lines changed

include/swift/SIL/SILModule.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ class SILModule {
191191
/// The callback used by the SILLoader.
192192
std::unique_ptr<SerializationCallback> Callback;
193193

194+
// Callbacks registered by the SIL optimizer to run on each deserializaed
195+
// function body. This is intentionally a stateless type because the
196+
// ModuleDecl and SILFunction should be sufficient context.
197+
typedef void (*SILFunctionBodyCallback)(ModuleDecl *, SILFunction *F);
198+
SmallVector<SILFunctionBodyCallback, 0> DeserializationCallbacks;
199+
194200
/// The SILLoader used when linking functions into this module.
195201
///
196202
/// This is lazily initialized the first time we attempt to
@@ -231,6 +237,12 @@ class SILModule {
231237
public:
232238
~SILModule();
233239

240+
/// Add a callback for each newly deserialized SIL function body.
241+
void registerDeserializationCallback(SILFunctionBodyCallback callBack);
242+
243+
/// Return set of registered deserialization callbacks.
244+
ArrayRef<SILFunctionBodyCallback> getDeserializationCallbacks();
245+
234246
/// Add a delete notification handler \p Handler to the module context.
235247
void registerDeleteNotificationHandler(DeleteNotificationHandler* Handler);
236248

lib/SIL/SILModule.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ class SILModule::SerializationCallback : public SerializedSILLoader::Callback {
7474
return;
7575
}
7676
}
77+
78+
void didDeserializeFunctionBody(ModuleDecl *M, SILFunction *fn) override {
79+
// Callbacks are currently applied in the order they are registered.
80+
for (auto callBack : fn->getModule().getDeserializationCallbacks())
81+
callBack(M, fn);
82+
}
7783
};
7884

7985
SILModule::SILModule(ModuleDecl *SwiftModule, SILOptions &Options,
@@ -726,6 +732,18 @@ lookUpFunctionInVTable(ClassDecl *Class, SILDeclRef Member) {
726732
return nullptr;
727733
}
728734

735+
void SILModule::registerDeserializationCallback(
736+
SILFunctionBodyCallback callBack) {
737+
if (std::find(DeserializationCallbacks.begin(),
738+
DeserializationCallbacks.end(), callBack)
739+
== DeserializationCallbacks.end())
740+
DeserializationCallbacks.push_back(callBack);
741+
}
742+
743+
ArrayRef<SILModule::SILFunctionBodyCallback>
744+
SILModule::getDeserializationCallbacks() {
745+
return DeserializationCallbacks;
746+
}
729747

730748
void SILModule::
731749
registerDeleteNotificationHandler(DeleteNotificationHandler* Handler) {

lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp

Lines changed: 66 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,33 @@ llvm::cl::opt<bool> EnableAccessMarkers(
5252

5353
namespace {
5454

55-
struct AccessMarkerElimination : SILModuleTransform {
56-
virtual bool isFullElimination() = 0;
55+
struct AccessMarkerElimination {
56+
SILModule *Mod;
57+
SILFunction *F;
58+
bool isFullElimination;
5759

5860
bool removedAny = false;
5961

62+
AccessMarkerElimination(SILFunction *F, bool isFullElimination)
63+
: Mod(&F->getModule()), F(F), isFullElimination(isFullElimination) {}
64+
6065
SILBasicBlock::iterator eraseInst(SILInstruction *inst) {
6166
removedAny = true;
6267
return inst->getParent()->erase(inst);
6368
};
6469

6570
void replaceBeginAccessUsers(BeginAccessInst *beginAccess);
6671

67-
// Precondition: !EnableAccessMarkers || isFullElimination()
72+
// Precondition: !EnableAccessMarkers || isFullElimination
6873
bool shouldPreserveAccess(SILAccessEnforcement enforcement);
6974

7075
// Check if the instruction is a marker that should be eliminated. If so,
7176
// updated the SIL, short of erasing the marker itself, and return true.
7277
bool checkAndEliminateMarker(SILInstruction *inst);
7378

74-
// Entry point called by the pass manager.
75-
void run() override;
79+
// Entry point called either by the pass by the same name
80+
// or as a utility (e.g. during deserialization).
81+
bool stripMarkers();
7682
};
7783

7884
void AccessMarkerElimination::replaceBeginAccessUsers(
@@ -93,24 +99,24 @@ void AccessMarkerElimination::replaceBeginAccessUsers(
9399
}
94100
}
95101

96-
// Precondition: !EnableAccessMarkers || isFullElimination()
102+
// Precondition: !EnableAccessMarkers || isFullElimination
97103
bool AccessMarkerElimination::shouldPreserveAccess(
98104
SILAccessEnforcement enforcement) {
99-
if (isFullElimination())
105+
if (isFullElimination)
100106
return false;
101107

102-
auto &M = *getModule();
103108
switch (enforcement) {
104109
case SILAccessEnforcement::Unknown:
105110
return false;
106111
case SILAccessEnforcement::Static:
107112
// Even though static enforcement is already performed, this flag is
108113
// useful to control marker preservation for now.
109-
return EnableAccessMarkers || M.getOptions().EnforceExclusivityStatic;
114+
return EnableAccessMarkers || Mod->getOptions().EnforceExclusivityStatic;
110115
case SILAccessEnforcement::Dynamic:
111116
// FIXME: when dynamic markers are fully supported, don't strip:
112-
// return EnableAccessMarkers || M.getOptions().EnforceExclusivityDynamic;
113-
return M.getOptions().EnforceExclusivityDynamic;
117+
// return
118+
// EnableAccessMarkers || Mod->getOptions().EnforceExclusivityDynamic;
119+
return Mod->getOptions().EnforceExclusivityDynamic;
114120
case SILAccessEnforcement::Unsafe:
115121
return false;
116122
}
@@ -152,38 +158,64 @@ bool AccessMarkerElimination::checkAndEliminateMarker(SILInstruction *inst) {
152158
return false;
153159
}
154160

155-
void AccessMarkerElimination::run() {
161+
// Top-level per-function entry-point.
162+
// Return `true` if any markers were removed.
163+
bool AccessMarkerElimination::stripMarkers() {
156164
// FIXME: When dynamic markers are fully supported, just skip this pass:
157-
// if (EnableAccessMarkers && !isFullElimination())
158-
// return;
159-
160-
auto &M = *getModule();
161-
for (auto &F : M) {
162-
// Iterating in reverse eliminates more begin_access users before they
163-
// need to be replaced.
164-
for (auto &BB : reversed(F)) {
165-
// Don't cache the begin iterator since we're reverse iterating.
166-
for (auto II = BB.end(); II != BB.begin();) {
167-
SILInstruction *inst = &*(--II);
168-
if (checkAndEliminateMarker(inst))
169-
II = eraseInst(inst);
170-
}
165+
// if (EnableAccessMarkers && !isFullElimination)
166+
// return false;
167+
168+
// Iterating in reverse eliminates more begin_access users before they
169+
// need to be replaced.
170+
for (auto &BB : reversed(*F)) {
171+
// Don't cache the begin iterator since we're reverse iterating.
172+
for (auto II = BB.end(); II != BB.begin();) {
173+
SILInstruction *inst = &*(--II);
174+
if (checkAndEliminateMarker(inst))
175+
II = eraseInst(inst);
171176
}
177+
}
178+
return removedAny;
179+
}
172180

173-
// Don't invalidate any analyses if we didn't do anything.
174-
if (!removedAny)
175-
continue;
181+
} // end anonymous namespace
176182

177-
auto InvalidKind = SILAnalysis::InvalidationKind::Instructions;
178-
invalidateAnalysis(&F, InvalidKind);
179-
}
183+
// Implement a SILModule::SILFunctionBodyCallback that strips all access
184+
// markers from newly deserialized function bodies.
185+
static void prepareSILFunctionForOptimization(ModuleDecl *, SILFunction *F) {
186+
AccessMarkerElimination(F, /*isFullElimination=*/true).stripMarkers();
180187
}
181188

182-
struct InactiveAccessMarkerElimination : AccessMarkerElimination {
189+
namespace {
190+
191+
struct AccessMarkerEliminationPass : SILModuleTransform {
192+
virtual bool isFullElimination() = 0;
193+
194+
void run() override {
195+
auto &M = *getModule();
196+
for (auto &F : M) {
197+
bool removedAny = AccessMarkerElimination(&F, isFullElimination())
198+
.stripMarkers();
199+
200+
// Only invalidate analyses if we removed some markers.
201+
if (removedAny) {
202+
auto InvalidKind = SILAnalysis::InvalidationKind::Instructions;
203+
invalidateAnalysis(&F, InvalidKind);
204+
}
205+
206+
// Markers from all current SIL functions are stripped. Register a
207+
// callback to strip an subsequently loaded functions on-the-fly.
208+
if (isFullElimination())
209+
M.registerDeserializationCallback(prepareSILFunctionForOptimization);
210+
}
211+
}
212+
};
213+
214+
struct InactiveAccessMarkerElimination : AccessMarkerEliminationPass {
183215
virtual bool isFullElimination() { return false; }
184216
};
185217

186-
struct FullAccessMarkerElimination : AccessMarkerElimination {
218+
struct FullAccessMarkerElimination : AccessMarkerEliminationPass {
187219
virtual bool isFullElimination() { return true; }
188220
};
189221

test/SILGen/addressors.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
// RUN: %target-swift-frontend -parse-stdlib -emit-silgen %s | %FileCheck %s -check-prefix=SILGEN
33
// RUN: %target-swift-frontend -parse-stdlib -emit-ir %s
44

5+
// This test includes some calls to transparent stdlib functions.
6+
// We pattern match for the absence of access markers in the inlined code.
7+
// REQUIRES: optimized_stdlib
8+
59
import Swift
610

711
func someValidPointer<T>() -> UnsafePointer<T> { fatalError() }

0 commit comments

Comments
 (0)