1919#include " swift/Basic/LLVM.h"
2020#include " swift/SIL/SILFunction.h"
2121#include " swift/SIL/SILInstruction.h"
22+ #include " swift/SILOptimizer/Utils/InstOptUtils.h"
2223#include " swift/SILOptimizer/Utils/SILIsolationInfo.h"
2324
2425#include " llvm/ADT/MapVector.h"
@@ -963,6 +964,14 @@ struct PartitionOpEvaluator {
963964 return Impl::getIsolationInfo (partitionOp);
964965 }
965966
967+ std::optional<Element> getElement (SILValue value) const {
968+ return asImpl ().getElement (value);
969+ }
970+
971+ SILValue getRepresentative (SILValue value) const {
972+ return asImpl ().getRepresentative (value);
973+ }
974+
966975 // / Apply \p op to the partition op.
967976 void apply (const PartitionOp &op) const {
968977 if (shouldEmitVerboseLogging ()) {
@@ -1018,10 +1027,16 @@ struct PartitionOpEvaluator {
10181027 assert (p.isTrackingElement (op.getOpArgs ()[0 ]) &&
10191028 " Transfer PartitionOp's argument should already be tracked" );
10201029
1030+ // Before we do any further work, see if we have a nonisolated(unsafe)
1031+ // element. In such a case, this is also not a real transfer point.
1032+ Element transferredElement = op.getOpArgs ()[0 ];
1033+ if (getIsolationRegionInfo (transferredElement).isUnsafeNonIsolated ()) {
1034+ return ;
1035+ }
1036+
10211037 // Otherwise, we need to merge our isolation region info with the
10221038 // isolation region info of everything else in our region. This is the
10231039 // dynamic isolation region info found by the dataflow.
1024- Element transferredElement = op.getOpArgs ()[0 ];
10251040 Region transferredRegion = p.getRegion (transferredElement);
10261041 bool isClosureCapturedElt = false ;
10271042 SILIsolationInfo transferredRegionIsolation;
@@ -1045,8 +1060,8 @@ struct PartitionOpEvaluator {
10451060 // region.
10461061 if (bool (transferredRegionIsolation) &&
10471062 !transferredRegionIsolation.isDisconnected ()) {
1048- return handleTransferNonTransferrable (op, op.getOpArgs ()[0 ],
1049- transferredRegionIsolation);
1063+ return handleTransferNonTransferrableHelper (op, op.getOpArgs ()[0 ],
1064+ transferredRegionIsolation);
10501065 }
10511066
10521067 // Mark op.getOpArgs()[0] as transferred.
@@ -1136,6 +1151,24 @@ struct PartitionOpEvaluator {
11361151 return ;
11371152 }
11381153
1154+ // If we have a temporary that is initialized with an unsafe nonisolated
1155+ // value... squelch the error like if we were that value.
1156+ //
1157+ // TODO: This goes away with opaque values.
1158+ if (SILValue equivalenceClassRep =
1159+ getRepresentative (transferringOp->get ())) {
1160+ if (auto *asi = dyn_cast<AllocStackInst>(equivalenceClassRep)) {
1161+ if (SILValue value = getInitOfTemporaryAllocStack (asi)) {
1162+ if (auto elt = getElement (value)) {
1163+ SILIsolationInfo eltIsolationInfo = getIsolationRegionInfo (*elt);
1164+ if (eltIsolationInfo.isUnsafeNonIsolated ()) {
1165+ return ;
1166+ }
1167+ }
1168+ }
1169+ }
1170+ }
1171+
11391172 // If our instruction does not have any isolation info associated with it,
11401173 // it must be nonisolated. See if our function has a matching isolation to
11411174 // our transferring operand. If so, we can squelch this.
@@ -1151,6 +1184,35 @@ struct PartitionOpEvaluator {
11511184 // Ok, we actually need to emit a call to the callback.
11521185 return handleLocalUseAfterTransfer (op, elt, transferringOp);
11531186 }
1187+
1188+ // Private helper that squelches the error if our transfer instruction and our
1189+ // use have the same isolation.
1190+ void handleTransferNonTransferrableHelper (
1191+ const PartitionOp &op, Element elt,
1192+ SILIsolationInfo dynamicMergedIsolationInfo) const {
1193+ if (shouldTryToSquelchErrors ()) {
1194+ // If we have a temporary that is initialized with an unsafe nonisolated
1195+ // value... squelch the error like if we were that value.
1196+ //
1197+ // TODO: This goes away with opaque values.
1198+ if (SILValue equivalenceClassRep =
1199+ getRepresentative (op.getSourceOp ()->get ())) {
1200+ if (auto *asi = dyn_cast<AllocStackInst>(equivalenceClassRep)) {
1201+ if (SILValue value = getInitOfTemporaryAllocStack (asi)) {
1202+ if (auto elt = getElement (value)) {
1203+ SILIsolationInfo eltIsolationInfo = getIsolationRegionInfo (*elt);
1204+ if (eltIsolationInfo.isUnsafeNonIsolated ()) {
1205+ return ;
1206+ }
1207+ }
1208+ }
1209+ }
1210+ }
1211+ }
1212+
1213+ // Ok, we actually need to emit a call to the callback.
1214+ return handleTransferNonTransferrable (op, elt, dynamicMergedIsolationInfo);
1215+ }
11541216};
11551217
11561218// / A base implementation that can be used to default initialize CRTP
@@ -1213,6 +1275,15 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
12131275 return SILIsolationInfo ();
12141276 }
12151277
1278+ // / If we are able to, return the element associated with \p value. If
1279+ // / unsupported, returns none.
1280+ std::optional<Element> getElement (SILValue value) const { return {}; }
1281+
1282+ // / If supported, returns the representative in \p value's equivalence
1283+ // / class. Returns an empty SILValue if this is unsupported or if it does not
1284+ // / have one.
1285+ SILValue getRepresentative (SILValue value) const { return SILValue (); }
1286+
12161287 // / Check if the representative value of \p elt is closure captured at \p
12171288 // / op.
12181289 // /
0 commit comments