Skip to content

Commit c9e750b

Browse files
committed
[region-isolation] Clean up/standardize comments.
1 parent a0e1507 commit c9e750b

File tree

3 files changed

+314
-313
lines changed

3 files changed

+314
-313
lines changed

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 142 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,22 @@ enum class PartitionOpKind : uint8_t {
9090
Require,
9191
};
9292

93-
// PartitionOp represents a primitive operation that can be performed on
94-
// Partitions. This is part of the TransferNonSendable SIL pass workflow:
95-
// first SILBasicBlocks are compiled to vectors of PartitionOps, then a fixed
96-
// point partition is found over the CFG.
93+
/// PartitionOp represents a primitive operation that can be performed on
94+
/// Partitions. This is part of the TransferNonSendable SIL pass workflow:
95+
/// first SILBasicBlocks are compiled to vectors of PartitionOps, then a fixed
96+
/// point partition is found over the CFG.
9797
class PartitionOp {
9898
private:
9999
PartitionOpKind OpKind;
100100
llvm::SmallVector<Element, 2> OpArgs;
101101

102-
// Record the SILInstruction that this PartitionOp was generated from, if
103-
// generated during compilation from a SILBasicBlock
102+
/// Record the SILInstruction that this PartitionOp was generated from, if
103+
/// generated during compilation from a SILBasicBlock
104104
SILInstruction *sourceInst;
105105

106-
// Record an AST expression corresponding to this PartitionOp, currently
107-
// populated only for Consume expressions to indicate the value being
108-
// transferred
106+
/// Record an AST expression corresponding to this PartitionOp, currently
107+
/// populated only for Consume expressions to indicate the value being
108+
/// transferred
109109
Expr *sourceExpr;
110110

111111
// TODO: can the following declarations be merged?
@@ -154,7 +154,7 @@ class PartitionOp {
154154
&& OpArgs == other.OpArgs
155155
&& sourceInst == other.sourceInst;
156156
};
157-
// implemented for insertion into std::map
157+
158158
bool operator<(const PartitionOp &other) const {
159159
if (OpKind != other.OpKind)
160160
return OpKind < other.OpKind;
@@ -202,12 +202,12 @@ class PartitionOp {
202202
}
203203
};
204204

205-
// For the passed `map`, ensure that `key` maps to `val`. If `key` already
206-
// mapped to a different value, ensure that all other keys mapped to that
207-
// value also now map to `val`. This is a relatively expensive (linear time)
208-
// operation that's unfortunately used pervasively throughout PartitionOp
209-
// application. If this is a performance bottleneck, let's consider optimizing
210-
// it to a true union-find or other tree-based data structure.
205+
/// For the passed `map`, ensure that `key` maps to `val`. If `key` already
206+
/// mapped to a different value, ensure that all other keys mapped to that
207+
/// value also now map to `val`. This is a relatively expensive (linear time)
208+
/// operation that's unfortunately used pervasively throughout PartitionOp
209+
/// application. If this is a performance bottleneck, let's consider optimizing
210+
/// it to a true union-find or other tree-based data structure.
211211
static void horizontalUpdate(std::map<Element, Region> &map, Element key,
212212
Region val) {
213213
if (!map.count(key)) {
@@ -224,121 +224,36 @@ static void horizontalUpdate(std::map<Element, Region> &map, Element key,
224224
map.insert_or_assign(otherKey, val);
225225
}
226226

227+
/// A map from Element -> Region that represents the current partition set.
228+
///
229+
///
227230
class Partition {
228231
public:
229232
/// A class defined in PartitionUtils unittest used to grab state from
230233
/// Partition without exposing it to other users.
231234
struct PartitionTester;
232235

233236
private:
234-
// Label each index with a non-negative (unsigned) label if it is associated
235-
// with a valid region, and with -1 if it is associated with a transferred
236-
// region in-order traversal relied upon.
237+
/// Label each index with a non-negative (unsigned) label if it is associated
238+
/// with a valid region, and with -1 if it is associated with a transferred
239+
/// region in-order traversal relied upon.
237240
std::map<Element, Region> labels;
238241

239-
// Track a label that is guaranteed to be strictly larger than all in use,
240-
// and therefore safe for use as a fresh label.
242+
/// Track a label that is guaranteed to be strictly larger than all in use,
243+
/// and therefore safe for use as a fresh label.
241244
Region fresh_label = Region(0);
242245

243-
// In a canonical partition, all regions are labelled with the smallest index
244-
// of any member. Certain operations like join and equals rely on canonicality
245-
// so when it's invalidated this boolean tracks that, and it must be
246-
// reestablished by a call to canonicalize().
246+
/// In a canonical partition, all regions are labelled with the smallest index
247+
/// of any member. Certain operations like join and equals rely on
248+
/// canonicality so when it's invalidated this boolean tracks that, and it
249+
/// must be reestablished by a call to canonicalize().
247250
bool canonical;
248251

249-
// Used only in assertions, check that Partitions promised to be canonical
250-
// are actually canonical
251-
bool is_canonical_correct() {
252-
if (!canonical)
253-
return true; // vacuously correct
254-
255-
auto fail = [&](Element i, int type) {
256-
llvm::dbgs() << "FAIL(i=" << i << "; type=" << type << "): ";
257-
print(llvm::dbgs());
258-
return false;
259-
};
260-
261-
for (auto &[i, label] : labels) {
262-
// correctness vacuous at transferred indices
263-
if (label.isTransferred())
264-
continue;
265-
266-
// this label should not exceed fresh_label
267-
if (label >= fresh_label)
268-
return fail(i, 0);
269-
270-
// the label of a region should be at most as large as each index in it
271-
if ((unsigned)label > i)
272-
return fail(i, 1);
273-
274-
// each region label should also be an element of the partition
275-
if (!labels.count(Element(label)))
276-
return fail(i, 2);
277-
278-
// each element that is also a region label should be mapped to itself
279-
if (labels.at(Element(label)) != label)
280-
return fail(i, 3);
281-
}
282-
283-
return true;
284-
}
285-
286-
// linear time - For each region label that occurs, find the first index
287-
// at which it occurs and relabel all instances of it to that index.
288-
// This excludes the -1 label for transferred regions.
289-
void canonicalize() {
290-
if (canonical)
291-
return;
292-
canonical = true;
293-
294-
std::map<Region, Region> relabel;
295-
296-
// relies on in-order traversal of labels
297-
for (auto &[i, label] : labels) {
298-
// leave -1 (transferred region) as is
299-
if (label.isTransferred())
300-
continue;
301-
302-
if (!relabel.count(label)) {
303-
// if this is the first time encountering this region label,
304-
// then this region label should be relabelled to this index,
305-
// so enter that into the map
306-
relabel.insert_or_assign(label, Region(i));
307-
}
308-
309-
// update this label with either its own index, or a prior index that
310-
// shared a region with it
311-
label = relabel.at(label);
312-
313-
// the maximum index iterated over will be used here to appropriately
314-
// set fresh_label
315-
fresh_label = Region(i + 1);
316-
}
317-
318-
assert(is_canonical_correct());
319-
}
320-
321-
// linear time - merge the regions of two indices, maintaining canonicality
322-
void merge(Element fst, Element snd) {
323-
assert(labels.count(fst) && labels.count(snd));
324-
if (labels.at(fst) == labels.at(snd))
325-
return;
326-
327-
// maintain canonicality by renaming the greater-numbered region
328-
if (labels.at(fst) < labels.at(snd))
329-
horizontalUpdate(labels, snd, labels.at(fst));
330-
else
331-
horizontalUpdate(labels, fst, labels.at(snd));
332-
333-
assert(is_canonical_correct());
334-
assert(labels.at(fst) == labels.at(snd));
335-
}
336-
337252
public:
338253
Partition() : labels({}), canonical(true) {}
339254

340-
// 1-arg constructor used when canonicality will be immediately invalidated,
341-
// so set to false to begin with
255+
/// 1-arg constructor used when canonicality will be immediately invalidated,
256+
/// so set to false to begin with
342257
Partition(bool canonical) : labels({}), canonical(canonical) {}
343258

344259
static Partition singleRegion(ArrayRef<Element> indices) {
@@ -371,8 +286,10 @@ class Partition {
371286
return p;
372287
}
373288

374-
// linear time - Test two partititons for equality by first putting them
375-
// in canonical form then comparing for exact equality.
289+
/// Test two partititons for equality by first putting them in canonical form
290+
/// then comparing for exact equality.
291+
///
292+
/// Runs in linear time.
376293
static bool equals(Partition &fst, Partition &snd) {
377294
fst.canonicalize();
378295
snd.canonicalize();
@@ -386,10 +303,10 @@ class Partition {
386303
return isTracked(val) && labels.at(val).isTransferred();
387304
}
388305

389-
// quadratic time - Construct the partition corresponding to the join of the
390-
// two passed partitions; the join labels each index labelled by both operands
391-
// and two indices are in the same region of the join iff they are in the same
392-
// region in either operand.
306+
/// Construct the partition corresponding to the union of the two passed
307+
/// partitions.
308+
///
309+
/// Runs in quadratic time.
393310
static Partition join(const Partition &fst, const Partition &snd) {
394311
// First copy and canonicalize our inputs.
395312
Partition fst_reduced = fst;
@@ -460,14 +377,14 @@ class Partition {
460377
return fst_reduced;
461378
}
462379

463-
// Apply the passed PartitionOp to this partition, performing its action. A
464-
// `handleFailure` closure can optionally be passed in that will be called if
465-
// a transferred region is required. The closure is given the PartitionOp that
466-
// failed, and the index of the SIL value that was required but
467-
// transferred. Additionally, a list of "nonconsumable" indices can be passed
468-
// in along with a handleConsumeNonConsumable closure. In the event that a
469-
// region containing one of the nonconsumable indices is transferred, the
470-
// closure will be called with the offending transfer.
380+
/// Apply the passed PartitionOp to this partition, performing its action. A
381+
/// `handleFailure` closure can optionally be passed in that will be called if
382+
/// a transferred region is required. The closure is given the PartitionOp
383+
/// that failed, and the index of the SIL value that was required but
384+
/// transferred. Additionally, a list of "nonconsumable" indices can be passed
385+
/// in along with a handleConsumeNonConsumable closure. In the event that a
386+
/// region containing one of the nonconsumable indices is transferred, the
387+
/// closure will be called with the offending transfer.
471388
void apply(
472389
PartitionOp op,
473390
llvm::function_ref<void(const PartitionOp &, Element)> handleFailure =
@@ -578,20 +495,20 @@ class Partition {
578495
assert(is_canonical_correct());
579496
}
580497

581-
// return a vector of the transferred values in this partition
498+
/// Return a vector of the transferred values in this partition.
582499
std::vector<Element> getTransferredVals() const {
583-
// for effeciency, this could return an iterator not a vector
500+
// For effeciency, this could return an iterator not a vector.
584501
std::vector<Element> transferredVals;
585502
for (auto [i, _] : labels)
586503
if (isTransferred(i))
587504
transferredVals.push_back(i);
588505
return transferredVals;
589506
}
590507

591-
// return a vector of the non-transferred regions in this partition, each
592-
// represented as a vector of values
508+
/// Return a vector of the non-transferred regions in this partition, each
509+
/// represented as a vector of values.
593510
std::vector<std::vector<Element>> getNonTransferredRegions() const {
594-
// for effeciency, this could return an iterator not a vector
511+
// For effeciency, this could return an iterator not a vector.
595512
std::map<Region, std::vector<Element>> buckets;
596513

597514
for (auto [i, label] : labels)
@@ -634,6 +551,97 @@ class Partition {
634551
}
635552
os << "]\n";
636553
}
554+
555+
private:
556+
/// Used only in assertions, check that Partitions promised to be canonical
557+
/// are actually canonical
558+
bool is_canonical_correct() {
559+
if (!canonical)
560+
return true; // vacuously correct
561+
562+
auto fail = [&](Element i, int type) {
563+
llvm::dbgs() << "FAIL(i=" << i << "; type=" << type << "): ";
564+
print(llvm::dbgs());
565+
return false;
566+
};
567+
568+
for (auto &[i, label] : labels) {
569+
// Correctness vacuous at transferred indices.
570+
if (label.isTransferred())
571+
continue;
572+
573+
// Labels should not exceed fresh_label.
574+
if (label >= fresh_label)
575+
return fail(i, 0);
576+
577+
// The label of a region should be at most as large as each index in it.
578+
if ((unsigned)label > i)
579+
return fail(i, 1);
580+
581+
// Each region label should also be an element of the partition.
582+
if (!labels.count(Element(label)))
583+
return fail(i, 2);
584+
585+
// Each element that is also a region label should be mapped to itself.
586+
if (labels.at(Element(label)) != label)
587+
return fail(i, 3);
588+
}
589+
590+
return true;
591+
}
592+
593+
/// For each region label that occurs, find the first index at which it occurs
594+
/// and relabel all instances of it to that index. This excludes the -1 label
595+
/// for transferred regions.
596+
///
597+
/// This runs in linear time.
598+
void canonicalize() {
599+
if (canonical)
600+
return;
601+
canonical = true;
602+
603+
std::map<Region, Region> relabel;
604+
605+
// relies on in-order traversal of labels
606+
for (auto &[i, label] : labels) {
607+
// leave -1 (transferred region) as is
608+
if (label.isTransferred())
609+
continue;
610+
611+
if (!relabel.count(label)) {
612+
// if this is the first time encountering this region label,
613+
// then this region label should be relabelled to this index,
614+
// so enter that into the map
615+
relabel.insert_or_assign(label, Region(i));
616+
}
617+
618+
// update this label with either its own index, or a prior index that
619+
// shared a region with it
620+
label = relabel.at(label);
621+
622+
// the maximum index iterated over will be used here to appropriately
623+
// set fresh_label
624+
fresh_label = Region(i + 1);
625+
}
626+
627+
assert(is_canonical_correct());
628+
}
629+
630+
// linear time - merge the regions of two indices, maintaining canonicality
631+
void merge(Element fst, Element snd) {
632+
assert(labels.count(fst) && labels.count(snd));
633+
if (labels.at(fst) == labels.at(snd))
634+
return;
635+
636+
// maintain canonicality by renaming the greater-numbered region
637+
if (labels.at(fst) < labels.at(snd))
638+
horizontalUpdate(labels, snd, labels.at(fst));
639+
else
640+
horizontalUpdate(labels, fst, labels.at(snd));
641+
642+
assert(is_canonical_correct());
643+
assert(labels.at(fst) == labels.at(snd));
644+
}
637645
};
638646

639647
} // namespace swift

0 commit comments

Comments
 (0)