26
26
#define DEBUG_TYPE " copy-propagation"
27
27
28
28
#include " swift/SIL/BasicBlockUtils.h"
29
+ #include " swift/SIL/SILUndef.h"
29
30
#include " swift/SILOptimizer/Analysis/DeadEndBlocksAnalysis.h"
30
31
#include " swift/SILOptimizer/PassManager/Passes.h"
31
32
#include " swift/SILOptimizer/PassManager/Transforms.h"
34
35
35
36
using namespace swift ;
36
37
38
+ // This only applies to -O copy-propagation.
39
+ llvm::cl::opt<bool >
40
+ EnableRewriteBorrows (" canonical-ossa-rewrite-borrows" ,
41
+ llvm::cl::init (false ),
42
+ llvm::cl::desc(" Enable rewriting borrow scopes" ));
43
+
37
44
// ===----------------------------------------------------------------------===//
38
45
// CopyPropagation: Top-Level Function Transform.
39
46
// ===----------------------------------------------------------------------===//
@@ -44,13 +51,17 @@ class CopyPropagation : public SILFunctionTransform {
44
51
bool pruneDebug;
45
52
// / True of all values should be canonicalized.
46
53
bool canonicalizeAll;
54
+ // / If true, then borrow scopes will be canonicalized, allowing copies of
55
+ // / guaranteed values to be optimized. Does *not* shrink the borrow scope.
56
+ bool canonicalizeBorrows;
47
57
// / If true, then new destroy_value instructions will be poison.
48
58
bool poisonRefs;
49
59
50
60
public:
51
- CopyPropagation (bool pruneDebug, bool canonicalizeAll, bool poisonRefs)
52
- : pruneDebug(pruneDebug), canonicalizeAll(canonicalizeAll),
53
- poisonRefs (poisonRefs) {}
61
+ CopyPropagation (bool pruneDebug, bool canonicalizeAll,
62
+ bool canonicalizeBorrows, bool poisonRefs)
63
+ : pruneDebug(pruneDebug), canonicalizeAll(canonicalizeAll),
64
+ canonicalizeBorrows (canonicalizeBorrows), poisonRefs(poisonRefs) {}
54
65
55
66
// / The entry point to this function transformation.
56
67
void run () override ;
@@ -71,12 +82,18 @@ static bool isCopyDead(CopyValueInst *copy, bool pruneDebug) {
71
82
return true ;
72
83
}
73
84
85
+ static bool isBorrowDead (BeginBorrowInst *borrow) {
86
+ return llvm::all_of (borrow->getUses (), [](Operand *use) {
87
+ SILInstruction *user = use->getUser ();
88
+ return isa<EndBorrowInst>(user) || user->isDebugInstruction ();
89
+ });
90
+ }
91
+
74
92
// / Top-level pass driver.
75
93
void CopyPropagation::run () {
76
94
auto *f = getFunction ();
77
95
auto *accessBlockAnalysis = getAnalysis<NonLocalAccessBlockAnalysis>();
78
96
auto *dominanceAnalysis = getAnalysis<DominanceAnalysis>();
79
- auto *deBlocksAnalysis = getAnalysis<DeadEndBlocksAnalysis>();
80
97
81
98
// Debug label for unit testing.
82
99
LLVM_DEBUG (llvm::dbgs () << " *** CopyPropagation: " << f->getName () << " \n " );
@@ -115,6 +132,12 @@ void CopyPropagation::run() {
115
132
|| SILValue (extract).getOwnershipKind () != OwnershipKind::Guaranteed)
116
133
continue ;
117
134
135
+ // Bail-out if we won't rewrite borrows because that currently regresses
136
+ // Breadcrumbs.MutatedUTF16ToIdx.Mixed/Breadcrumbs.MutatedIdxToUTF16.Mixed.
137
+ // Also, mandatory copyprop does not need to rewrite destructures.
138
+ if (!canonicalizeBorrows)
139
+ continue ;
140
+
118
141
if (SILValue destructuredResult = convertExtractToDestructure (extract)) {
119
142
// Remove to-be-deleted instructions from copiedDeds. The extract cannot
120
143
// be in the copiedDefs set since getCanonicalCopiedDef does not allow a
@@ -138,14 +161,13 @@ void CopyPropagation::run() {
138
161
}
139
162
}
140
163
// Perform copy propgation for each copied value.
141
- CanonicalizeOSSALifetime canonicalizer (pruneDebug, poisonRefs,
142
- accessBlockAnalysis,
143
- dominanceAnalysis,
144
- deBlocksAnalysis->get (f));
164
+ CanonicalizeOSSALifetime canonicalizer (pruneDebug, canonicalizeBorrows,
165
+ poisonRefs, accessBlockAnalysis,
166
+ dominanceAnalysis);
145
167
// Cleanup dead copies. If getCanonicalCopiedDef returns a copy (because the
146
- // copy's source operand is unrecgonized), then thecan copy is itself treated
168
+ // copy's source operand is unrecgonized), then the copy is itself treated
147
169
// like a def and may be dead after canonicalization.
148
- llvm::SmallVector<CopyValueInst *, 4 > deadCopies;
170
+ llvm::SmallVector<SILInstruction *, 4 > deadCopies;
149
171
for (auto &def : copiedDefs) {
150
172
// Canonicalized this def.
151
173
canonicalizer.canonicalizeValueLifetime (def);
@@ -155,6 +177,14 @@ void CopyPropagation::run() {
155
177
deadCopies.push_back (copy);
156
178
}
157
179
}
180
+ // Dead borrow scopes must be removed as uses before canonicalizing the
181
+ // outer copy.
182
+ if (auto *borrow = dyn_cast<BeginBorrowInst>(def)) {
183
+ if (isBorrowDead (borrow)) {
184
+ borrow->setOperand (SILUndef::get (borrow->getType (), *f));
185
+ deadCopies.push_back (borrow);
186
+ }
187
+ }
158
188
// Canonicalize any new outer copy.
159
189
if (SILValue outerCopy = canonicalizer.createdOuterCopy ()) {
160
190
SILValue outerDef = canonicalizer.getCanonicalCopiedDef (outerCopy);
@@ -165,26 +195,29 @@ void CopyPropagation::run() {
165
195
}
166
196
if (canonicalizer.hasChanged () || !deadCopies.empty ()) {
167
197
InstructionDeleter deleter;
168
- for (auto *copy : deadCopies) {
169
- deleter.recursivelyDeleteUsersIfDead (copy );
198
+ for (auto *copyOrBorrow : deadCopies) {
199
+ deleter.recursivelyDeleteUsersIfDead (copyOrBorrow );
170
200
}
171
201
// Preserves NonLocalAccessBlockAnalysis.
172
202
accessBlockAnalysis->lockInvalidation ();
173
203
invalidateAnalysis (SILAnalysis::InvalidationKind::Instructions);
174
204
accessBlockAnalysis->unlockInvalidation ();
175
205
if (f->getModule ().getOptions ().VerifySILOwnership ) {
206
+ auto *deBlocksAnalysis = getAnalysis<DeadEndBlocksAnalysis>();
176
207
f->verifyOwnership (deBlocksAnalysis->get (f));
177
208
}
178
209
}
179
210
}
180
211
181
212
SILTransform *swift::createMandatoryCopyPropagation () {
182
213
return new CopyPropagation (/* pruneDebug*/ true , /* canonicalizeAll*/ true ,
214
+ /* canonicalizeBorrows*/ false ,
183
215
/* poisonRefs*/ true );
184
216
}
185
217
186
218
SILTransform *swift::createCopyPropagation () {
187
219
return new CopyPropagation (/* pruneDebug*/ true , /* canonicalizeAll*/ false ,
220
+ /* canonicalizeBorrows*/ EnableRewriteBorrows,
188
221
/* poisonRefs*/ false );
189
222
}
190
223
0 commit comments