11
11
// ===----------------------------------------------------------------------===//
12
12
13
13
#define DEBUG_TYPE " sil-combine"
14
+
14
15
#include " SILCombiner.h"
15
16
#include " swift/SIL/DebugUtils.h"
16
17
#include " swift/SIL/DynamicCasts.h"
22
23
#include " swift/SILOptimizer/Analysis/ValueTracking.h"
23
24
#include " swift/SILOptimizer/Utils/CFGOptUtils.h"
24
25
#include " swift/SILOptimizer/Utils/InstOptUtils.h"
26
+ #include " swift/SILOptimizer/Utils/OwnershipOptUtils.h"
25
27
#include " llvm/ADT/DenseMap.h"
26
28
#include " llvm/ADT/SmallPtrSet.h"
27
29
#include " llvm/ADT/SmallVector.h"
@@ -109,6 +111,92 @@ SILInstruction *SILCombiner::optimizeBuiltinIsConcrete(BuiltinInst *BI) {
109
111
return Builder.createIntegerLiteral (BI->getLoc (), BI->getType (), 1 );
110
112
}
111
113
114
+ // / Replace
115
+ // / \code
116
+ // / %b = builtin "COWBufferForReading" %r
117
+ // / %bb = begin_borrow %b
118
+ // / %a = ref_element_addr %bb
119
+ // / ... use %a ...
120
+ // / end_borrow %bb
121
+ // / \endcode
122
+ // / with
123
+ // / \code
124
+ // / %bb = begin_borrow %r
125
+ // / %a = ref_element_addr [immutable] %r
126
+ // / ... use %b ...
127
+ // / end_borrow %bb
128
+ // / \endcode
129
+ // / The same for ref_tail_addr.
130
+ SILInstruction *
131
+ SILCombiner::optimizeBuiltinCOWBufferForReadingOSSA (BuiltinInst *bi) {
132
+ SmallVector<BorrowedValue, 32 > accumulatedBorrowedValues;
133
+
134
+ // A helper that performs our main loop to look through uses. It ensures
135
+ // that we do not need to fill up the useWorklist on the first iteration.
136
+ for (auto *use : bi->getUses ()) {
137
+ // See if we have a borrowing operand that we can find a local borrowed
138
+ // value for. In such a case, we stash that borrowed value so that we can
139
+ // use it to find interior pointer operands.
140
+ if (auto operand = BorrowingOperand (use)) {
141
+ if (operand.isReborrow ())
142
+ return nullptr ;
143
+ operand.visitBorrowIntroducingUserResults ([&](BorrowedValue bv) {
144
+ accumulatedBorrowedValues.push_back (bv);
145
+ return true ;
146
+ });
147
+ continue ;
148
+ }
149
+
150
+ // Otherwise, look for instructions that we know are uses that we can
151
+ // ignore.
152
+ auto *user = use->getUser ();
153
+
154
+ // Debug instructions are safe.
155
+ if (user->isDebugInstruction ())
156
+ continue ;
157
+
158
+ // copy_value, destroy_value are safe due to our checking of the
159
+ // instruction use list for safety.
160
+ if (isa<DestroyValueInst>(user) || isa<CopyValueInst>(user))
161
+ continue ;
162
+
163
+ // An instruction we don't understand, bail.
164
+ return nullptr ;
165
+ }
166
+
167
+ // Now that we know that we have a case we support, use our stashed
168
+ // BorrowedValues to find all interior pointer operands into this copy of our
169
+ // COWBuffer and mark them as immutable.
170
+ //
171
+ // NOTE: We currently only use nested int ptr operands instead of extended int
172
+ // ptr operands since we do not want to look through reborrows and thus lose
173
+ // dominance.
174
+ while (!accumulatedBorrowedValues.empty ()) {
175
+ auto bv = accumulatedBorrowedValues.pop_back_val ();
176
+ bv.visitNestedInteriorPointerOperands (
177
+ [&](InteriorPointerOperand intPtrOperand) {
178
+ switch (intPtrOperand.kind ) {
179
+ case InteriorPointerOperandKind::Invalid:
180
+ llvm_unreachable (" Invalid int pointer kind?!" );
181
+ case InteriorPointerOperandKind::RefElementAddr:
182
+ cast<RefElementAddrInst>(intPtrOperand->getUser ())->setImmutable ();
183
+ return ;
184
+ case InteriorPointerOperandKind::RefTailAddr:
185
+ cast<RefTailAddrInst>(intPtrOperand->getUser ())->setImmutable ();
186
+ return ;
187
+ case InteriorPointerOperandKind::OpenExistentialBox:
188
+ // Can not mark this immutable.
189
+ return ;
190
+ }
191
+ });
192
+ }
193
+
194
+ OwnershipRAUWHelper helper (ownershipFixupContext, bi, bi->getOperand (0 ));
195
+ assert (helper && " COWBufferForReading always has an owned arg/owned result" );
196
+ helper.perform ();
197
+ return nullptr ;
198
+ }
199
+
112
200
// / Replace
113
201
// / \code
114
202
// / %b = builtin "COWBufferForReading" %r
@@ -119,23 +207,24 @@ SILInstruction *SILCombiner::optimizeBuiltinIsConcrete(BuiltinInst *BI) {
119
207
// / %a = ref_element_addr [immutable] %r
120
208
// / \endcode
121
209
// / The same for ref_tail_addr.
122
- SILInstruction *SILCombiner::optimizeBuiltinCOWBufferForReading (BuiltinInst *BI) {
123
- auto useIter = BI->use_begin ();
124
- while (useIter != BI->use_end ()) {
210
+ SILInstruction *
211
+ SILCombiner::optimizeBuiltinCOWBufferForReadingNonOSSA (BuiltinInst *bi) {
212
+ auto useIter = bi->use_begin ();
213
+ while (useIter != bi->use_end ()) {
125
214
auto nextIter = std::next (useIter);
126
215
SILInstruction *user = useIter->getUser ();
127
- SILValue ref = BI ->getOperand (0 );
216
+ SILValue ref = bi ->getOperand (0 );
128
217
switch (user->getKind ()) {
129
218
case SILInstructionKind::RefElementAddrInst: {
130
- auto *REAI = cast<RefElementAddrInst>(user);
131
- REAI ->setOperand (ref);
132
- REAI ->setImmutable ();
219
+ auto *reai = cast<RefElementAddrInst>(user);
220
+ reai ->setOperand (ref);
221
+ reai ->setImmutable ();
133
222
break ;
134
223
}
135
224
case SILInstructionKind::RefTailAddrInst: {
136
- auto *RTAI = cast<RefTailAddrInst>(user);
137
- RTAI ->setOperand (ref);
138
- RTAI ->setImmutable ();
225
+ auto *rtai = cast<RefTailAddrInst>(user);
226
+ rtai ->setOperand (ref);
227
+ rtai ->setImmutable ();
139
228
break ;
140
229
}
141
230
case SILInstructionKind::DestroyValueInst:
@@ -151,11 +240,18 @@ SILInstruction *SILCombiner::optimizeBuiltinCOWBufferForReading(BuiltinInst *BI)
151
240
}
152
241
153
242
// If there are unknown users, keep the builtin, and IRGen will handle it.
154
- if (BI ->use_empty ())
155
- return eraseInstFromFunction (*BI );
243
+ if (bi ->use_empty ())
244
+ return eraseInstFromFunction (*bi );
156
245
return nullptr ;
157
246
}
158
247
248
+ SILInstruction *
249
+ SILCombiner::optimizeBuiltinCOWBufferForReading (BuiltinInst *BI) {
250
+ if (hasOwnership ())
251
+ return optimizeBuiltinCOWBufferForReadingOSSA (BI);
252
+ return optimizeBuiltinCOWBufferForReadingNonOSSA (BI);
253
+ }
254
+
159
255
static unsigned getTypeWidth (SILType Ty) {
160
256
if (auto BuiltinIntTy = Ty.getAs <BuiltinIntegerType>()) {
161
257
if (BuiltinIntTy->isFixedWidth ()) {
0 commit comments