@@ -432,6 +432,53 @@ static bool isTransferrableFunctionArgument(SILFunctionArgument *arg) {
432
432
return arg->isTransferring ();
433
433
}
434
434
435
+ // ===----------------------------------------------------------------------===//
436
+ // MARK: TrackableValue
437
+ // ===----------------------------------------------------------------------===//
438
+
439
+ bool TrackableValue::isTransferringParameter () const {
440
+ // First get our alloc_stack.
441
+ //
442
+ // TODO: We should just put a flag on the alloc_stack, so we /know/ 100% that
443
+ // it is from a consuming parameter. We don't have that so we pattern match.
444
+ auto *asi =
445
+ dyn_cast_or_null<AllocStackInst>(representativeValue.maybeGetValue ());
446
+ if (!asi)
447
+ return false ;
448
+
449
+ if (asi->getParent () != asi->getFunction ()->getEntryBlock ())
450
+ return false ;
451
+
452
+ // See if we are initialized from a transferring parameter and are the only
453
+ // use of the parameter.
454
+ for (auto *use : asi->getUses ()) {
455
+ auto *user = use->getUser ();
456
+
457
+ if (auto *si = dyn_cast<StoreInst>(user)) {
458
+ // Check if our store inst is from a function argument that is
459
+ // transferring. If not, then this isn't the consuming parameter
460
+ // alloc_stack.
461
+ auto *fArg = dyn_cast<SILFunctionArgument>(si->getSrc ());
462
+ if (!fArg || !fArg ->isTransferring ())
463
+ return false ;
464
+ return fArg ->getSingleUse ();
465
+ }
466
+
467
+ if (auto *copyAddr = dyn_cast<CopyAddrInst>(user)) {
468
+ // Check if our store inst is from a function argument that is
469
+ // transferring. If not, then this isn't the consuming parameter
470
+ // alloc_stack.
471
+ auto *fArg = dyn_cast<SILFunctionArgument>(copyAddr->getSrc ());
472
+ if (!fArg || !fArg ->isTransferring ())
473
+ return false ;
474
+ return fArg ->getSingleUse ();
475
+ }
476
+ }
477
+
478
+ // Otherwise, this isn't a consuming parameter.
479
+ return false ;
480
+ }
481
+
435
482
// ===----------------------------------------------------------------------===//
436
483
// MARK: Partial Apply Reachability
437
484
// ===----------------------------------------------------------------------===//
@@ -1701,13 +1748,52 @@ class PartitionOpTranslator {
1701
1748
return translateSILMerge (dest, TinyPtrVector<SILValue>(src));
1702
1749
}
1703
1750
1704
- // / If tgt is known to be unaliased (computed thropugh a combination of
1751
+ void translateSILAssignmentToTransferringParameter (TrackableValue destRoot,
1752
+ Operand *destOperand,
1753
+ TrackableValue srcRoot,
1754
+ Operand *srcOperand) {
1755
+ assert (isa<AllocStackInst>(destRoot.getRepresentative ().getValue ()) &&
1756
+ " Destination should always be an alloc_stack" );
1757
+
1758
+ // Transfer src. This ensures that we cannot use src again locally in this
1759
+ // function... which makes sense since its value is now in the transferring
1760
+ // parameter.
1761
+ builder.addTransfer (srcRoot.getRepresentative ().getValue (), srcOperand);
1762
+
1763
+ // Then check if we are assigning into an aggregate projection. In such a
1764
+ // case, we want to ensure that we keep tracking the elements already in the
1765
+ // region of transferring. This is more conservative than we need to be
1766
+ // (since we could forget anything reachable from the aggregate
1767
+ // field)... but being more conservative is ok.
1768
+ if (isProjectedFromAggregate (destOperand->get ()))
1769
+ return ;
1770
+
1771
+ // If we are assigning over the entire value though, we perform an assign
1772
+ // fresh since we are guaranteed that any value that could be referenced via
1773
+ // the old value is gone.
1774
+ builder.addAssignFresh (destRoot.getRepresentative ().getValue ());
1775
+ }
1776
+
1777
+ // / If \p dest is known to be unaliased (computed through a combination of
1705
1778
// / AccessStorage's inUniquelyIdenfitied check and a custom search for
1706
- // / captures by applications), then these can be treated as assignments of tgt
1707
- // / to src. If the tgt could be aliased, then we must instead treat them as
1708
- // / merges, to ensure any aliases of tgt are also updated.
1709
- void translateSILStore (SILValue dest, SILValue src) {
1710
- if (auto nonSendableTgt = tryToTrackValue (dest)) {
1779
+ // / captures by applications), then these can be treated as assignments of \p
1780
+ // / dest to src. If the \p dest could be aliased, then we must instead treat
1781
+ // / them as merges, to ensure any aliases of \p dest are also updated.
1782
+ void translateSILStore (Operand *dest, Operand *src) {
1783
+ SILValue destValue = dest->get ();
1784
+ SILValue srcValue = src->get ();
1785
+
1786
+ if (auto nonSendableDest = tryToTrackValue (destValue)) {
1787
+ // Before we do anything check if we have an assignment into an
1788
+ // alloc_stack for a consuming transferring parameter... in such a case,
1789
+ // we need to handle this specially.
1790
+ if (nonSendableDest->isTransferringParameter ()) {
1791
+ if (auto nonSendableSrc = tryToTrackValue (srcValue)) {
1792
+ return translateSILAssignmentToTransferringParameter (
1793
+ *nonSendableDest, dest, *nonSendableSrc, src);
1794
+ }
1795
+ }
1796
+
1711
1797
// In the following situations, we can perform an assign:
1712
1798
//
1713
1799
// 1. A store to unaliased storage.
@@ -1719,11 +1805,12 @@ class PartitionOpTranslator {
1719
1805
// specifically in this projection... but that is better than
1720
1806
// miscompiling. For memory like this, we probably need to track it on a
1721
1807
// per field basis to allow for us to assign.
1722
- if (nonSendableTgt.value ().isNoAlias () && !isProjectedFromAggregate (dest))
1723
- return translateSILAssign (dest, src);
1808
+ if (nonSendableDest.value ().isNoAlias () &&
1809
+ !isProjectedFromAggregate (destValue))
1810
+ return translateSILAssign (destValue, srcValue);
1724
1811
1725
1812
// Stores to possibly aliased storage must be treated as merges.
1726
- return translateSILMerge (dest, src );
1813
+ return translateSILMerge (destValue, srcValue );
1727
1814
}
1728
1815
1729
1816
// Stores to storage of non-Sendable type can be ignored.
@@ -1859,8 +1946,9 @@ class PartitionOpTranslator {
1859
1946
return translateSILLookThrough (inst->getResults (), inst->getOperand (0 ));
1860
1947
1861
1948
case TranslationSemantics::Store:
1862
- return translateSILStore (inst->getOperand (CopyLikeInstruction::Dest),
1863
- inst->getOperand (CopyLikeInstruction::Src));
1949
+ return translateSILStore (
1950
+ &inst->getAllOperands ()[CopyLikeInstruction::Dest],
1951
+ &inst->getAllOperands ()[CopyLikeInstruction::Src]);
1864
1952
1865
1953
case TranslationSemantics::Special:
1866
1954
return ;
0 commit comments