Skip to content

Commit 90f192a

Browse files
authored
Merge pull request swiftlang#71380 from gottesmm/pr-5c52de648d247153d66d33aad7d089d6324242ed
[region-isolation] When changing an elements region, if that element was the last element in a transferred regionl, remove that region from the transferredOpMap.
2 parents b049e69 + 434261b commit 90f192a

File tree

2 files changed

+108
-12
lines changed

2 files changed

+108
-12
lines changed

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -499,16 +499,73 @@ class Partition {
499499
}
500500

501501
void trackNewElement(Element newElt) {
502-
// Map index newElt to a fresh label.
503-
elementToRegionMap.insert_or_assign(newElt, fresh_label);
502+
SWIFT_DEFER { validateRegionToTransferredOpMapRegions(); };
503+
504+
// First try to emplace newElt with fresh_label.
505+
auto iter = elementToRegionMap.try_emplace(newElt, fresh_label);
506+
507+
// If we did insert, then we know that the value is completely new. We can
508+
// just update the fresh_label, set canonical to false, and return.
509+
if (iter.second) {
510+
// Increment the fresh label so it remains fresh.
511+
fresh_label = Region(fresh_label + 1);
512+
canonical = false;
513+
return;
514+
}
515+
516+
// Otherwise, we have a bit more work that we need to perform:
517+
//
518+
// 1. We of course need to update iter to point at fresh_label.
519+
//
520+
// 2. We need to see if this value was the last element in its current
521+
// region. If so, then we need to remove the region from the transferred op
522+
// map.
523+
//
524+
// This is important to ensure that every region in the transferredOpMap is
525+
// also in elementToRegionMap.
526+
auto oldRegion = iter.first->second;
527+
iter.first->second = fresh_label;
528+
529+
if (llvm::none_of(elementToRegionMap,
530+
[&](std::pair<Element, Region> value) {
531+
return value.second == oldRegion;
532+
})) {
533+
regionToTransferredOpMap.erase(oldRegion);
534+
}
504535

505536
// Increment the fresh label so it remains fresh.
506537
fresh_label = Region(fresh_label + 1);
507538
canonical = false;
508539
}
509540

541+
/// Assigns \p oldElt to the region associated with \p newElt.
510542
void assignElement(Element oldElt, Element newElt) {
511-
elementToRegionMap.insert_or_assign(oldElt, elementToRegionMap.at(newElt));
543+
SWIFT_DEFER { validateRegionToTransferredOpMapRegions(); };
544+
545+
// First try to emplace oldElt with the newRegion.
546+
auto newRegion = elementToRegionMap.at(newElt);
547+
auto iter = elementToRegionMap.try_emplace(oldElt, newRegion);
548+
549+
// If we did an insert, then we know that the value is new and we can just
550+
// set canonical to false and return.
551+
if (iter.second) {
552+
canonical = false;
553+
return;
554+
}
555+
556+
// Otherwise, we did an assign. In such a case, we need to see if oldElt was
557+
// the last element in oldRegion. If so, we need to erase the oldRegion from
558+
// regionToTransferredOpMap.
559+
auto oldRegion = iter.first->second;
560+
iter.first->second = newRegion;
561+
562+
if (llvm::none_of(elementToRegionMap,
563+
[&](std::pair<Element, Region> value) {
564+
return value.second == oldRegion;
565+
})) {
566+
regionToTransferredOpMap.erase(oldRegion);
567+
}
568+
512569
canonical = false;
513570
}
514571

@@ -766,6 +823,22 @@ class Partition {
766823
return set;
767824
}
768825

826+
/// Validate that all regions in the regionToTransferredOpMap exist in the
827+
/// elementToRegionMap.
828+
///
829+
/// Asserts when NDEBUG is set. Does nothing otherwise.
830+
void validateRegionToTransferredOpMapRegions() const {
831+
#ifndef NDEBUG
832+
llvm::SmallSet<Region, 8> regions;
833+
for (auto [eltNo, regionNo] : elementToRegionMap) {
834+
regions.insert(regionNo);
835+
}
836+
for (auto [regionNo, opSet] : regionToTransferredOpMap) {
837+
assert(regions.contains(regionNo) && "Region doesn't exist?!");
838+
}
839+
#endif
840+
}
841+
769842
/// Used only in assertions, check that Partitions promised to be canonical
770843
/// are actually canonical
771844
bool is_canonical_correct() {
@@ -781,12 +854,7 @@ class Partition {
781854
return false;
782855
};
783856

784-
llvm::SmallDenseSet<Region, 8> seenRegion;
785857
for (auto &[eltNo, regionNo] : elementToRegionMap) {
786-
// See if all of our regionToTransferMap keys are regions in labels.
787-
if (regionToTransferredOpMap.count(regionNo))
788-
seenRegion.insert(regionNo);
789-
790858
// Labels should not exceed fresh_label.
791859
if (regionNo >= fresh_label)
792860
return fail(eltNo, 0);
@@ -804,10 +872,8 @@ class Partition {
804872
return fail(eltNo, 3);
805873
}
806874

807-
if (seenRegion.size() != regionToTransferredOpMap.size()) {
808-
llvm::report_fatal_error(
809-
"FAIL! regionToTransferMap has a region that isn't being tracked?!");
810-
}
875+
// Before we do anything, validate region to transferred op map.
876+
validateRegionToTransferredOpMapRegions();
811877

812878
return true;
813879
#endif
@@ -868,6 +934,7 @@ class Partition {
868934
return;
869935
canonical = true;
870936

937+
validateRegionToTransferredOpMapRegions();
871938
std::map<Region, Region> oldRegionToRelabeledMap;
872939

873940
// We rely on in-order traversal of labels to ensure that we always take the

unittests/SILOptimizer/PartitionUtilsTest.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,3 +698,32 @@ TEST(PartitionUtilsTest, TestUndoTransfer) {
698698
PartitionOp::UndoTransfer(Element(0), instSingletons[0]),
699699
PartitionOp::Require(Element(0), instSingletons[0])});
700700
}
701+
702+
TEST(PartitionUtilsTest, TestLastEltInTransferredRegion) {
703+
llvm::BumpPtrAllocator allocator;
704+
Partition::TransferringOperandSetFactory factory(allocator);
705+
706+
// First make sure that we do this correctly with an assign fresh.
707+
Partition p;
708+
{
709+
PartitionOpEvaluatorBasic eval(p, factory);
710+
eval.apply({PartitionOp::AssignFresh(Element(0)),
711+
PartitionOp::AssignFresh(Element(1)),
712+
PartitionOp::AssignFresh(Element(2)),
713+
PartitionOp::Transfer(Element(0), transferSingletons[0]),
714+
PartitionOp::AssignFresh(Element(0))});
715+
}
716+
p.validateRegionToTransferredOpMapRegions();
717+
718+
// Now make sure that we do this correctly with assign.
719+
Partition p2;
720+
{
721+
PartitionOpEvaluatorBasic eval(p2, factory);
722+
eval.apply({PartitionOp::AssignFresh(Element(0)),
723+
PartitionOp::AssignFresh(Element(1)),
724+
PartitionOp::AssignFresh(Element(2)),
725+
PartitionOp::Transfer(Element(0), transferSingletons[0]),
726+
PartitionOp::Assign(Element(0), Element(2))});
727+
}
728+
p2.validateRegionToTransferredOpMapRegions();
729+
}

0 commit comments

Comments
 (0)