19
19
#include " swift/Basic/LLVM.h"
20
20
#include " swift/SIL/SILFunction.h"
21
21
#include " swift/SIL/SILInstruction.h"
22
+ #include " swift/SILOptimizer/Utils/InstOptUtils.h"
22
23
#include " swift/SILOptimizer/Utils/SILIsolationInfo.h"
23
24
24
25
#include " llvm/ADT/MapVector.h"
@@ -963,6 +964,14 @@ struct PartitionOpEvaluator {
963
964
return Impl::getIsolationInfo (partitionOp);
964
965
}
965
966
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
+
966
975
// / Apply \p op to the partition op.
967
976
void apply (const PartitionOp &op) const {
968
977
if (shouldEmitVerboseLogging ()) {
@@ -1018,10 +1027,16 @@ struct PartitionOpEvaluator {
1018
1027
assert (p.isTrackingElement (op.getOpArgs ()[0 ]) &&
1019
1028
" Transfer PartitionOp's argument should already be tracked" );
1020
1029
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
+
1021
1037
// Otherwise, we need to merge our isolation region info with the
1022
1038
// isolation region info of everything else in our region. This is the
1023
1039
// dynamic isolation region info found by the dataflow.
1024
- Element transferredElement = op.getOpArgs ()[0 ];
1025
1040
Region transferredRegion = p.getRegion (transferredElement);
1026
1041
bool isClosureCapturedElt = false ;
1027
1042
SILIsolationInfo transferredRegionIsolation;
@@ -1045,8 +1060,8 @@ struct PartitionOpEvaluator {
1045
1060
// region.
1046
1061
if (bool (transferredRegionIsolation) &&
1047
1062
!transferredRegionIsolation.isDisconnected ()) {
1048
- return handleTransferNonTransferrable (op, op.getOpArgs ()[0 ],
1049
- transferredRegionIsolation);
1063
+ return handleTransferNonTransferrableHelper (op, op.getOpArgs ()[0 ],
1064
+ transferredRegionIsolation);
1050
1065
}
1051
1066
1052
1067
// Mark op.getOpArgs()[0] as transferred.
@@ -1136,6 +1151,24 @@ struct PartitionOpEvaluator {
1136
1151
return ;
1137
1152
}
1138
1153
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
+
1139
1172
// If our instruction does not have any isolation info associated with it,
1140
1173
// it must be nonisolated. See if our function has a matching isolation to
1141
1174
// our transferring operand. If so, we can squelch this.
@@ -1151,6 +1184,35 @@ struct PartitionOpEvaluator {
1151
1184
// Ok, we actually need to emit a call to the callback.
1152
1185
return handleLocalUseAfterTransfer (op, elt, transferringOp);
1153
1186
}
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
+ }
1154
1216
};
1155
1217
1156
1218
// / A base implementation that can be used to default initialize CRTP
@@ -1213,6 +1275,15 @@ struct PartitionOpEvaluatorBaseImpl : PartitionOpEvaluator<Subclass> {
1213
1275
return SILIsolationInfo ();
1214
1276
}
1215
1277
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
+
1216
1287
// / Check if the representative value of \p elt is closure captured at \p
1217
1288
// / op.
1218
1289
// /
0 commit comments