Skip to content

Commit ccefdeb

Browse files
authored
Merge pull request #70031 from gottesmm/region-isolation-async-let
[region-isolation] Add support for async let
2 parents 63abbb6 + d1870c1 commit ccefdeb

File tree

14 files changed

+1647
-191
lines changed

14 files changed

+1647
-191
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -877,16 +877,19 @@ NOTE(sil_referencebinding_inout_binding_here, none,
877877

878878
// Warnings arising from the flow-sensitive checking of Sendability of
879879
// non-Sendable values
880-
WARNING(arg_region_transferred, none,
880+
WARNING(regionbasedisolation_selforargtransferred, none,
881881
"call site passes `self` or a non-sendable argument of this function to another thread, potentially yielding a race with the caller", ())
882-
WARNING(transfer_yields_race, none,
883-
"non-sendable value sent across isolation domains that could be concurrently accessed later in this function (%0 access site%select{|s}1 displayed%select{|, %3 more hidden}2)",
884-
(unsigned, bool, bool, unsigned))
885-
WARNING(call_site_transfer_yields_race, none,
882+
WARNING(regionbasedisolation_transfer_yields_race_no_isolation, none,
883+
"transferred value of non-Sendable type %0 that could race with later accesses",
884+
(Type))
885+
WARNING(regionbasedisolation_transfer_yields_race_with_isolation, none,
886886
"passing argument of non-sendable type %0 from %1 context to %2 context at this call site could yield a race with accesses later in this function",
887887
(Type, ActorIsolation, ActorIsolation))
888-
NOTE(possible_racy_access_site, none,
888+
NOTE(regionbasedisolation_maybe_race, none,
889889
"access here could race", ())
890+
ERROR(regionbasedisolation_unknown_pattern, none,
891+
"pattern that the region based isolation checker does not understand how to check. Please file a bug",
892+
())
890893

891894
// TODO: print the name of the nominal type
892895
ERROR(deinit_not_visible, none,

include/swift/SIL/OperandBits.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//===--- OperandBits.h ----------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_SIL_OPERANDBITS_H
14+
#define SWIFT_SIL_OPERANDBITS_H
15+
16+
#include "swift/SIL/SILBitfield.h"
17+
#include "swift/SIL/SILValue.h"
18+
19+
namespace swift {
20+
21+
class OperandBitfield : public SILBitfield<OperandBitfield, Operand> {
22+
template <class, class>
23+
friend class SILBitfield;
24+
25+
OperandBitfield *insertInto(SILFunction *function) {
26+
assert(function && "OperandBitField constructed with a null function");
27+
OperandBitfield *oldParent = function->newestAliveOperandBitfield;
28+
function->newestAliveOperandBitfield = this;
29+
return oldParent;
30+
}
31+
32+
public:
33+
OperandBitfield(SILFunction *function, int size)
34+
: SILBitfield(function, size, insertInto(function)) {}
35+
36+
~OperandBitfield() {
37+
assert(function->newestAliveOperandBitfield == this &&
38+
"BasicBlockBitfield destructed too early");
39+
function->newestAliveOperandBitfield = parent;
40+
}
41+
};
42+
43+
/// A set of Operands.
44+
///
45+
/// For details see OperandBitfield.
46+
class OperandSet {
47+
OperandBitfield bit;
48+
49+
public:
50+
OperandSet(SILFunction *function) : bit(function, 1) {}
51+
52+
SILFunction *getFunction() const { return bit.getFunction(); }
53+
54+
bool contains(Operand *node) const { return (bool)bit.get(node); }
55+
56+
/// Returns true if \p node was not contained in the set before inserting.
57+
bool insert(Operand *node) {
58+
bool wasContained = contains(node);
59+
if (!wasContained) {
60+
bit.set(node, 1);
61+
}
62+
return !wasContained;
63+
}
64+
65+
void erase(Operand *node) { bit.set(node, 0); }
66+
};
67+
68+
using OperandSetWithSize = KnownSizeSet<OperandSet>;
69+
70+
} // namespace swift
71+
72+
#endif
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
//===--- OperanDatastructures.h -------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file defines efficient data structures for working with Operands.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_SIL_OPERANDDATASTRUCTURES_H
18+
#define SWIFT_SIL_OPERANDDATASTRUCTURES_H
19+
20+
#include "swift/SIL/OperandBits.h"
21+
#include "swift/SIL/StackList.h"
22+
23+
namespace swift {
24+
25+
/// An implementation of `llvm::SetVector<Operand *,
26+
/// StackList<Operand *>,
27+
/// OperandSet>`.
28+
///
29+
/// Unfortunately it's not possible to use `llvm::SetVector` directly because
30+
/// the OperandSet and StackList constructors needs a `SILFunction`
31+
/// argument.
32+
///
33+
/// Note: This class does not provide a `remove` method intentionally, because
34+
/// it would have a O(n) complexity.
35+
class OperandSetVector {
36+
StackList<Operand *> vector;
37+
OperandSet set;
38+
39+
public:
40+
using iterator = typename StackList<Operand *>::iterator;
41+
42+
OperandSetVector(SILFunction *function) : vector(function), set(function) {}
43+
44+
iterator begin() const { return vector.begin(); }
45+
iterator end() const { return vector.end(); }
46+
47+
llvm::iterator_range<iterator> getRange() const {
48+
return llvm::make_range(begin(), end());
49+
}
50+
51+
bool empty() const { return vector.empty(); }
52+
53+
bool contains(Operand *instruction) const {
54+
return set.contains(instruction);
55+
}
56+
57+
/// Returns true if \p instruction was not contained in the set before
58+
/// inserting.
59+
bool insert(Operand *instruction) {
60+
if (set.insert(instruction)) {
61+
vector.push_back(instruction);
62+
return true;
63+
}
64+
return false;
65+
}
66+
};
67+
68+
/// A utility for processing instructions in a worklist.
69+
///
70+
/// It is basically a combination of an instruction vector and an instruction
71+
/// set. It can be used for typical worklist-processing algorithms.
72+
class OperandWorklist {
73+
StackList<Operand *> worklist;
74+
OperandSet visited;
75+
76+
public:
77+
/// Construct an empty worklist.
78+
OperandWorklist(SILFunction *function)
79+
: worklist(function), visited(function) {}
80+
81+
/// Initialize the worklist with \p initialOperand.
82+
OperandWorklist(Operand *initialOperand)
83+
: OperandWorklist(initialOperand->getUser()->getFunction()) {
84+
push(initialOperand);
85+
}
86+
87+
/// Pops the last added element from the worklist or returns null, if the
88+
/// worklist is empty.
89+
Operand *pop() {
90+
if (worklist.empty())
91+
return nullptr;
92+
return worklist.pop_back_val();
93+
}
94+
95+
/// Pushes \p operand onto the worklist if \p operand has never been
96+
/// push before.
97+
bool pushIfNotVisited(Operand *operand) {
98+
if (visited.insert(operand)) {
99+
worklist.push_back(operand);
100+
return true;
101+
}
102+
return false;
103+
}
104+
105+
/// Pushes the operands of all uses of \p instruction onto the worklist if the
106+
/// operands have never been pushed before. Returns \p true if we inserted
107+
/// /any/ values.
108+
///
109+
/// This is a bulk convenience API.
110+
bool pushResultOperandsIfNotVisited(SILInstruction *inst) {
111+
bool insertedOperand = false;
112+
for (auto result : inst->getResults()) {
113+
for (auto *use : result->getUses()) {
114+
insertedOperand |= pushIfNotVisited(use);
115+
}
116+
}
117+
return insertedOperand;
118+
}
119+
120+
/// Like `pushIfNotVisited`, but requires that \p operand has never been
121+
/// on the worklist before.
122+
void push(Operand *operand) {
123+
assert(!visited.contains(operand));
124+
visited.insert(operand);
125+
worklist.push_back(operand);
126+
}
127+
128+
/// Like `pop`, but marks the returned operand as "unvisited". This means,
129+
/// that the operand can be pushed onto the worklist again.
130+
Operand *popAndForget() {
131+
if (worklist.empty())
132+
return nullptr;
133+
Operand *operand = worklist.pop_back_val();
134+
visited.erase(operand);
135+
return operand;
136+
}
137+
138+
/// Returns true if \p operand was visited, i.e. has been added to the
139+
/// worklist.
140+
bool isVisited(Operand *operand) const { return visited.contains(operand); }
141+
};
142+
143+
} // namespace swift
144+
145+
#endif

include/swift/SIL/SILFunction.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class SILFunctionBuilder;
3838
class SILProfiler;
3939
class BasicBlockBitfield;
4040
class NodeBitfield;
41+
class OperandBitfield;
4142
class SILPassManager;
4243

4344
namespace Lowering {
@@ -203,6 +204,7 @@ class SILFunction
203204
template <class, class> friend class SILBitfield;
204205
friend class BasicBlockBitfield;
205206
friend class NodeBitfield;
207+
friend class OperandBitfield;
206208

207209
/// Module - The SIL module that the function belongs to.
208210
SILModule &Module;
@@ -278,9 +280,12 @@ class SILFunction
278280
/// The head of a single-linked list of currently alive NodeBitfield.
279281
NodeBitfield *newestAliveNodeBitfield = nullptr;
280282

283+
/// The head of a single-linked list of currently alive OperandBitfields.
284+
OperandBitfield *newestAliveOperandBitfield = nullptr;
285+
281286
/// A monotonically increasing ID which is incremented whenever a
282-
/// BasicBlockBitfield or NodeBitfield is constructed.
283-
/// For details see SILBitfield::bitfieldID;
287+
/// BasicBlockBitfield, NodeBitfield, or OperandBitfield is constructed. For
288+
/// details see SILBitfield::bitfieldID;
284289
int64_t currentBitfieldID = 1;
285290

286291
/// Unique identifier for vector indexing and deterministic sorting.

0 commit comments

Comments
 (0)