1717#include " swift/Basic/FrozenMultiMap.h"
1818#include " swift/Basic/ImmutablePointerSet.h"
1919#include " swift/Basic/LLVM.h"
20+ #include " swift/SIL/SILFunction.h"
2021#include " swift/SIL/SILInstruction.h"
2122#include " llvm/ADT/SmallVector.h"
2223#include " llvm/Support/Debug.h"
@@ -204,7 +205,7 @@ class SILIsolationInfo {
204205 return getActorIsolated (actorIsolation);
205206 if (nomDecl->isActor ())
206207 return {Kind::Actor, nomDecl};
207- return {} ;
208+ return SILIsolationInfo () ;
208209 }
209210
210211 static SILIsolationInfo getTaskIsolated (SILValue value) {
@@ -756,8 +757,8 @@ struct PartitionOpEvaluator {
756757 // value... emit an error.
757758 if (auto *transferredOperandSet = p.getTransferred (op.getOpArgs ()[1 ])) {
758759 for (auto transferredOperand : transferredOperandSet->data ()) {
759- handleLocalUseAfterTransfer (op, op.getOpArgs ()[1 ],
760- transferredOperand);
760+ handleLocalUseAfterTransferHelper (op, op.getOpArgs ()[1 ],
761+ transferredOperand);
761762 }
762763 }
763764 p.assignElement (op.getOpArgs ()[0 ], op.getOpArgs ()[1 ]);
@@ -789,6 +790,21 @@ struct PartitionOpEvaluator {
789790 std::tie (transferredRegionIsolation, isClosureCapturedElt) =
790791 getIsolationRegionInfo (transferredRegion, op.getSourceOp ());
791792
793+ // Before we do anything, see if our dynamic isolation kind is the same as
794+ // the isolation info for our partition op. If they match, this is not a
795+ // real transfer operation.
796+ //
797+ // DISCUSSION: We couldn't not emit this earlier since we needed the
798+ // dynamic isolation info of our value.
799+ if (transferredRegionIsolation.isActorIsolated ()) {
800+ if (auto calleeIsolationInfo =
801+ SILIsolationInfo::get (op.getSourceInst ())) {
802+ if (transferredRegionIsolation == calleeIsolationInfo) {
803+ return ;
804+ }
805+ }
806+ }
807+
792808 // If we merged anything, we need to handle a transfer
793809 // non-transferrable. We pass in the dynamic isolation region info of our
794810 // region.
@@ -824,14 +840,14 @@ struct PartitionOpEvaluator {
824840 // if attempting to merge a transferred region, handle the failure
825841 if (auto *transferredOperandSet = p.getTransferred (op.getOpArgs ()[0 ])) {
826842 for (auto transferredOperand : transferredOperandSet->data ()) {
827- handleLocalUseAfterTransfer (op, op.getOpArgs ()[0 ],
828- transferredOperand);
843+ handleLocalUseAfterTransferHelper (op, op.getOpArgs ()[0 ],
844+ transferredOperand);
829845 }
830846 }
831847 if (auto *transferredOperandSet = p.getTransferred (op.getOpArgs ()[1 ])) {
832848 for (auto transferredOperand : transferredOperandSet->data ()) {
833- handleLocalUseAfterTransfer (op, op.getOpArgs ()[1 ],
834- transferredOperand);
849+ handleLocalUseAfterTransferHelper (op, op.getOpArgs ()[1 ],
850+ transferredOperand);
835851 }
836852 }
837853
@@ -844,8 +860,8 @@ struct PartitionOpEvaluator {
844860 " Require PartitionOp's argument should already be tracked" );
845861 if (auto *transferredOperandSet = p.getTransferred (op.getOpArgs ()[0 ])) {
846862 for (auto transferredOperand : transferredOperandSet->data ()) {
847- handleLocalUseAfterTransfer (op, op.getOpArgs ()[0 ],
848- transferredOperand);
863+ handleLocalUseAfterTransferHelper (op, op.getOpArgs ()[0 ],
864+ transferredOperand);
849865 }
850866 }
851867 return ;
@@ -858,6 +874,43 @@ struct PartitionOpEvaluator {
858874 for (auto &o : ops)
859875 apply (o);
860876 }
877+
878+ // / Provides a way for subclasses to disable the error squelching
879+ // / functionality.
880+ // /
881+ // / Used by the unittests.
882+ bool shouldTryToSquelchErrors () const {
883+ return asImpl ().shouldTryToSquelchErrors ();
884+ }
885+
886+ private:
887+ // Private helper that squelches the error if our transfer instruction and our
888+ // use have the same isolation.
889+ void
890+ handleLocalUseAfterTransferHelper (const PartitionOp &op, Element elt,
891+ TransferringOperand *transferringOp) const {
892+ if (shouldTryToSquelchErrors ()) {
893+ if (auto isolationInfo = SILIsolationInfo::get (op.getSourceInst ())) {
894+ if (isolationInfo.isActorIsolated () &&
895+ isolationInfo == SILIsolationInfo::get (transferringOp->getUser ()))
896+ return ;
897+ }
898+
899+ // If our instruction does not have any isolation info associated with it,
900+ // it must be nonisolated. See if our function has a matching isolation to
901+ // our transferring operand. If so, we can squelch this.
902+ if (auto functionIsolation =
903+ transferringOp->getUser ()->getFunction ()->getActorIsolation ()) {
904+ if (functionIsolation->isActorIsolated () &&
905+ SILIsolationInfo::getActorIsolated (*functionIsolation) ==
906+ SILIsolationInfo::get (transferringOp->getUser ()))
907+ return ;
908+ }
909+ }
910+
911+ // Ok, we actually need to emit a call to the callback.
912+ return handleLocalUseAfterTransfer (op, elt, transferringOp);
913+ }
861914};
862915
863916// / A base implementation that can be used to default initialize CRTP
@@ -927,6 +980,9 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
927980 // / to access the instruction in the evaluator which creates a problem when
928981 // / since the operand we pass in is a dummy operand.
929982 bool isClosureCaptured (Element elt, Operand *op) const { return false ; }
983+
984+ // / By default squelch errors.
985+ bool shouldTryToSquelchErrors () const { return true ; }
930986};
931987
932988// / A subclass of PartitionOpEvaluatorBaseImpl that doesn't have any special
0 commit comments