Skip to content

Commit defc710

Browse files
committed
[exclusivity] Teach LetPropertiesOpt how to handle begin_access.
1 parent 4a7f57c commit defc710

File tree

4 files changed

+53
-25
lines changed

4 files changed

+53
-25
lines changed

include/swift/SIL/InstructionUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ SILValue stripUpCasts(SILValue V);
4848
/// upcasts and downcasts.
4949
SILValue stripClassCasts(SILValue V);
5050

51+
/// Return the underlying SILValue after stripping off non-projection address
52+
/// casts. The result will still be an address--this does not look through
53+
/// pointer-to-address.
54+
SILValue stripAddressAccess(SILValue V);
55+
5156
/// Return the underlying SILValue after stripping off all address projection
5257
/// instructions.
5358
SILValue stripAddressProjections(SILValue V);

lib/SIL/InstructionUtils.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,18 @@ SILValue swift::stripClassCasts(SILValue V) {
181181
}
182182
}
183183

184+
SILValue swift::stripAddressAccess(SILValue V) {
185+
while (true) {
186+
switch (V->getKind()) {
187+
default:
188+
return V;
189+
case ValueKind::BeginBorrowInst:
190+
case ValueKind::BeginAccessInst:
191+
return stripAddressAccess(cast<SingleValueInstruction>(V)->getOperand(0));
192+
}
193+
}
194+
}
195+
184196
SILValue swift::stripAddressProjections(SILValue V) {
185197
while (true) {
186198
V = stripSinglePredecessorArgs(V);

lib/SILOptimizer/IPO/LetPropertiesOpts.cpp

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
//===----------------------------------------------------------------------===//
2020

2121
#define DEBUG_TYPE "let-properties-opt"
22-
#include "swift/SIL/SILInstruction.h"
23-
#include "swift/SIL/SILBasicBlock.h"
2422
#include "swift/SIL/DebugUtils.h"
23+
#include "swift/SIL/InstructionUtils.h"
24+
#include "swift/SIL/SILBasicBlock.h"
25+
#include "swift/SIL/SILInstruction.h"
2526
#include "swift/SIL/SILLinkage.h"
2627
#include "swift/SILOptimizer/PassManager/Passes.h"
2728
#include "swift/SILOptimizer/PassManager/Transforms.h"
@@ -201,7 +202,10 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
201202
};
202203

203204
// Look for any instructions accessing let properties.
204-
if (auto proj = dyn_cast<RefElementAddrInst>(Load)) {
205+
if (isa<RefElementAddrInst>(Load) || isa<StructElementAddrInst>(Load)
206+
|| isa<BeginAccessInst>(Load)) {
207+
auto proj = cast<SingleValueInstruction>(Load);
208+
205209
// Copy the initializer into the function
206210
// Replace the access to a let property by the value
207211
// computed by this initializer.
@@ -210,6 +214,14 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
210214
for (auto UI = proj->use_begin(), E = proj->use_end(); UI != E;) {
211215
auto *User = UI->getUser();
212216
++UI;
217+
218+
if (isIncidentalUse(User))
219+
continue;
220+
221+
// A nested begin_access will be mapped as a separate "Load".
222+
if (isa<BeginAccessInst>(User))
223+
continue;
224+
213225
if (isa<StoreInst>(User))
214226
continue;
215227

@@ -231,23 +243,6 @@ void LetPropertiesOpt::optimizeLetPropertyAccess(VarDecl *Property,
231243
proj->eraseFromParent();
232244
++NumReplaced;
233245
ChangedFunctions.insert(F);
234-
} else if (auto proj = dyn_cast<StructElementAddrInst>(Load)) {
235-
// Copy the initializer into the function
236-
// Replace the access to a let property by the value
237-
// computed by this initializer.
238-
SILValue clonedInit = cloneInitAt(proj);
239-
SILBuilderWithScope B(proj);
240-
for (auto UI = proj->use_begin(), E = proj->use_end(); UI != E;) {
241-
auto *User = UI->getUser();
242-
++UI;
243-
if (isa<StoreInst>(User))
244-
continue;
245-
replaceLoadSequence(User, clonedInit, B);
246-
eraseUsesOfInstruction(User);
247-
User->eraseFromParent();
248-
++NumReplaced;
249-
}
250-
ChangedFunctions.insert(F);
251246
}
252247
}
253248

@@ -422,7 +417,7 @@ LetPropertiesOpt::analyzeInitValue(SILInstruction *I, VarDecl *Property) {
422417
if (auto SI = dyn_cast<StructInst>(I)) {
423418
value = SI->getFieldValue(Property);
424419
} else if (auto SI = dyn_cast<StoreInst>(I)) {
425-
auto Dest = SI->getDest();
420+
auto Dest = stripAddressAccess(SI->getDest());
426421

427422
assert(((isa<RefElementAddrInst>(Dest) &&
428423
cast<RefElementAddrInst>(Dest)->getField() == Property) ||
@@ -524,9 +519,12 @@ static bool isValidPropertyLoad(SILInstruction *I) {
524519

525520
if (isa<StructElementAddrInst>(I) || isa<TupleElementAddrInst>(I)) {
526521
auto projection = cast<SingleValueInstruction>(I);
527-
for (auto Use : getNonDebugUses(projection))
522+
for (auto Use : getNonDebugUses(projection)) {
523+
if (isIncidentalUse(Use->getUser()))
524+
continue;
528525
if (!isValidPropertyLoad(Use->getUser()))
529526
return false;
527+
}
530528
return true;
531529
}
532530

@@ -545,11 +543,19 @@ void LetPropertiesOpt::collectPropertyAccess(SILInstruction *I,
545543
<< "':\n";
546544
llvm::dbgs() << "The instructions are:\n"; I->dumpInContext());
547545

548-
if (isa<RefElementAddrInst>(I) || isa<StructElementAddrInst>(I)) {
546+
if (isa<RefElementAddrInst>(I) || isa<StructElementAddrInst>(I)
547+
|| isa<BeginAccessInst>(I)) {
549548
// Check if there is a store to this property.
550549
auto projection = cast<SingleValueInstruction>(I);
551550
for (auto Use : getNonDebugUses(projection)) {
552551
auto *User = Use->getUser();
552+
if (isIncidentalUse(User))
553+
continue;
554+
555+
// Each begin_access is analyzed as a separate property access. Do not
556+
// consider a begin_access a use of the current projection.
557+
if (isa<BeginAccessInst>(User))
558+
continue;
553559

554560
if (auto *SI = dyn_cast<StoreInst>(User)) {
555561
// There is a store into this property.
@@ -595,7 +601,12 @@ void LetPropertiesOpt::run(SILModuleTransform *T) {
595601
// It includes referencing this specific property (both reads and
596602
// stores), as well as implicit stores by means of e.g.
597603
// a struct instruction.
598-
if (auto *REAI = dyn_cast<RefElementAddrInst>(&I)) {
604+
if (auto *BAI = dyn_cast<BeginAccessInst>(&I)) {
605+
if (auto *REAI =
606+
dyn_cast<RefElementAddrInst>(stripAddressAccess(BAI))) {
607+
collectPropertyAccess(BAI, REAI->getField(), NonRemovable);
608+
}
609+
} else if (auto *REAI = dyn_cast<RefElementAddrInst>(&I)) {
599610
collectPropertyAccess(REAI, REAI->getField(), NonRemovable);
600611
} else if (auto *SEI = dyn_cast<StructExtractInst>(&I)) {
601612
collectPropertyAccess(SEI, SEI->getField(), NonRemovable);

test/SILOptimizer/let_properties_opts.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// REQUIRES: plus_one_runtime
2-
// RUN: %target-swift-frontend %s -O -emit-sil | %FileCheck -check-prefix=CHECK-WMO %s
2+
// RUN: %target-swift-frontend %s -O -enforce-exclusivity=checked -emit-sil | %FileCheck -check-prefix=CHECK-WMO %s
33
// RUN: %target-swift-frontend -primary-file %s -O -emit-sil | %FileCheck %s
44

55
// Test propagation of non-static let properties with compile-time constant values.

0 commit comments

Comments
 (0)