@@ -145,200 +145,12 @@ STATISTIC(NumCopiesGenerated, "number of copy_value instructions created");
145145STATISTIC (NumDestroysGenerated, " number of destroy_value instructions created" );
146146STATISTIC (NumUnknownUsers, " number of functions with unknown users" );
147147
148- // ===----------------------------------------------------------------------===//
149- // Ownership Abstraction.
150- //
151- // FIXME: These helpers are only defined in this pass for prototyping. After
152- // bootstrapping, they should be moved to a central ownership API (shared by
153- // SILOwnershipVerifier, etc.).
154- //
155- // Categories of owned value users. (U1-U2 apply to any value, O3-O5 only apply
156- // to owned values).
157- //
158- // U1. Use the value instantaneously (copy_value, @guaranteed).
159- //
160- // U2. Escape the nontrivial contents of the value (ref_to_unowned,
161- // unchecked_trivial_bitcast).
162- //
163- // O3. Propagate the value without consuming it (mark_dependence, begin_borrow).
164- //
165- // O4. Consume the value immediately (store, destroy, @owned, destructure).
166- //
167- // O5. Consume the value indirectly via a move (tuple, struct).
168- // ===---------------------------------------------------------------------===//
169-
170- // TODO: Figure out how to handle these cases if possible.
171- static bool isUnknownUse (Operand *use) {
172- switch (use->getUser ()->getKind ()) {
173- default :
174- return false ;
175- // FIXME: (Category O3) mark_dependence requires recursion to find all
176- // uses. It should be replaced by begin/end dependence.
177- case SILInstructionKind::MarkDependenceInst: // Dependent
178- // FIXME: (Category O3) ref_tail_addr should require a borrow because it
179- // doesn't rely on fix_lifetime like other escaping instructions.
180- case SILInstructionKind::RefTailAddrInst:
181- // FIXME: (Category O3) dynamic_method_br seems to capture self, presumably
182- // propagating lifetime. This should probably borrow self, then be treated
183- // like mark_dependence.
184- case SILInstructionKind::DynamicMethodBranchInst:
185- // FIXME: (Category O3) The ownership verifier says project_box can accept an
186- // owned value as a normal use, but it projects the address. That's either an
187- // ownership bug or a special case.
188- case SILInstructionKind::ProjectBoxInst:
189- case SILInstructionKind::ProjectExistentialBoxInst:
190- // FIXME: (Category O3) The ownership verifier says open_existential_box can
191- // accept an owned value as a normal use, but it projects an address.
192- case SILInstructionKind::OpenExistentialBoxInst:
193- // Unmanaged operations hopefully don't apply to the same value as CopyValue?
194- case SILInstructionKind::UnmanagedRetainValueInst:
195- case SILInstructionKind::UnmanagedReleaseValueInst:
196- case SILInstructionKind::UnmanagedAutoreleaseValueInst:
197- return true ;
198- }
199- }
200-
201- // / Return true if the given owned operand is consumed by the given call.
202- static bool isAppliedArgConsumed (ApplySite apply, Operand *oper) {
203- ParameterConvention paramConv;
204- if (oper->get () == apply.getCallee ()) {
205- assert (oper->getOperandNumber () == 0
206- && " function can't be passed to itself" );
207- paramConv = apply.getSubstCalleeType ()->getCalleeConvention ();
208- } else {
209- unsigned argIndex = apply.getCalleeArgIndex (*oper);
210- paramConv = apply.getSubstCalleeConv ()
211- .getParamInfoForSILArg (argIndex)
212- .getConvention ();
213- }
214- return isConsumedParameter (paramConv);
215- }
216-
217- // / Return true if the given builtin consumes its operand.
218- static bool isBuiltinArgConsumed (BuiltinInst *BI) {
219- const BuiltinInfo &Builtin = BI->getBuiltinInfo ();
220- switch (Builtin.ID ) {
221- default :
222- llvm_unreachable (" Unexpected Builtin with owned value operand." );
223- // Extend lifetime without consuming.
224- case BuiltinValueKind::ErrorInMain:
225- case BuiltinValueKind::UnexpectedError:
226- case BuiltinValueKind::WillThrow:
227- return false ;
228- // UnsafeGuaranteed moves the value, which will later be destroyed.
229- case BuiltinValueKind::UnsafeGuaranteed:
230- return true ;
231- }
232- }
233-
234- // / Return true if the given operand is consumed by its user.
235- // /
236- // / TODO: Review the semantics of operations that extend the lifetime *without*
237- // / propagating the value. Ideally, that never happens without borrowing first.
238- static bool isConsuming (Operand *use) {
239- auto *user = use->getUser ();
240- if (isa<ApplySite>(user))
241- return isAppliedArgConsumed (ApplySite (user), use);
242-
243- if (auto *BI = dyn_cast<BuiltinInst>(user))
244- return isBuiltinArgConsumed (BI);
245-
246- switch (user->getKind ()) {
247- default :
248- llvm::dbgs () << *user;
249- llvm_unreachable (" Unexpected use of a loadable owned value." );
250-
251- // Consume the value.
252- case SILInstructionKind::AutoreleaseValueInst:
253- case SILInstructionKind::DeallocBoxInst:
254- case SILInstructionKind::DeallocExistentialBoxInst:
255- case SILInstructionKind::DeallocRefInst:
256- case SILInstructionKind::DeinitExistentialValueInst:
257- case SILInstructionKind::DestroyValueInst:
258- case SILInstructionKind::EndLifetimeInst:
259- case SILInstructionKind::InitExistentialRefInst:
260- case SILInstructionKind::InitExistentialValueInst:
261- case SILInstructionKind::KeyPathInst:
262- case SILInstructionKind::ReleaseValueInst:
263- case SILInstructionKind::ReleaseValueAddrInst:
264- case SILInstructionKind::StoreInst:
265- case SILInstructionKind::StrongReleaseInst:
266- case SILInstructionKind::UnownedReleaseInst:
267- case SILInstructionKind::UnconditionalCheckedCastValueInst:
268- return true ;
269-
270- // Terminators must consume their owned values.
271- case SILInstructionKind::BranchInst:
272- case SILInstructionKind::CheckedCastBranchInst:
273- case SILInstructionKind::CheckedCastValueBranchInst:
274- case SILInstructionKind::CondBranchInst:
275- case SILInstructionKind::ReturnInst:
276- case SILInstructionKind::ThrowInst:
277- return true ;
278-
279- case SILInstructionKind::DeallocPartialRefInst:
280- return cast<DeallocPartialRefInst>(user)->getInstance () == use->get ();
281-
282- // Move the value.
283- case SILInstructionKind::TupleInst:
284- case SILInstructionKind::StructInst:
285- case SILInstructionKind::ObjectInst:
286- case SILInstructionKind::EnumInst:
287- case SILInstructionKind::OpenExistentialRefInst:
288- case SILInstructionKind::UpcastInst:
289- case SILInstructionKind::UncheckedRefCastInst:
290- case SILInstructionKind::ConvertFunctionInst:
291- case SILInstructionKind::RefToBridgeObjectInst:
292- case SILInstructionKind::BridgeObjectToRefInst:
293- case SILInstructionKind::UnconditionalCheckedCastInst:
294- case SILInstructionKind::MarkUninitializedInst:
295- case SILInstructionKind::UncheckedEnumDataInst:
296- case SILInstructionKind::DestructureStructInst:
297- case SILInstructionKind::DestructureTupleInst:
298- return true ;
299-
300- // BeginBorrow should already be skipped.
301- // EndBorrow extends the lifetime like a normal use.
302- case SILInstructionKind::EndBorrowInst:
303- return false ;
304-
305- // Extend the lifetime without borrowing, propagating, or destroying it.
306- case SILInstructionKind::BridgeObjectToWordInst:
307- case SILInstructionKind::ClassMethodInst:
308- case SILInstructionKind::CopyBlockInst:
309- case SILInstructionKind::CopyValueInst:
310- case SILInstructionKind::DebugValueInst:
311- case SILInstructionKind::ExistentialMetatypeInst:
312- case SILInstructionKind::FixLifetimeInst:
313- case SILInstructionKind::SelectEnumInst:
314- case SILInstructionKind::SetDeallocatingInst:
315- case SILInstructionKind::StoreWeakInst:
316- case SILInstructionKind::ValueMetatypeInst:
317- return false ;
318-
319- // Escape the value. The lifetime must already be enforced via something like
320- // fix_lifetime.
321- case SILInstructionKind::RefToRawPointerInst:
322- case SILInstructionKind::RefToUnmanagedInst:
323- case SILInstructionKind::RefToUnownedInst:
324- case SILInstructionKind::UncheckedBitwiseCastInst:
325- case SILInstructionKind::UncheckedTrivialBitCastInst:
326- return false ;
327-
328- // Dynamic dispatch without capturing self.
329- case SILInstructionKind::ObjCMethodInst:
330- case SILInstructionKind::ObjCSuperMethodInst:
331- case SILInstructionKind::SuperMethodInst:
332- case SILInstructionKind::WitnessMethodInst:
333- return false ;
334- }
335- }
336-
337148// ===----------------------------------------------------------------------===//
338149// CopyPropagationState: shared state for the pass's analysis and transforms.
339150// ===----------------------------------------------------------------------===//
340151
341152namespace {
153+
342154// / LiveWithin blocks have at least one use and/or def within the block, but are
343155// / not LiveOut.
344156// /
@@ -357,9 +169,10 @@ class LivenessInfo {
357169 // used value is consumed. (Non-consuming uses within a block that is already
358170 // known to be live are uninteresting.)
359171 DenseMap<SILInstruction *, bool > users;
172+
360173 // Original points in the CFG where the current value was consumed or
361174 // destroyed.
362- typedef SmallSetVector<SILBasicBlock *, 8 > BlockSetVec ;
175+ using BlockSetVec = SmallSetVector<SILBasicBlock *, 8 >;
363176 BlockSetVec originalDestroyBlocks;
364177
365178public:
@@ -409,7 +222,7 @@ class LivenessInfo {
409222 //
410223 // This call cannot be allowed to destroy %val.
411224 void recordUser (Operand *use) {
412- bool consume = isConsuming ( use);
225+ bool consume = use-> isConsumingUse ( );
413226 auto iterAndSuccess = users.try_emplace (use->getUser (), consume);
414227 if (!iterAndSuccess.second )
415228 iterAndSuccess.first ->second &= consume;
@@ -468,7 +281,7 @@ class DestroyInfo {
468281
469282// / This pass' shared state.
470283struct CopyPropagationState {
471- SILFunction *F ;
284+ SILFunction *func ;
472285
473286 // Per-function invalidation state.
474287 unsigned invalidation;
@@ -483,7 +296,7 @@ struct CopyPropagationState {
483296 DestroyInfo destroys;
484297
485298 CopyPropagationState (SILFunction *F)
486- : F (F), invalidation(SILAnalysis::InvalidationKind::Nothing) {}
299+ : func (F), invalidation(SILAnalysis::InvalidationKind::Nothing) {}
487300
488301 bool isValueOwned () const {
489302 return currDef.getOwnershipKind () == ValueOwnershipKind::Owned;
@@ -600,27 +413,23 @@ static bool computeLiveness(CopyPropagationState &pass) {
600413 for (Operand *use : value->getUses ()) {
601414 auto *user = use->getUser ();
602415
603- // Bailout if we cannot yet determine the ownership of a use.
604- if (isUnknownUse (use)) {
605- LLVM_DEBUG (llvm::dbgs () << " Unknown owned value user: " ; user->dump ());
606- ++NumUnknownUsers;
607- return false ;
608- }
609416 // Recurse through copies.
610417 if (auto *copy = dyn_cast<CopyValueInst>(user)) {
611418 defUseWorkList.insert (copy);
612419 continue ;
613420 }
421+
614422 // An entire borrow scope is considered a single use that occurs at the
615423 // point of the end_borrow.
616- if (auto *BBI = dyn_cast<BeginBorrowInst>(user)) {
617- for (Operand *use : BBI ->getUses ()) {
424+ if (auto *bbi = dyn_cast<BeginBorrowInst>(user)) {
425+ for (Operand *use : bbi ->getUses ()) {
618426 if (isa<EndBorrowInst>(use->getUser ()))
619427 computeUseLiveness (use, pass);
620428 }
621429 continue ;
622430 }
623- if (isConsuming (use)) {
431+
432+ if (use->isConsumingUse ()) {
624433 pass.liveness .recordOriginalDestroy (use);
625434 // Destroying a values does not force liveness.
626435 if (isa<DestroyValueInst>(user))
@@ -649,13 +458,14 @@ static void insertDestroyOnCFGEdge(SILBasicBlock *predBB, SILBasicBlock *succBB,
649458 if (destroyBB != succBB)
650459 pass.markInvalid (SILAnalysis::InvalidationKind::Branches);
651460
652- SILBuilderWithScope B (destroyBB->begin ());
653- auto *DI = B.createDestroyValue (succBB->begin ()->getLoc (), pass.currDef );
461+ SILBuilderWithScope builder (destroyBB->begin ());
462+ auto *di =
463+ builder.createDestroyValue (succBB->begin ()->getLoc (), pass.currDef );
654464
655- pass.destroys .recordFinalDestroy (DI );
465+ pass.destroys .recordFinalDestroy (di );
656466
657467 ++NumDestroysGenerated;
658- LLVM_DEBUG (llvm::dbgs () << " Destroy on edge " ; DI ->dump ());
468+ LLVM_DEBUG (llvm::dbgs () << " Destroy on edge " ; di ->dump ());
659469
660470 pass.markInvalid (SILAnalysis::InvalidationKind::Instructions);
661471}
@@ -665,11 +475,11 @@ static void insertDestroyOnCFGEdge(SILBasicBlock *predBB, SILBasicBlock *succBB,
665475// / Create a final destroy, immediately after `pos`.
666476static void insertDestroyAtInst (SILBasicBlock::iterator pos,
667477 CopyPropagationState &pass) {
668- SILBuilderWithScope B (pos);
669- auto *DI = B .createDestroyValue ((*pos).getLoc (), pass.currDef );
670- pass.destroys .recordFinalDestroy (DI );
478+ SILBuilderWithScope builder (pos);
479+ auto *di = builder .createDestroyValue ((*pos).getLoc (), pass.currDef );
480+ pass.destroys .recordFinalDestroy (di );
671481 ++NumDestroysGenerated;
672- LLVM_DEBUG (llvm::dbgs () << " Destroy at last use " ; DI ->dump ());
482+ LLVM_DEBUG (llvm::dbgs () << " Destroy at last use " ; di ->dump ());
673483 pass.markInvalid (SILAnalysis::InvalidationKind::Instructions);
674484}
675485
@@ -679,9 +489,9 @@ static void insertDestroyAtInst(SILBasicBlock::iterator pos,
679489static void findOrInsertDestroyInBlock (SILBasicBlock *bb,
680490 CopyPropagationState &pass) {
681491 auto *defInst = pass.currDef ->getDefiningInstruction ();
682- auto I = bb->getTerminator ()->getIterator ();
492+ auto instIter = bb->getTerminator ()->getIterator ();
683493 while (true ) {
684- auto *inst = &*I ;
494+ auto *inst = &*instIter ;
685495 Optional<bool > isConsumingResult = pass.liveness .isConsumingUser (inst);
686496 if (isConsumingResult.hasValue ()) {
687497 if (isConsumingResult.getValue ()) {
@@ -691,20 +501,20 @@ static void findOrInsertDestroyInBlock(SILBasicBlock *bb,
691501 }
692502 // Insert a destroy after this non-consuming use.
693503 assert (inst != bb->getTerminator () && " Terminator must consume operand." );
694- insertDestroyAtInst (std::next (I ), pass);
504+ insertDestroyAtInst (std::next (instIter ), pass);
695505 break ;
696506 }
697507 // This is not a potential last user. Keep scanning.
698508 // If the original destroy is reached, this is a dead live range. Insert a
699509 // destroy immediately after the def.
700- if (I == bb->begin ()) {
510+ if (instIter == bb->begin ()) {
701511 assert (cast<SILArgument>(pass.currDef )->getParent () == bb);
702- insertDestroyAtInst (I , pass);
512+ insertDestroyAtInst (instIter , pass);
703513 break ;
704514 }
705- --I ;
706- if (&*I == defInst) {
707- insertDestroyAtInst (std::next (I ), pass);
515+ --instIter ;
516+ if (&*instIter == defInst) {
517+ insertDestroyAtInst (std::next (instIter ), pass);
708518 break ;
709519 }
710520 }
@@ -799,6 +609,7 @@ static void rewriteCopies(CopyPropagationState &pass) {
799609 defUseWorklist.insert (copy);
800610 return ;
801611 }
612+
802613 if (auto *destroy = dyn_cast<DestroyValueInst>(user)) {
803614 // If this destroy was marked as a final destroy, ignore it; otherwise,
804615 // delete it.
@@ -809,8 +620,9 @@ static void rewriteCopies(CopyPropagationState &pass) {
809620 }
810621 return ;
811622 }
623+
812624 // Nonconsuming uses do not need copies and cannot be marked as destroys.
813- if (!isConsuming ( use))
625+ if (!use-> isConsumingUse ( ))
814626 return ;
815627
816628 // If this use was marked as a final destroy *and* this is the first
@@ -862,6 +674,7 @@ static SILValue stripCopies(SILValue v) {
862674 v = srcCopy->getOperand ();
863675 continue ;
864676 }
677+
865678 return v;
866679 }
867680}
@@ -885,12 +698,13 @@ void CopyPropagation::run() {
885698 // Step 1. Find all copied defs.
886699 CopyPropagationState pass (getFunction ());
887700 SmallSetVector<SILValue, 16 > copiedDefs;
888- for (auto &BB : *pass.F ) {
889- for (auto &I : BB ) {
890- if (auto *copy = dyn_cast<CopyValueInst>(&I ))
701+ for (auto &bb : *pass.func ) {
702+ for (auto &i : bb ) {
703+ if (auto *copy = dyn_cast<CopyValueInst>(&i ))
891704 copiedDefs.insert (stripCopies (copy));
892705 }
893706 }
707+
894708 for (auto &def : copiedDefs) {
895709 pass.resetDef (def);
896710 // Step 2: computeLiveness
0 commit comments