@@ -117,30 +117,37 @@ class PartitionOp {
117117 using Element = PartitionPrimitives::Element;
118118
119119private:
120- PartitionOpKind OpKind ;
121- llvm::SmallVector<Element, 2 > OpArgs ;
120+ PartitionOpKind opKind ;
121+ llvm::SmallVector<Element, 2 > opArgs ;
122122
123123 // / Record the SILInstruction that this PartitionOp was generated from, if
124124 // / generated during compilation from a SILBasicBlock
125- SILInstruction *sourceInst ;
125+ PointerUnion< SILInstruction *, Operand *> source ;
126126
127127 // / Record an AST expression corresponding to this PartitionOp, currently
128128 // / populated only for Transfer expressions to indicate the value being
129129 // / transferred
130130 Expr *sourceExpr;
131131
132132 // TODO: can the following declarations be merged?
133- PartitionOp (PartitionOpKind OpKind , Element arg1,
133+ PartitionOp (PartitionOpKind opKind , Element arg1,
134134 SILInstruction *sourceInst = nullptr , Expr *sourceExpr = nullptr )
135- : OpKind(OpKind ), OpArgs ({arg1}), sourceInst (sourceInst),
135+ : opKind(opKind ), opArgs ({arg1}), source (sourceInst),
136136 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) &&
138145 " Transfer needs a sourceInst" );
139146 }
140147
141148 PartitionOp (PartitionOpKind OpKind, Element arg1, Element arg2,
142149 SILInstruction *sourceInst = nullptr , Expr *sourceExpr = nullptr )
143- : OpKind (OpKind), OpArgs ({arg1, arg2}), sourceInst (sourceInst),
150+ : opKind (OpKind), opArgs ({arg1, arg2}), source (sourceInst),
144151 sourceExpr (sourceExpr) {
145152 assert ((OpKind != PartitionOpKind::Transfer || sourceInst) &&
146153 " Transfer needs a sourceInst" );
@@ -159,9 +166,9 @@ class PartitionOp {
159166 return PartitionOp (PartitionOpKind::AssignFresh, tgt, sourceInst);
160167 }
161168
162- static PartitionOp Transfer (Element tgt, SILInstruction *transferringInst ,
169+ static PartitionOp Transfer (Element tgt, Operand *transferringOp ,
163170 Expr *sourceExpr = nullptr ) {
164- return PartitionOp (PartitionOpKind::Transfer, tgt, transferringInst ,
171+ return PartitionOp (PartitionOpKind::Transfer, tgt, transferringOp ,
165172 sourceExpr);
166173 }
167174
@@ -176,30 +183,30 @@ class PartitionOp {
176183 }
177184
178185 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 ;
182188 };
183189
184190 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 ;
190196 }
191197
192- PartitionOpKind getKind () const { return OpKind ; }
198+ PartitionOpKind getKind () const { return opKind ; }
193199
194- ArrayRef<Element> getOpArgs () const { return OpArgs ; }
200+ ArrayRef<Element> getOpArgs () const { return opArgs ; }
195201
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 *>();
201206 }
202207
208+ Operand *getSourceOp () const { return source.get <Operand *>(); }
209+
203210 SILLocation getSourceLoc () const { return getSourceInst (true )->getLoc (); }
204211
205212 Expr *getSourceExpr () const {
@@ -209,44 +216,44 @@ class PartitionOp {
209216 SWIFT_DEBUG_DUMP { print (llvm::dbgs ()); }
210217
211218 void print (llvm::raw_ostream &os, bool extraSpace = false ) const {
212- switch (OpKind ) {
219+ switch (opKind ) {
213220 case PartitionOpKind::Assign: {
214221 constexpr static char extraSpaceLiteral[10 ] = " " ;
215222 os << " assign " ;
216223 if (extraSpace)
217224 os << extraSpaceLiteral;
218- os << " %%" << OpArgs [0 ] << " = %%" << OpArgs [1 ];
225+ os << " %%" << opArgs [0 ] << " = %%" << opArgs [1 ];
219226 break ;
220227 }
221228 case PartitionOpKind::AssignFresh:
222- os << " assign_fresh %%" << OpArgs [0 ];
229+ os << " assign_fresh %%" << opArgs [0 ];
223230 break ;
224231 case PartitionOpKind::Transfer: {
225232 constexpr static char extraSpaceLiteral[10 ] = " " ;
226233 os << " transfer " ;
227234 if (extraSpace)
228235 os << extraSpaceLiteral;
229- os << " %%" << OpArgs [0 ];
236+ os << " %%" << opArgs [0 ];
230237 break ;
231238 }
232239 case PartitionOpKind::Merge: {
233240 constexpr static char extraSpaceLiteral[10 ] = " " ;
234241 os << " merge " ;
235242 if (extraSpace)
236243 os << extraSpaceLiteral;
237- os << " %%" << OpArgs [0 ] << " with %%" << OpArgs [1 ];
244+ os << " %%" << opArgs [0 ] << " with %%" << opArgs [1 ];
238245 break ;
239246 }
240247 case PartitionOpKind::Require: {
241248 constexpr static char extraSpaceLiteral[10 ] = " " ;
242249 os << " require " ;
243250 if (extraSpace)
244251 os << extraSpaceLiteral;
245- os << " %%" << OpArgs [0 ];
252+ os << " %%" << opArgs [0 ];
246253 break ;
247254 }
248255 }
249- os << " : " << *getSourceInst (true );
256+ os << " : " << *getSourceInst ();
250257 }
251258};
252259
@@ -288,7 +295,7 @@ class Partition {
288295 // / multi map here. The implication of this is that when we are performing
289296 // / dataflow we use a union operation to combine CFG elements and just take
290297 // / the first instruction that we see.
291- llvm::SmallDenseMap<Region, SILInstruction *, 2 > regionToTransferredInstMap ;
298+ llvm::SmallDenseMap<Region, Operand *, 2 > regionToTransferredOpMap ;
292299
293300public:
294301 Partition () : elementToRegionMap({}), canonical(true ) {}
@@ -342,12 +349,12 @@ class Partition {
342349
343350 // / Mark val as transferred. Returns true if we inserted \p
344351 // / transferOperand. We return false otherwise.
345- bool markTransferred (Element val, SILInstruction *transferOperand) {
352+ bool markTransferred (Element val, Operand *transferOperand) {
346353 // First see if our val is tracked. If it is not tracked, insert it and mark
347354 // its new region as transferred.
348355 if (!isTracked (val)) {
349356 elementToRegionMap.insert_or_assign (val, fresh_label);
350- regionToTransferredInstMap .insert ({fresh_label, transferOperand});
357+ regionToTransferredOpMap .insert ({fresh_label, transferOperand});
351358 fresh_label = Region (fresh_label + 1 );
352359 canonical = false ;
353360 return true ;
@@ -357,7 +364,7 @@ class Partition {
357364 auto iter1 = elementToRegionMap.find (val);
358365 assert (iter1 != elementToRegionMap.end ());
359366 auto iter2 =
360- regionToTransferredInstMap .try_emplace (iter1->second , transferOperand);
367+ regionToTransferredOpMap .try_emplace (iter1->second , transferOperand);
361368 return iter2.second ;
362369 }
363370
@@ -384,10 +391,10 @@ class Partition {
384391
385392 // Then if sndRegionNumber is transferred in sndReduced, make sure
386393 // 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 );
391398 }
392399 continue ;
393400 }
@@ -420,9 +427,9 @@ class Partition {
420427 // due to our traversal being in order. Thus just add this to fst_reduced.
421428 assert (sndEltNumber == Element (sndRegionNumber));
422429 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 (
426433 {sndRegionNumber, iter->second });
427434 }
428435 if (fstReduced.fresh_label < sndRegionNumber)
@@ -489,7 +496,7 @@ class Partition {
489496
490497 os << " [" ;
491498 for (auto [regionNo, elementNumbers] : multimap.getRange ()) {
492- bool isTransferred = regionToTransferredInstMap .count (regionNo);
499+ bool isTransferred = regionToTransferredOpMap .count (regionNo);
493500 os << (isTransferred ? " {" : " (" );
494501 int j = 0 ;
495502 for (Element i : elementNumbers) {
@@ -504,17 +511,17 @@ class Partition {
504511 auto iter = elementToRegionMap.find (val);
505512 if (iter == elementToRegionMap.end ())
506513 return false ;
507- return regionToTransferredInstMap .count (iter->second );
514+ return regionToTransferredOpMap .count (iter->second );
508515 }
509516
510517 // / Return the instruction that transferred \p val's region or nullptr
511518 // / otherwise.
512- SILInstruction *getTransferred (Element val) const {
519+ Operand *getTransferred (Element val) const {
513520 auto iter = elementToRegionMap.find (val);
514521 if (iter == elementToRegionMap.end ())
515522 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 ())
518525 return nullptr ;
519526 return iter2->second ;
520527 }
@@ -535,7 +542,7 @@ class Partition {
535542 llvm::SmallDenseSet<Region, 8 > seenRegion;
536543 for (auto &[eltNo, regionNo] : elementToRegionMap) {
537544 // See if all of our regionToTransferMap keys are regions in labels.
538- if (regionToTransferredInstMap .count (regionNo))
545+ if (regionToTransferredOpMap .count (regionNo))
539546 seenRegion.insert (regionNo);
540547
541548 // Labels should not exceed fresh_label.
@@ -555,7 +562,7 @@ class Partition {
555562 return fail (eltNo, 3 );
556563 }
557564
558- if (seenRegion.size () != regionToTransferredInstMap .size ()) {
565+ if (seenRegion.size () != regionToTransferredOpMap .size ()) {
559566 llvm::report_fatal_error (
560567 " FAIL! regionToTransferMap has a region that isn't being tracked?!" );
561568 }
@@ -596,12 +603,15 @@ class Partition {
596603
597604 // Then relabel our regionToTransferredInst map if we need to by swapping
598605 // 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) {
602612 auto iter = oldRegionToRelabeledMap.find (oldReg);
603613 assert (iter != oldRegionToRelabeledMap.end ());
604- regionToTransferredInstMap [iter->second ] = inst ;
614+ regionToTransferredOpMap [iter->second ] = op ;
605615 }
606616
607617 assert (is_canonical_correct ());
@@ -628,19 +638,19 @@ class Partition {
628638
629639 // Rename snd to use first region.
630640 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);
635645 }
636646 } else {
637647 result = sndRegion;
638648
639649 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);
644654 }
645655 }
646656
@@ -702,9 +712,11 @@ struct PartitionOpEvaluator {
702712 // /
703713 // / 2. The element in the PartitionOp that was asked to be alive.
704714 // /
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 ;
708720
709721 // / A list of elements that cannot be transferred. Whenever we transfer, we
710722 // / check this list to see if we are transferring the element and then call
@@ -727,10 +739,10 @@ struct PartitionOpEvaluator {
727739
728740 // / A wrapper around the failure callback that checks if it is nullptr.
729741 void handleFailure (const PartitionOp &op, Element elt,
730- SILInstruction *transferringInst ) const {
742+ Operand *transferringOp ) const {
731743 if (!failureCallback)
732744 return ;
733- failureCallback (op, elt, transferringInst );
745+ failureCallback (op, elt, transferringOp );
734746 }
735747
736748 // / A wrapper around transferNonTransferrableCallback that only calls it if it
@@ -829,7 +841,7 @@ struct PartitionOpEvaluator {
829841 return handleTransferNonTransferrable (op, op.getOpArgs ()[0 ]);
830842
831843 // Mark op.getOpArgs()[0] as transferred.
832- p.markTransferred (op.getOpArgs ()[0 ], op.getSourceInst ( true ));
844+ p.markTransferred (op.getOpArgs ()[0 ], op.getSourceOp ( ));
833845 break ;
834846 }
835847 case PartitionOpKind::Merge:
0 commit comments