@@ -432,6 +432,53 @@ static bool isTransferrableFunctionArgument(SILFunctionArgument *arg) {
432432 return arg->isTransferring ();
433433}
434434
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+
435482// ===----------------------------------------------------------------------===//
436483// MARK: Partial Apply Reachability
437484// ===----------------------------------------------------------------------===//
@@ -1701,13 +1748,52 @@ class PartitionOpTranslator {
17011748 return translateSILMerge (dest, TinyPtrVector<SILValue>(src));
17021749 }
17031750
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
17051778 // / 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+
17111797 // In the following situations, we can perform an assign:
17121798 //
17131799 // 1. A store to unaliased storage.
@@ -1719,11 +1805,12 @@ class PartitionOpTranslator {
17191805 // specifically in this projection... but that is better than
17201806 // miscompiling. For memory like this, we probably need to track it on a
17211807 // 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);
17241811
17251812 // Stores to possibly aliased storage must be treated as merges.
1726- return translateSILMerge (dest, src );
1813+ return translateSILMerge (destValue, srcValue );
17271814 }
17281815
17291816 // Stores to storage of non-Sendable type can be ignored.
@@ -1859,8 +1946,9 @@ class PartitionOpTranslator {
18591946 return translateSILLookThrough (inst->getResults (), inst->getOperand (0 ));
18601947
18611948 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]);
18641952
18651953 case TranslationSemantics::Special:
18661954 return ;
0 commit comments