Skip to content

Commit ff6ee74

Browse files
authored
Merge pull request #69423 from gottesmm/pr-4c7e13d3cbc1677f17c72b86d9a02042e97eded1
[region-isolation] Fix join to be a true union operation including the symmetric difference.
2 parents 46d99a2 + 27db2e6 commit ff6ee74

File tree

5 files changed

+339
-27
lines changed

5 files changed

+339
-27
lines changed

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ static void horizontalUpdate(std::map<Element, Region> &map, Element key,
225225
}
226226

227227
class Partition {
228+
public:
229+
/// A class defined in PartitionUtils unittest used to grab state from
230+
/// Partition without exposing it to other users.
231+
struct PartitionTester;
232+
228233
private:
229234
// Label each index with a non-negative (unsigned) label if it is associated
230235
// with a valid region, and with -1 if it is associated with a transferred
@@ -351,6 +356,21 @@ class Partition {
351356
return p;
352357
}
353358

359+
static Partition separateRegions(ArrayRef<Element> indices) {
360+
Partition p;
361+
if (indices.empty())
362+
return p;
363+
364+
Region max_index =
365+
Region(*std::max_element(indices.begin(), indices.end()));
366+
p.fresh_label = Region(max_index + 1);
367+
for (Element index : indices) {
368+
p.labels.insert_or_assign(index, Region(index));
369+
}
370+
assert(p.is_canonical_correct());
371+
return p;
372+
}
373+
354374
// linear time - Test two partititons for equality by first putting them
355375
// in canonical form then comparing for exact equality.
356376
static bool equals(Partition &fst, Partition &snd) {
@@ -370,30 +390,63 @@ class Partition {
370390
// two passed partitions; the join labels each index labelled by both operands
371391
// and two indices are in the same region of the join iff they are in the same
372392
// region in either operand.
373-
static Partition join(Partition &fst, Partition &snd) {
374-
// ensure copies are made
375-
Partition fst_reduced = false;
376-
Partition snd_reduced = false;
377-
378-
// make canonical copies of fst and snd, reduced to their intersected domain
379-
for (auto [i, _] : fst.labels)
380-
if (snd.labels.count(i)) {
381-
fst_reduced.labels.insert_or_assign(i, fst.labels.at(i));
382-
snd_reduced.labels.insert_or_assign(i, snd.labels.at(i));
383-
}
393+
static Partition join(const Partition &fst, const Partition &snd) {
394+
// First copy and canonicalize our inputs.
395+
Partition fst_reduced = fst;
396+
Partition snd_reduced = snd;
397+
384398
fst_reduced.canonicalize();
385399
snd_reduced.canonicalize();
386400

387-
// merging each index in fst with its label in snd ensures that all pairs
388-
// of indices that are in the same region in snd are also in the same region
389-
// in fst - the desired property
390-
for (const auto [i, snd_label] : snd_reduced.labels) {
391-
if (snd_label.isTransferred())
392-
// if snd says that the region has been transferred, mark it transferred
393-
// in fst
394-
horizontalUpdate(fst_reduced.labels, i, Region::transferred());
395-
else
396-
fst_reduced.merge(i, Element(snd_label));
401+
// For each element in snd_reduced...
402+
for (const auto &[sndEltNumber, sndRegionNumber] : snd_reduced.labels) {
403+
// For values that are both in fst_reduced and snd_reduced, we need to
404+
// merge their regions.
405+
if (fst_reduced.labels.count(sndEltNumber)) {
406+
if (sndRegionNumber.isTransferred()) {
407+
// If snd says that the region has been transferred, mark it
408+
// transferred in fst.
409+
horizontalUpdate(fst_reduced.labels, sndEltNumber,
410+
Region::transferred());
411+
continue;
412+
}
413+
414+
// Otherwise merge. This maintains canonicality.
415+
fst_reduced.merge(sndEltNumber, Element(sndRegionNumber));
416+
continue;
417+
}
418+
419+
// Otherwise, we have an element in snd that is not in fst. First see if
420+
// our region is transferred. In such a case, just add this element as
421+
// transferred.
422+
if (sndRegionNumber.isTransferred()) {
423+
fst_reduced.labels.insert({sndEltNumber, Region::transferred()});
424+
continue;
425+
}
426+
427+
// Then check if the representative element number for this element in snd
428+
// is in fst. In that case, we know that we visited it before we visited
429+
// this elt number (since we are processing in order) so what ever is
430+
// mapped to that number in snd must be the correct number for this
431+
// element as well since this number is guaranteed to be greater than our
432+
// representative and the number mapped to our representative in fst must
433+
// be <= our representative.
434+
auto iter = fst_reduced.labels.find(Element(sndRegionNumber));
435+
if (iter != fst_reduced.labels.end()) {
436+
fst_reduced.labels.insert({sndEltNumber, iter->second});
437+
if (fst_reduced.fresh_label < Region(sndEltNumber))
438+
fst_reduced.fresh_label = Region(sndEltNumber + 1);
439+
continue;
440+
}
441+
442+
// Otherwise, we have an element that is not in fst and its representative
443+
// is not in fst. This means that we must be our representative in snd
444+
// since we should have visited our representative earlier if we were not
445+
// due to our traversal being in order. Thus just add this to fst_reduced.
446+
assert(sndEltNumber == Element(sndRegionNumber));
447+
fst_reduced.labels.insert({sndEltNumber, sndRegionNumber});
448+
if (fst_reduced.fresh_label < sndRegionNumber)
449+
fst_reduced.fresh_label = Region(sndEltNumber + 1);
397450
}
398451

399452
LLVM_DEBUG(llvm::dbgs() << "JOIN PEFORMED: \nFST: ";
@@ -581,6 +634,9 @@ class Partition {
581634
}
582635
os << "]\n";
583636
}
637+
638+
/// Routine used in unittests
639+
Region getRegion(Element elt) const { return labels.at(elt); }
584640
};
585641

586642
} // namespace swift

test/Concurrency/sendnonsendable_basic.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,10 @@ extension Actor {
263263
}
264264
}
265265

266-
// We emit the first error that we see. So we do not emit the self error.
267266
await transferToMain(closure) // expected-sns-note {{access here could race}}
268-
// expected-complete-warning @-1 {{passing argument of non-sendable type '() -> ()' into main actor-isolated context may introduce data races}}
269-
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
267+
// expected-sns-warning @-1 {{call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller}}
268+
// expected-complete-warning @-2 {{passing argument of non-sendable type '() -> ()' into main actor-isolated context may introduce data races}}
269+
// expected-complete-note @-3 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
270270
}
271271

272272
// In this case, we reinit along both paths, but only one has an actor derived
@@ -286,9 +286,7 @@ extension Actor {
286286
closure = {}
287287
}
288288

289-
// TODO: We do not error here yet since we are performing the control flow
290-
// union incorrectly.
291-
await transferToMain(closure)
289+
await transferToMain(closure) // expected-sns-warning {{call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller}}
292290
// expected-complete-warning @-1 {{passing argument of non-sendable type '() -> ()' into main actor-isolated context may introduce data races}}
293291
// expected-complete-note @-2 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
294292
}

unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ if(SWIFT_INCLUDE_TOOLS)
1616
add_subdirectory(Remangler)
1717
add_subdirectory(Sema)
1818
add_subdirectory(SIL)
19+
add_subdirectory(SILOptimizer)
1920
add_subdirectory(SwiftDemangle)
2021

2122
add_subdirectory(Threading)

unittests/SILOptimizer/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,7 @@ add_swift_unittest(SwiftSILOptimizerTests
55
target_link_libraries(SwiftSILOptimizerTests
66
PRIVATE
77
swiftSILOptimizer
8+
swiftIRGen
9+
swiftAST
10+
swiftFrontend
811
)

0 commit comments

Comments
 (0)