@@ -105,6 +105,10 @@ enum class PartitionOpKind : uint8_t {
105
105
// / Transfer the region of a value if not already transferred, takes one arg.
106
106
Transfer,
107
107
108
+ // / Due to an async let or something like that a value that was transferred is
109
+ // / no longer transferred.
110
+ UndoTransfer,
111
+
108
112
// / Require the region of a value to be non-transferred, takes one arg.
109
113
Require,
110
114
};
@@ -128,20 +132,26 @@ class PartitionOp {
128
132
PartitionOp (PartitionOpKind opKind, Element arg1,
129
133
SILInstruction *sourceInst = nullptr )
130
134
: opKind(opKind), opArgs({arg1}), source(sourceInst) {
131
- assert ((opKind != PartitionOpKind::Transfer || sourceInst) &&
135
+ assert (((opKind != PartitionOpKind::Transfer &&
136
+ opKind != PartitionOpKind::UndoTransfer) ||
137
+ sourceInst) &&
132
138
" Transfer needs a sourceInst" );
133
139
}
134
140
135
141
PartitionOp (PartitionOpKind opKind, Element arg1, Operand *sourceOperand)
136
142
: opKind(opKind), opArgs({arg1}), source(sourceOperand) {
137
- assert ((opKind != PartitionOpKind::Transfer || sourceOperand) &&
143
+ assert (((opKind != PartitionOpKind::Transfer &&
144
+ opKind != PartitionOpKind::UndoTransfer) ||
145
+ sourceOperand) &&
138
146
" Transfer needs a sourceInst" );
139
147
}
140
148
141
149
PartitionOp (PartitionOpKind opKind, Element arg1, Element arg2,
142
150
SILInstruction *sourceInst = nullptr )
143
151
: opKind(opKind), opArgs({arg1, arg2}), source(sourceInst) {
144
- assert ((opKind != PartitionOpKind::Transfer || sourceInst) &&
152
+ assert (((opKind != PartitionOpKind::Transfer &&
153
+ opKind != PartitionOpKind::UndoTransfer) ||
154
+ sourceInst) &&
145
155
" Transfer needs a sourceInst" );
146
156
}
147
157
@@ -162,6 +172,11 @@ class PartitionOp {
162
172
return PartitionOp (PartitionOpKind::Transfer, tgt, transferringOp);
163
173
}
164
174
175
+ static PartitionOp UndoTransfer (Element tgt,
176
+ SILInstruction *untransferringInst) {
177
+ return PartitionOp (PartitionOpKind::UndoTransfer, tgt, untransferringInst);
178
+ }
179
+
165
180
static PartitionOp Merge (Element tgt1, Element tgt2,
166
181
SILInstruction *sourceInst = nullptr ) {
167
182
return PartitionOp (PartitionOpKind::Merge, tgt1, tgt2, sourceInst);
@@ -222,6 +237,14 @@ class PartitionOp {
222
237
os << " %%" << opArgs[0 ];
223
238
break ;
224
239
}
240
+ case PartitionOpKind::UndoTransfer: {
241
+ constexpr static char extraSpaceLiteral[10 ] = " " ;
242
+ os << " undo_transfer " ;
243
+ if (extraSpace)
244
+ os << extraSpaceLiteral;
245
+ os << " %%" << opArgs[0 ];
246
+ break ;
247
+ }
225
248
case PartitionOpKind::Merge: {
226
249
constexpr static char extraSpaceLiteral[10 ] = " " ;
227
250
os << " merge " ;
@@ -354,6 +377,33 @@ class Partition {
354
377
return iter2.second ;
355
378
}
356
379
380
+ // / If val was marked as transferred, unmark it as transfer. Returns true if
381
+ // / we found that \p val was transferred. We return false otherwise.
382
+ bool undoTransfer (Element val) {
383
+ // First see if our val is tracked. If it is not tracked, insert it.
384
+ if (!isTracked (val)) {
385
+ elementToRegionMap.insert_or_assign (val, fresh_label);
386
+ fresh_label = Region (fresh_label + 1 );
387
+ canonical = false ;
388
+ return true ;
389
+ }
390
+
391
+ // Otherwise, we already have this value in the map. Remove it from the
392
+ // transferred map.
393
+ auto iter1 = elementToRegionMap.find (val);
394
+ assert (iter1 != elementToRegionMap.end ());
395
+ return regionToTransferredOpMap.erase (iter1->second );
396
+ }
397
+
398
+ void addElement (Element newElt) {
399
+ // Map index newElt to a fresh label.
400
+ elementToRegionMap.insert_or_assign (newElt, fresh_label);
401
+
402
+ // Increment the fresh label so it remains fresh.
403
+ fresh_label = Region (fresh_label + 1 );
404
+ canonical = false ;
405
+ }
406
+
357
407
// / Construct the partition corresponding to the union of the two passed
358
408
// / partitions.
359
409
// /
@@ -784,12 +834,7 @@ struct PartitionOpEvaluator {
784
834
assert (op.getOpArgs ().size () == 1 &&
785
835
" AssignFresh PartitionOp should be passed 1 argument" );
786
836
787
- // map index op.getOpArgs()[0] to a fresh label
788
- p.elementToRegionMap .insert_or_assign (op.getOpArgs ()[0 ], p.fresh_label );
789
-
790
- // increment the fresh label so it remains fresh
791
- p.fresh_label = Region (p.fresh_label + 1 );
792
- p.canonical = false ;
837
+ p.addElement (op.getOpArgs ()[0 ]);
793
838
break ;
794
839
case PartitionOpKind::Transfer: {
795
840
assert (op.getOpArgs ().size () == 1 &&
@@ -817,6 +862,7 @@ struct PartitionOpEvaluator {
817
862
// actor derived, we need to treat as nontransferrable.
818
863
if (isActorDerived (op.getOpArgs ()[0 ]))
819
864
return handleTransferNonTransferrable (op, op.getOpArgs ()[0 ]);
865
+
820
866
Region elementRegion = p.elementToRegionMap .at (op.getOpArgs ()[0 ]);
821
867
if (llvm::any_of (p.elementToRegionMap ,
822
868
[&](const std::pair<Element, Region> &pair) -> bool {
@@ -830,6 +876,16 @@ struct PartitionOpEvaluator {
830
876
p.markTransferred (op.getOpArgs ()[0 ], op.getSourceOp ());
831
877
break ;
832
878
}
879
+ case PartitionOpKind::UndoTransfer: {
880
+ assert (op.getOpArgs ().size () == 1 &&
881
+ " UndoTransfer PartitionOp should be passed 1 argument" );
882
+ assert (p.elementToRegionMap .count (op.getOpArgs ()[0 ]) &&
883
+ " UndoTransfer PartitionOp's argument should already be tracked" );
884
+
885
+ // Mark op.getOpArgs()[0] as not transferred.
886
+ p.undoTransfer (op.getOpArgs ()[0 ]);
887
+ break ;
888
+ }
833
889
case PartitionOpKind::Merge:
834
890
assert (op.getOpArgs ().size () == 2 &&
835
891
" Merge PartitionOp should be passed 2 arguments" );
0 commit comments