1111// ===----------------------------------------------------------------------===//
1212
1313#define DEBUG_TYPE " sil-combine"
14+
1415#include " SILCombiner.h"
1516#include " swift/SIL/DebugUtils.h"
1617#include " swift/SIL/DynamicCasts.h"
2223#include " swift/SILOptimizer/Analysis/ValueTracking.h"
2324#include " swift/SILOptimizer/Utils/CFGOptUtils.h"
2425#include " swift/SILOptimizer/Utils/InstOptUtils.h"
26+ #include " swift/SILOptimizer/Utils/OwnershipOptUtils.h"
2527#include " llvm/ADT/DenseMap.h"
2628#include " llvm/ADT/SmallPtrSet.h"
2729#include " llvm/ADT/SmallVector.h"
@@ -109,6 +111,92 @@ SILInstruction *SILCombiner::optimizeBuiltinIsConcrete(BuiltinInst *BI) {
109111 return Builder.createIntegerLiteral (BI->getLoc (), BI->getType (), 1 );
110112}
111113
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+
112200// / Replace
113201// / \code
114202// / %b = builtin "COWBufferForReading" %r
@@ -119,23 +207,24 @@ SILInstruction *SILCombiner::optimizeBuiltinIsConcrete(BuiltinInst *BI) {
119207// / %a = ref_element_addr [immutable] %r
120208// / \endcode
121209// / 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 ()) {
125214 auto nextIter = std::next (useIter);
126215 SILInstruction *user = useIter->getUser ();
127- SILValue ref = BI ->getOperand (0 );
216+ SILValue ref = bi ->getOperand (0 );
128217 switch (user->getKind ()) {
129218 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 ();
133222 break ;
134223 }
135224 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 ();
139228 break ;
140229 }
141230 case SILInstructionKind::DestroyValueInst:
@@ -151,11 +240,18 @@ SILInstruction *SILCombiner::optimizeBuiltinCOWBufferForReading(BuiltinInst *BI)
151240 }
152241
153242 // 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 );
156245 return nullptr ;
157246}
158247
248+ SILInstruction *
249+ SILCombiner::optimizeBuiltinCOWBufferForReading (BuiltinInst *BI) {
250+ if (hasOwnership ())
251+ return optimizeBuiltinCOWBufferForReadingOSSA (BI);
252+ return optimizeBuiltinCOWBufferForReadingNonOSSA (BI);
253+ }
254+
159255static unsigned getTypeWidth (SILType Ty) {
160256 if (auto BuiltinIntTy = Ty.getAs <BuiltinIntegerType>()) {
161257 if (BuiltinIntTy->isFixedWidth ()) {
0 commit comments