Skip to content

Commit fc2bd05

Browse files
authored
Merge pull request swiftlang#34416 from gottesmm/pr-494b149e92fdf8f15a07109c6a33d12a1d3ab666
[copy-propagation] Since this runs on OSSA and we have formalized consuming there, use that instead of our own handrolled consuming use impl.
2 parents b385332 + bdd7b42 commit fc2bd05

File tree

1 file changed

+36
-222
lines changed

1 file changed

+36
-222
lines changed

lib/SILOptimizer/Transforms/CopyPropagation.cpp

Lines changed: 36 additions & 222 deletions
Original file line numberDiff line numberDiff line change
@@ -145,200 +145,12 @@ STATISTIC(NumCopiesGenerated, "number of copy_value instructions created");
145145
STATISTIC(NumDestroysGenerated, "number of destroy_value instructions created");
146146
STATISTIC(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

341152
namespace {
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

365178
public:
@@ -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.
470283
struct 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`.
666476
static 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,
679489
static 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

Comments
 (0)