@@ -117,30 +117,37 @@ class PartitionOp {
117
117
using Element = PartitionPrimitives::Element;
118
118
119
119
private:
120
- PartitionOpKind OpKind ;
121
- llvm::SmallVector<Element, 2 > OpArgs ;
120
+ PartitionOpKind opKind ;
121
+ llvm::SmallVector<Element, 2 > opArgs ;
122
122
123
123
// / Record the SILInstruction that this PartitionOp was generated from, if
124
124
// / generated during compilation from a SILBasicBlock
125
- SILInstruction *sourceInst ;
125
+ PointerUnion< SILInstruction *, Operand *> source ;
126
126
127
127
// / Record an AST expression corresponding to this PartitionOp, currently
128
128
// / populated only for Transfer expressions to indicate the value being
129
129
// / transferred
130
130
Expr *sourceExpr;
131
131
132
132
// TODO: can the following declarations be merged?
133
- PartitionOp (PartitionOpKind OpKind , Element arg1,
133
+ PartitionOp (PartitionOpKind opKind , Element arg1,
134
134
SILInstruction *sourceInst = nullptr , Expr *sourceExpr = nullptr )
135
- : OpKind(OpKind ), OpArgs ({arg1}), sourceInst (sourceInst),
135
+ : opKind(opKind ), opArgs ({arg1}), source (sourceInst),
136
136
sourceExpr (sourceExpr) {
137
- assert ((OpKind != PartitionOpKind::Transfer || sourceInst) &&
137
+ assert ((opKind != PartitionOpKind::Transfer || sourceInst) &&
138
+ " Transfer needs a sourceInst" );
139
+ }
140
+
141
+ PartitionOp (PartitionOpKind opKind, Element arg1,
142
+ Operand *sourceOperand, Expr *sourceExpr = nullptr )
143
+ : opKind(opKind), opArgs({arg1}), source(sourceOperand), sourceExpr(sourceExpr) {
144
+ assert ((opKind != PartitionOpKind::Transfer || source) &&
138
145
" Transfer needs a sourceInst" );
139
146
}
140
147
141
148
PartitionOp (PartitionOpKind OpKind, Element arg1, Element arg2,
142
149
SILInstruction *sourceInst = nullptr , Expr *sourceExpr = nullptr )
143
- : OpKind (OpKind), OpArgs ({arg1, arg2}), sourceInst (sourceInst),
150
+ : opKind (OpKind), opArgs ({arg1, arg2}), source (sourceInst),
144
151
sourceExpr (sourceExpr) {
145
152
assert ((OpKind != PartitionOpKind::Transfer || sourceInst) &&
146
153
" Transfer needs a sourceInst" );
@@ -159,9 +166,9 @@ class PartitionOp {
159
166
return PartitionOp (PartitionOpKind::AssignFresh, tgt, sourceInst);
160
167
}
161
168
162
- static PartitionOp Transfer (Element tgt, SILInstruction *transferringInst ,
169
+ static PartitionOp Transfer (Element tgt, Operand *transferringOp ,
163
170
Expr *sourceExpr = nullptr ) {
164
- return PartitionOp (PartitionOpKind::Transfer, tgt, transferringInst ,
171
+ return PartitionOp (PartitionOpKind::Transfer, tgt, transferringOp ,
165
172
sourceExpr);
166
173
}
167
174
@@ -176,30 +183,30 @@ class PartitionOp {
176
183
}
177
184
178
185
bool operator ==(const PartitionOp &other) const {
179
- return OpKind == other.OpKind
180
- && OpArgs == other.OpArgs
181
- && sourceInst == other.sourceInst ;
186
+ return opKind == other.opKind && opArgs == other.opArgs &&
187
+ source == other.source ;
182
188
};
183
189
184
190
bool operator <(const PartitionOp &other) const {
185
- if (OpKind != other.OpKind )
186
- return OpKind < other.OpKind ;
187
- if (OpArgs != other.OpArgs )
188
- return OpArgs < other.OpArgs ;
189
- return sourceInst < other.sourceInst ;
191
+ if (opKind != other.opKind )
192
+ return opKind < other.opKind ;
193
+ if (opArgs != other.opArgs )
194
+ return opArgs < other.opArgs ;
195
+ return source < other.source ;
190
196
}
191
197
192
- PartitionOpKind getKind () const { return OpKind ; }
198
+ PartitionOpKind getKind () const { return opKind ; }
193
199
194
- ArrayRef<Element> getOpArgs () const { return OpArgs ; }
200
+ ArrayRef<Element> getOpArgs () const { return opArgs ; }
195
201
196
- SILInstruction *getSourceInst (bool assertNonNull = false ) const {
197
- assert (!assertNonNull ||
198
- sourceInst && " PartitionOps should be assigned SILInstruction"
199
- " sources when used for the core analysis" );
200
- return sourceInst;
202
+ SILInstruction *getSourceInst () const {
203
+ if (source.is <Operand *>())
204
+ return source.get <Operand *>()->getUser ();
205
+ return source.get <SILInstruction *>();
201
206
}
202
207
208
+ Operand *getSourceOp () const { return source.get <Operand *>(); }
209
+
203
210
SILLocation getSourceLoc () const { return getSourceInst (true )->getLoc (); }
204
211
205
212
Expr *getSourceExpr () const {
@@ -209,44 +216,44 @@ class PartitionOp {
209
216
SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
210
217
211
218
void print (llvm::raw_ostream &os, bool extraSpace = false ) const {
212
- switch (OpKind ) {
219
+ switch (opKind ) {
213
220
case PartitionOpKind::Assign: {
214
221
constexpr static char extraSpaceLiteral[10 ] = " " ;
215
222
os << " assign " ;
216
223
if (extraSpace)
217
224
os << extraSpaceLiteral;
218
- os << " %%" << OpArgs [0 ] << " = %%" << OpArgs [1 ];
225
+ os << " %%" << opArgs [0 ] << " = %%" << opArgs [1 ];
219
226
break ;
220
227
}
221
228
case PartitionOpKind::AssignFresh:
222
- os << " assign_fresh %%" << OpArgs [0 ];
229
+ os << " assign_fresh %%" << opArgs [0 ];
223
230
break ;
224
231
case PartitionOpKind::Transfer: {
225
232
constexpr static char extraSpaceLiteral[10 ] = " " ;
226
233
os << " transfer " ;
227
234
if (extraSpace)
228
235
os << extraSpaceLiteral;
229
- os << " %%" << OpArgs [0 ];
236
+ os << " %%" << opArgs [0 ];
230
237
break ;
231
238
}
232
239
case PartitionOpKind::Merge: {
233
240
constexpr static char extraSpaceLiteral[10 ] = " " ;
234
241
os << " merge " ;
235
242
if (extraSpace)
236
243
os << extraSpaceLiteral;
237
- os << " %%" << OpArgs [0 ] << " with %%" << OpArgs [1 ];
244
+ os << " %%" << opArgs [0 ] << " with %%" << opArgs [1 ];
238
245
break ;
239
246
}
240
247
case PartitionOpKind::Require: {
241
248
constexpr static char extraSpaceLiteral[10 ] = " " ;
242
249
os << " require " ;
243
250
if (extraSpace)
244
251
os << extraSpaceLiteral;
245
- os << " %%" << OpArgs [0 ];
252
+ os << " %%" << opArgs [0 ];
246
253
break ;
247
254
}
248
255
}
249
- os << " : " << *getSourceInst (true );
256
+ os << " : " << *getSourceInst ();
250
257
}
251
258
};
252
259
@@ -288,7 +295,7 @@ class Partition {
288
295
// / multi map here. The implication of this is that when we are performing
289
296
// / dataflow we use a union operation to combine CFG elements and just take
290
297
// / the first instruction that we see.
291
- llvm::SmallDenseMap<Region, SILInstruction *, 2 > regionToTransferredInstMap ;
298
+ llvm::SmallDenseMap<Region, Operand *, 2 > regionToTransferredOpMap ;
292
299
293
300
public:
294
301
Partition () : elementToRegionMap({}), canonical(true ) {}
@@ -342,12 +349,12 @@ class Partition {
342
349
343
350
// / Mark val as transferred. Returns true if we inserted \p
344
351
// / transferOperand. We return false otherwise.
345
- bool markTransferred (Element val, SILInstruction *transferOperand) {
352
+ bool markTransferred (Element val, Operand *transferOperand) {
346
353
// First see if our val is tracked. If it is not tracked, insert it and mark
347
354
// its new region as transferred.
348
355
if (!isTracked (val)) {
349
356
elementToRegionMap.insert_or_assign (val, fresh_label);
350
- regionToTransferredInstMap .insert ({fresh_label, transferOperand});
357
+ regionToTransferredOpMap .insert ({fresh_label, transferOperand});
351
358
fresh_label = Region (fresh_label + 1 );
352
359
canonical = false ;
353
360
return true ;
@@ -357,7 +364,7 @@ class Partition {
357
364
auto iter1 = elementToRegionMap.find (val);
358
365
assert (iter1 != elementToRegionMap.end ());
359
366
auto iter2 =
360
- regionToTransferredInstMap .try_emplace (iter1->second , transferOperand);
367
+ regionToTransferredOpMap .try_emplace (iter1->second , transferOperand);
361
368
return iter2.second ;
362
369
}
363
370
@@ -384,10 +391,10 @@ class Partition {
384
391
385
392
// Then if sndRegionNumber is transferred in sndReduced, make sure
386
393
// mergedRegion is transferred in fstReduced.
387
- auto iter = sndReduced.regionToTransferredInstMap .find (sndRegionNumber);
388
- if (iter != sndReduced.regionToTransferredInstMap .end ()) {
389
- fstReduced.regionToTransferredInstMap .try_emplace (mergedRegion,
390
- iter->second );
394
+ auto iter = sndReduced.regionToTransferredOpMap .find (sndRegionNumber);
395
+ if (iter != sndReduced.regionToTransferredOpMap .end ()) {
396
+ fstReduced.regionToTransferredOpMap .try_emplace (mergedRegion,
397
+ iter->second );
391
398
}
392
399
continue ;
393
400
}
@@ -420,9 +427,9 @@ class Partition {
420
427
// due to our traversal being in order. Thus just add this to fst_reduced.
421
428
assert (sndEltNumber == Element (sndRegionNumber));
422
429
fstReduced.elementToRegionMap .insert ({sndEltNumber, sndRegionNumber});
423
- auto iter = sndReduced.regionToTransferredInstMap .find (sndRegionNumber);
424
- if (iter != sndReduced.regionToTransferredInstMap .end ()) {
425
- fstReduced.regionToTransferredInstMap .insert (
430
+ auto iter = sndReduced.regionToTransferredOpMap .find (sndRegionNumber);
431
+ if (iter != sndReduced.regionToTransferredOpMap .end ()) {
432
+ fstReduced.regionToTransferredOpMap .insert (
426
433
{sndRegionNumber, iter->second });
427
434
}
428
435
if (fstReduced.fresh_label < sndRegionNumber)
@@ -489,7 +496,7 @@ class Partition {
489
496
490
497
os << " [" ;
491
498
for (auto [regionNo, elementNumbers] : multimap.getRange ()) {
492
- bool isTransferred = regionToTransferredInstMap .count (regionNo);
499
+ bool isTransferred = regionToTransferredOpMap .count (regionNo);
493
500
os << (isTransferred ? " {" : " (" );
494
501
int j = 0 ;
495
502
for (Element i : elementNumbers) {
@@ -504,17 +511,17 @@ class Partition {
504
511
auto iter = elementToRegionMap.find (val);
505
512
if (iter == elementToRegionMap.end ())
506
513
return false ;
507
- return regionToTransferredInstMap .count (iter->second );
514
+ return regionToTransferredOpMap .count (iter->second );
508
515
}
509
516
510
517
// / Return the instruction that transferred \p val's region or nullptr
511
518
// / otherwise.
512
- SILInstruction *getTransferred (Element val) const {
519
+ Operand *getTransferred (Element val) const {
513
520
auto iter = elementToRegionMap.find (val);
514
521
if (iter == elementToRegionMap.end ())
515
522
return nullptr ;
516
- auto iter2 = regionToTransferredInstMap .find (iter->second );
517
- if (iter2 == regionToTransferredInstMap .end ())
523
+ auto iter2 = regionToTransferredOpMap .find (iter->second );
524
+ if (iter2 == regionToTransferredOpMap .end ())
518
525
return nullptr ;
519
526
return iter2->second ;
520
527
}
@@ -535,7 +542,7 @@ class Partition {
535
542
llvm::SmallDenseSet<Region, 8 > seenRegion;
536
543
for (auto &[eltNo, regionNo] : elementToRegionMap) {
537
544
// See if all of our regionToTransferMap keys are regions in labels.
538
- if (regionToTransferredInstMap .count (regionNo))
545
+ if (regionToTransferredOpMap .count (regionNo))
539
546
seenRegion.insert (regionNo);
540
547
541
548
// Labels should not exceed fresh_label.
@@ -555,7 +562,7 @@ class Partition {
555
562
return fail (eltNo, 3 );
556
563
}
557
564
558
- if (seenRegion.size () != regionToTransferredInstMap .size ()) {
565
+ if (seenRegion.size () != regionToTransferredOpMap .size ()) {
559
566
llvm::report_fatal_error (
560
567
" FAIL! regionToTransferMap has a region that isn't being tracked?!" );
561
568
}
@@ -596,12 +603,15 @@ class Partition {
596
603
597
604
// Then relabel our regionToTransferredInst map if we need to by swapping
598
605
// out the old map and updating.
599
- llvm::SmallDenseMap<Region, SILInstruction *, 2 > oldMap =
600
- std::move (regionToTransferredInstMap);
601
- for (auto &[oldReg, inst] : oldMap) {
606
+ //
607
+ // TODO: If we just used an array for this, we could just rewrite and
608
+ // re-sort and not have to deal with potential allocations.
609
+ llvm::SmallDenseMap<Region, Operand *, 2 > oldMap =
610
+ std::move (regionToTransferredOpMap);
611
+ for (auto &[oldReg, op] : oldMap) {
602
612
auto iter = oldRegionToRelabeledMap.find (oldReg);
603
613
assert (iter != oldRegionToRelabeledMap.end ());
604
- regionToTransferredInstMap [iter->second ] = inst ;
614
+ regionToTransferredOpMap [iter->second ] = op ;
605
615
}
606
616
607
617
assert (is_canonical_correct ());
@@ -628,19 +638,19 @@ class Partition {
628
638
629
639
// Rename snd to use first region.
630
640
horizontalUpdate (elementToRegionMap, snd, fstRegion);
631
- auto iter = regionToTransferredInstMap .find (sndRegion);
632
- if (iter != regionToTransferredInstMap .end ()) {
633
- regionToTransferredInstMap .try_emplace (fstRegion, iter->second );
634
- regionToTransferredInstMap .erase (iter);
641
+ auto iter = regionToTransferredOpMap .find (sndRegion);
642
+ if (iter != regionToTransferredOpMap .end ()) {
643
+ regionToTransferredOpMap .try_emplace (fstRegion, iter->second );
644
+ regionToTransferredOpMap .erase (iter);
635
645
}
636
646
} else {
637
647
result = sndRegion;
638
648
639
649
horizontalUpdate (elementToRegionMap, fst, sndRegion);
640
- auto iter = regionToTransferredInstMap .find (fstRegion);
641
- if (iter != regionToTransferredInstMap .end ()) {
642
- regionToTransferredInstMap .try_emplace (sndRegion, iter->second );
643
- regionToTransferredInstMap .erase (iter);
650
+ auto iter = regionToTransferredOpMap .find (fstRegion);
651
+ if (iter != regionToTransferredOpMap .end ()) {
652
+ regionToTransferredOpMap .try_emplace (sndRegion, iter->second );
653
+ regionToTransferredOpMap .erase (iter);
644
654
}
645
655
}
646
656
@@ -702,9 +712,11 @@ struct PartitionOpEvaluator {
702
712
// /
703
713
// / 2. The element in the PartitionOp that was asked to be alive.
704
714
// /
705
- // / 3. The instruction that originally transferred the region.
706
- std::function<void (const PartitionOp &, Element, SILInstruction *)>
707
- failureCallback = nullptr ;
715
+ // / 3. The operand of the instruction that originally transferred the
716
+ // / region. Can be used to get the immediate value transferred or the
717
+ // / transferring instruction.
718
+ std::function<void (const PartitionOp &, Element, Operand *)> failureCallback =
719
+ nullptr ;
708
720
709
721
// / A list of elements that cannot be transferred. Whenever we transfer, we
710
722
// / check this list to see if we are transferring the element and then call
@@ -727,10 +739,10 @@ struct PartitionOpEvaluator {
727
739
728
740
// / A wrapper around the failure callback that checks if it is nullptr.
729
741
void handleFailure (const PartitionOp &op, Element elt,
730
- SILInstruction *transferringInst ) const {
742
+ Operand *transferringOp ) const {
731
743
if (!failureCallback)
732
744
return ;
733
- failureCallback (op, elt, transferringInst );
745
+ failureCallback (op, elt, transferringOp );
734
746
}
735
747
736
748
// / A wrapper around transferNonTransferrableCallback that only calls it if it
@@ -829,7 +841,7 @@ struct PartitionOpEvaluator {
829
841
return handleTransferNonTransferrable (op, op.getOpArgs ()[0 ]);
830
842
831
843
// Mark op.getOpArgs()[0] as transferred.
832
- p.markTransferred (op.getOpArgs ()[0 ], op.getSourceInst ( true ));
844
+ p.markTransferred (op.getOpArgs ()[0 ], op.getSourceOp ( ));
833
845
break ;
834
846
}
835
847
case PartitionOpKind::Merge:
0 commit comments