Skip to content

Commit 707cecb

Browse files
authored
Merge pull request #9182 from atrick/access
2 parents 6d24150 + ab0d018 commit 707cecb

File tree

4 files changed

+103
-34
lines changed

4 files changed

+103
-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: 69 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -52,27 +52,34 @@ 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) {
66+
DEBUG(llvm::dbgs() << "Erasing access marker: " << *inst);
6167
removedAny = true;
6268
return inst->getParent()->erase(inst);
6369
};
6470

6571
void replaceBeginAccessUsers(BeginAccessInst *beginAccess);
6672

67-
// Precondition: !EnableAccessMarkers || isFullElimination()
73+
// Precondition: !EnableAccessMarkers || isFullElimination
6874
bool shouldPreserveAccess(SILAccessEnforcement enforcement);
6975

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

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

7885
void AccessMarkerElimination::replaceBeginAccessUsers(
@@ -93,24 +100,24 @@ void AccessMarkerElimination::replaceBeginAccessUsers(
93100
}
94101
}
95102

96-
// Precondition: !EnableAccessMarkers || isFullElimination()
103+
// Precondition: !EnableAccessMarkers || isFullElimination
97104
bool AccessMarkerElimination::shouldPreserveAccess(
98105
SILAccessEnforcement enforcement) {
99-
if (isFullElimination())
106+
if (isFullElimination)
100107
return false;
101108

102-
auto &M = *getModule();
103109
switch (enforcement) {
104110
case SILAccessEnforcement::Unknown:
105111
return false;
106112
case SILAccessEnforcement::Static:
107113
// Even though static enforcement is already performed, this flag is
108114
// useful to control marker preservation for now.
109-
return EnableAccessMarkers || M.getOptions().EnforceExclusivityStatic;
115+
return EnableAccessMarkers || Mod->getOptions().EnforceExclusivityStatic;
110116
case SILAccessEnforcement::Dynamic:
111117
// FIXME: when dynamic markers are fully supported, don't strip:
112-
// return EnableAccessMarkers || M.getOptions().EnforceExclusivityDynamic;
113-
return M.getOptions().EnforceExclusivityDynamic;
118+
// return
119+
// EnableAccessMarkers || Mod->getOptions().EnforceExclusivityDynamic;
120+
return Mod->getOptions().EnforceExclusivityDynamic;
114121
case SILAccessEnforcement::Unsafe:
115122
return false;
116123
}
@@ -152,38 +159,66 @@ bool AccessMarkerElimination::checkAndEliminateMarker(SILInstruction *inst) {
152159
return false;
153160
}
154161

155-
void AccessMarkerElimination::run() {
162+
// Top-level per-function entry-point.
163+
// Return `true` if any markers were removed.
164+
bool AccessMarkerElimination::stripMarkers() {
156165
// 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-
}
166+
// if (EnableAccessMarkers && !isFullElimination)
167+
// return false;
168+
169+
// Iterating in reverse eliminates more begin_access users before they
170+
// need to be replaced.
171+
for (auto &BB : reversed(*F)) {
172+
// Don't cache the begin iterator since we're reverse iterating.
173+
for (auto II = BB.end(); II != BB.begin();) {
174+
SILInstruction *inst = &*(--II);
175+
if (checkAndEliminateMarker(inst))
176+
II = eraseInst(inst);
171177
}
178+
}
179+
return removedAny;
180+
}
172181

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

177-
auto InvalidKind = SILAnalysis::InvalidationKind::Instructions;
178-
invalidateAnalysis(&F, InvalidKind);
179-
}
184+
// Implement a SILModule::SILFunctionBodyCallback that strips all access
185+
// markers from newly deserialized function bodies.
186+
static void prepareSILFunctionForOptimization(ModuleDecl *, SILFunction *F) {
187+
DEBUG(llvm::dbgs() << "Stripping all markers in: " << F->getName() << "\n");
188+
189+
AccessMarkerElimination(F, /*isFullElimination=*/true).stripMarkers();
180190
}
181191

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

186-
struct FullAccessMarkerElimination : AccessMarkerElimination {
221+
struct FullAccessMarkerElimination : AccessMarkerEliminationPass {
187222
virtual bool isFullElimination() { return true; }
188223
};
189224

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)