Skip to content

Commit 6d9e474

Browse files
author
jturcotti
committed
implement searching for a ConsumeReason instead of just diagnosing accesses to consumed values
1 parent 6e47a36 commit 6d9e474

File tree

4 files changed

+543
-129
lines changed

4 files changed

+543
-129
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -859,9 +859,13 @@ NOTE(sil_referencebinding_inout_binding_here, none,
859859
// Warnings arising from the flow-sensitive checking of Sendability of
860860
// non-Sendable values
861861
WARNING(consumed_value_used, none,
862-
"Non-Sendable value consumed, then used at this site; could yield race with another thread", ())
862+
"non-Sendable value consumed, then used at this site; could yield race with another thread", ())
863863
WARNING(arg_region_consumed, none,
864-
"This application could pass `self` or a Non-Sendable argument of this function to another thread, potentially yielding a race with the caller", ())
864+
"this application could pass `self` or a Non-Sendable argument of this function to another thread, potentially yielding a race with the caller", ())
865+
WARNING(consumption_yields_race, none,
866+
"non-Sendable value sent across isolation domains here, but could be accessed later in this function (%0 access site%select{|s}1 displayed%select{|, %3 more hidden}2)", (unsigned, bool, bool, unsigned))
867+
NOTE(possible_racy_access_site, none,
868+
"access here could race with non-Sendable value send above", ())
865869

866870
#define UNDEFINE_DIAGNOSTIC_MACROS
867871
#include "DefineDiagnosticMacros.h"

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,22 @@ class PartitionOp {
8181
return PartitionOp(PartitionOpKind::Require, tgt, sourceInst);
8282
}
8383

84-
SILInstruction *getSourceInst() const {
84+
bool operator==(const PartitionOp& other) const = default;
85+
// implemented for insertion into std::map
86+
bool operator<(const PartitionOp& other) const {
87+
if (OpKind != other.OpKind)
88+
return OpKind < other.OpKind;
89+
return sourceInst < other.sourceInst;
90+
}
91+
92+
PartitionOpKind getKind() const {
93+
return OpKind;
94+
}
95+
96+
SILInstruction *getSourceInst(bool assertNonNull = false) const {
97+
assert(!assertNonNull || sourceInst
98+
&& "PartitionOps should be assigned SILInstruction"
99+
" sources when used for the core analysis");
85100
return sourceInst;
86101
}
87102

@@ -196,7 +211,7 @@ class Partition {
196211
return;
197212
canonical = true;
198213

199-
std::map<signed, unsigned> relabel;
214+
std::map<unsigned, unsigned> relabel;
200215

201216
// relies on in-order traversal of labels
202217
for (auto &[i, label] : labels) {
@@ -268,6 +283,14 @@ class Partition {
268283
return fst.labels == snd.labels;
269284
}
270285

286+
bool isTracked(unsigned val) const {
287+
return labels.count(val);
288+
}
289+
290+
bool isConsumed(unsigned val) const {
291+
return isTracked(val) && labels.at(val) < 0;
292+
}
293+
271294
// quadratic time - Construct the partition corresponding to the join of the
272295
// two passed partitions; the join labels each index labelled by both operands
273296
// and two indices are in the same region of the join iff they are in the same
@@ -320,25 +343,17 @@ class Partition {
320343
nonconsumables = {},
321344

322345
llvm::function_ref<void(const PartitionOp&, unsigned)>
323-
handleConsumeNonConsumable = [](const PartitionOp&, unsigned) {},
324-
325-
bool reviveAfterFailure = false
346+
handleConsumeNonConsumable = [](const PartitionOp&, unsigned) {}
326347
) {
327-
auto handleFailureAndRevive =
328-
[&](const PartitionOp& partitionOp, unsigned consumedVal) {
329-
if (reviveAfterFailure)
330-
horizontalUpdate(labels, consumedVal, fresh_label++);
331-
handleFailure(partitionOp, consumedVal);
332-
};
333348
switch (op.OpKind) {
334349
case PartitionOpKind::Assign:
335350
assert(op.OpArgs.size() == 2 &&
336351
"Assign PartitionOp should be passed 2 arguments");
337352
assert(labels.count(op.OpArgs[1]) &&
338353
"Assign PartitionOp's source argument should be already tracked");
339354
// if assigning to a missing region, handle the failure
340-
if (labels[op.OpArgs[1]] < 0)
341-
handleFailureAndRevive(op, op.OpArgs[1]);
355+
if (isConsumed(op.OpArgs[1]))
356+
handleFailure(op, op.OpArgs[1]);
342357

343358
labels[op.OpArgs[0]] = labels[op.OpArgs[1]];
344359

@@ -361,8 +376,8 @@ class Partition {
361376
"Consume PartitionOp's argument should already be tracked");
362377

363378
// if attempting to consume a consumed region, handle the failure
364-
if (labels[op.OpArgs[0]] < 0)
365-
handleFailureAndRevive(op, op.OpArgs[0]);
379+
if (isConsumed(op.OpArgs[0]))
380+
handleFailure(op, op.OpArgs[0]);
366381

367382
// mark region as consumed
368383
horizontalUpdate(labels, op.OpArgs[0], -1);
@@ -387,10 +402,10 @@ class Partition {
387402
"Merge PartitionOp's arguments should already be tracked");
388403

389404
// if attempting to merge a consumed region, handle the failure
390-
if (labels[op.OpArgs[0]] < 0)
391-
handleFailureAndRevive(op, op.OpArgs[0]);
392-
if (labels[op.OpArgs[1]] < 0)
393-
handleFailureAndRevive(op, op.OpArgs[1]);
405+
if (isConsumed(op.OpArgs[0]))
406+
handleFailure(op, op.OpArgs[0]);
407+
if (isConsumed(op.OpArgs[1]))
408+
handleFailure(op, op.OpArgs[1]);
394409

395410
merge(op.OpArgs[0], op.OpArgs[1]);
396411
break;
@@ -399,13 +414,40 @@ class Partition {
399414
"Require PartitionOp should be passed 1 argument");
400415
assert(labels.count(op.OpArgs[0]) &&
401416
"Require PartitionOp's argument should already be tracked");
402-
if (labels[op.OpArgs[0]] < 0)
403-
handleFailureAndRevive(op, op.OpArgs[0]);
417+
if (isConsumed(op.OpArgs[0]))
418+
handleFailure(op, op.OpArgs[0]);
404419
}
405420

406421
assert(is_canonical_correct());
407422
}
408423

424+
// return a vector of the consumed values in this partition
425+
std::vector<unsigned> getConsumedVals() const {
426+
// for effeciency, this could return an iterator not a vector
427+
std::vector<unsigned> consumedVals;
428+
for (auto [i, _] : labels)
429+
if (isConsumed(i))
430+
consumedVals.push_back(i);
431+
return consumedVals;
432+
}
433+
434+
// return a vector of the non-consumed regions in this partition, each
435+
// represented as a vector of values
436+
std::vector<std::vector<unsigned>> getNonConsumedRegions() const {
437+
// for effeciency, this could return an iterator not a vector
438+
std::map<signed, std::vector<unsigned>> buckets;
439+
440+
for (auto [i, label] : labels)
441+
buckets[label].push_back(i);
442+
443+
std::vector<std::vector<unsigned>> doubleVec;
444+
445+
for (auto [_, bucket] : buckets)
446+
doubleVec.push_back(bucket);
447+
448+
return doubleVec;
449+
}
450+
409451
void dump_labels() const LLVM_ATTRIBUTE_USED {
410452
llvm::dbgs() << "Partition";
411453
if (canonical)
@@ -419,9 +461,8 @@ class Partition {
419461
void dump() LLVM_ATTRIBUTE_USED {
420462
std::map<signed, std::vector<unsigned>> buckets;
421463

422-
for (auto [i, label] : labels) {
464+
for (auto [i, label] : labels)
423465
buckets[label].push_back(i);
424-
}
425466

426467
llvm::dbgs() << "[";
427468
for (auto [label, indices] : buckets) {
@@ -432,9 +473,9 @@ class Partition {
432473
}
433474
llvm::dbgs() << (label < 0 ? "}" : ")");
434475
}
435-
llvm::dbgs() << "]";
476+
llvm::dbgs() << "]\n";
436477
}
437478
};
438479
}
439480

440-
#endif
481+
#endif // SWIFT_PARTITIONUTILS_H

0 commit comments

Comments
 (0)