Skip to content

Commit 74c71b8

Browse files
committed
[send-non-sendable] Make TrackableSILValue a POD value.
Previously before this patch, the logic for constructing TrackableSILValue was split inbetween TrackableSILValue and the PartitionOpTranslator. A lot of routines were also just utility routines that did not depend on the state in either of the constructs. With that in mind in this patch I: 1. Moved the utility functions that did not depend on internal state of those functions into utility functions in the utility section. 2. Moved the logic in TrackableSILValue's constructor that depended on state inside PartitionOpTranslator into PartitionOpTranslator itself. 3. Made TrackableSILValue a simple POD type used for storing state. 4. I changed capturedUIValues to just store within it a SILValue. It actually does not care about isAliased or isSendable... it is just used as a way to check if we have a uniquely identified value. In a forthcoming patch, I am going to try to do similar things with the other maps that use TrackableSILValues since by making the TrackableSILValues our keys/sets it allows for us to potentially store multiple versions of the same TrackableSILValues if their aliased/sendable state differ... which would lead to bugs.
1 parent 4f20b5d commit 74c71b8

File tree

1 file changed

+98
-102
lines changed

1 file changed

+98
-102
lines changed

lib/SILOptimizer/Mandatory/SendNonSendable.cpp

Lines changed: 98 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,36 @@ static bool isApplyInst(SILInstruction &inst) {
5656
return ApplySite::isa(&inst) || isa<BuiltinInst>(inst);
5757
}
5858

59+
static AccessStorage getAccessStorageFromAddr(SILValue value) {
60+
assert(isAddress(value));
61+
auto accessStorage = AccessStorage::compute(value);
62+
if (accessStorage && accessStorage.getRoot()) {
63+
if (auto definingInst = accessStorage.getRoot().getDefiningInstruction()) {
64+
if (isa<InitExistentialAddrInst, CopyValueInst>(definingInst))
65+
// look through these because AccessStorage does not
66+
return getAccessStorageFromAddr(definingInst->getOperand(0));
67+
}
68+
}
69+
70+
return accessStorage;
71+
}
72+
73+
static SILValue getUnderlyingTrackedValue(SILValue value) {
74+
if (!isAddress(value)) {
75+
return getUnderlyingObject(value);
76+
}
77+
78+
if (auto accessStorage = getAccessStorageFromAddr(value)) {
79+
if (accessStorage.getKind() == AccessRepresentation::Kind::Global)
80+
// globals don't reduce
81+
return value;
82+
assert(accessStorage.getRoot());
83+
return accessStorage.getRoot();
84+
}
85+
86+
return value;
87+
}
88+
5989
//===----------------------------------------------------------------------===//
6090
// MARK: Main Computation
6191
//===----------------------------------------------------------------------===//
@@ -67,6 +97,41 @@ static const char *SEP_STR = "╾───────────────
6797
using TrackableValueID = PartitionPrimitives::Element;
6898
using Region = PartitionPrimitives::Region;
6999

100+
class TrackableSILValue {
101+
SILValue value;
102+
bool aliased;
103+
bool sendable;
104+
105+
public:
106+
TrackableSILValue(SILValue inputValue, bool aliased, bool sendable)
107+
: value(inputValue), aliased(aliased), sendable(sendable) {}
108+
109+
bool isAliased() const { return aliased; }
110+
111+
bool isUnaliased() const { return !aliased; }
112+
113+
bool isSendable() const { return sendable; }
114+
115+
bool isNonSendable() const { return !sendable; }
116+
117+
SILValue getValue() const { return value; }
118+
119+
// comparison operates lookthrough to the underlying SILValue
120+
bool operator==(const TrackableSILValue &other) const {
121+
return value == other.value;
122+
}
123+
124+
bool operator<(const TrackableSILValue &other) const {
125+
return value < other.value;
126+
}
127+
128+
void dump() const {
129+
llvm::dbgs() << "TrackableSILValue[aliased=" << aliased
130+
<< "][sendable=" << sendable << "]: ";
131+
value->dump();
132+
}
133+
};
134+
70135
// PartitionOpTranslator is responsible for performing the translation from
71136
// SILInstructions to PartitionOps. Not all SILInstructions have an effect on
72137
// the region partition, and some have multiple effects - such as an application
@@ -87,100 +152,8 @@ class PartitionOpTranslator {
87152
SILFunction *function;
88153
ProtocolDecl *sendableProtocol;
89154

90-
class TrackableSILValue {
91-
bool aliased = true;
92-
bool sendable = false;
93-
SILValue value;
94-
95-
AccessStorage getAccessStorageFromAddr(SILValue val) {
96-
assert(isAddress(val));
97-
auto accessStorage = AccessStorage::compute(val);
98-
if (accessStorage && accessStorage.getRoot()) {
99-
auto definingInst = accessStorage.getRoot().getDefiningInstruction();
100-
if (definingInst &&
101-
isa<InitExistentialAddrInst, CopyValueInst>(definingInst))
102-
// look through these because AccessStorage does not
103-
return getAccessStorageFromAddr(definingInst->getOperand(0));
104-
}
105-
return accessStorage;
106-
}
107-
108-
// simplifyVal reduces an address-typed SILValue to the root SILValue
109-
// that it was derived from, reducing the set of values that must be
110-
// reasoned about by rendering two values that are projections/aliases the
111-
// same.
112-
SILValue simplifyVal(SILValue val) {
113-
if (!isAddress(val))
114-
//TODO: consider adding more reduction for non-address values
115-
return getUnderlyingObject(val);
116-
if (auto accessStorage = getAccessStorageFromAddr(val)) {
117-
if (accessStorage.getKind() == AccessRepresentation::Kind::Global)
118-
// globals don't reduce
119-
return val;
120-
assert(accessStorage.getRoot());
121-
return accessStorage.getRoot();
122-
}
123-
return val;
124-
}
125-
126-
public:
127-
TrackableSILValue(const PartitionOpTranslator *translator,
128-
SILValue value_in) :
129-
value(simplifyVal(value_in)) {
130-
131-
// set `aliased` appropriately
132-
if (isAddress(value))
133-
if (auto accessStorage = AccessStorage::compute(value))
134-
aliased = !accessStorage.isUniquelyIdentified() ||
135-
translator->capturedUIValues.count(*this);
136-
137-
// set `sendable` appropriately
138-
SILInstruction *defInst = value.getDefiningInstruction();
139-
if (defInst && isa<ClassMethodInst, FunctionRefInst>(defInst)) {
140-
// though these values are technically non-Sendable, we can safely
141-
// and consistently treat them as Sendable
142-
sendable = true;
143-
} else {
144-
sendable = !translator->isNonSendableType(value->getType());
145-
}
146-
}
147-
inline bool isAliased() const {
148-
return aliased;
149-
}
150-
151-
inline bool isUnaliased() const {
152-
return !aliased;
153-
}
154-
155-
inline bool isSendable() const {
156-
return sendable;
157-
}
158-
159-
inline bool isNonSendable() const {
160-
return !sendable;
161-
}
162-
163-
SILValue getValue() const {
164-
return value;
165-
}
166-
167-
// comparison operates lookthrough to the underlying SILValue
168-
bool operator==(const TrackableSILValue &other) const {
169-
return value == other.value;
170-
}
171-
bool operator<(const TrackableSILValue &other) const {
172-
return value < other.value;
173-
}
174-
175-
void dump() const {
176-
llvm::dbgs() << "TrackableSILValue[aliased="
177-
<< aliased << "][sendable=" << sendable << "]: ";
178-
value->dump();
179-
}
180-
};
181-
182155
llvm::Optional<TrackableSILValue> trackIfNonSendable(SILValue value) const {
183-
auto trackedVal = TrackableSILValue(this, value);
156+
auto trackedVal = getTrackableSILValue(value);
184157
if (trackedVal.isNonSendable()) {
185158
return trackedVal;
186159
}
@@ -202,7 +175,32 @@ class PartitionOpTranslator {
202175
// but at what points in function flow they do, this would be more
203176
// permissive, but I'm avoiding implementing it in case existing
204177
// utilities would make it easier than handrolling
205-
std::set<TrackableSILValue> capturedUIValues;
178+
std::set<SILValue> capturedUIValues;
179+
180+
TrackableSILValue getTrackableSILValue(SILValue value) const {
181+
value = getUnderlyingTrackedValue(value);
182+
183+
bool isAliased = true;
184+
185+
if (isAddress(value)) {
186+
if (auto accessStorage = AccessStorage::compute(value))
187+
isAliased = !accessStorage.isUniquelyIdentified() ||
188+
capturedUIValues.count(value);
189+
}
190+
191+
// set `sendable` appropriately
192+
if (auto *defInst = value.getDefiningInstruction()) {
193+
// Though these values are technically non-Sendable, we can safely and
194+
// consistently treat them as Sendable.
195+
if (isa<ClassMethodInst, FunctionRefInst>(defInst)) {
196+
return TrackableSILValue(value, isAliased, true /*is sendable*/);
197+
}
198+
}
199+
200+
// Otherwise refer to the oracle.
201+
return TrackableSILValue(value, isAliased,
202+
!isNonSendableType(value->getType()));
203+
}
206204

207205
void initCapturedUIValues() {
208206
for (auto &block : *function) {
@@ -211,9 +209,9 @@ class PartitionOpTranslator {
211209
// add all nonsendable, uniquely identified arguments to applications
212210
// to capturedUIValues, because applications capture them
213211
for (SILValue val : inst.getOperandValues()) {
214-
auto trackVal = TrackableSILValue(this, val);
212+
auto trackVal = getTrackableSILValue(val);
215213
if (trackVal.isNonSendable() && trackVal.isUnaliased())
216-
capturedUIValues.insert(trackVal);
214+
capturedUIValues.insert(val);
217215
}
218216
}
219217
}
@@ -231,12 +229,10 @@ class PartitionOpTranslator {
231229
"in contexts in which the availability of the "
232230
"Sendable protocol has already been checked.");
233231
initCapturedUIValues();
234-
LLVM_DEBUG(
235-
llvm::dbgs() << "Captured Uniquely Identified addresses for "
236-
<< function->getName() << ":\n";
237-
for (TrackableSILValue val : capturedUIValues)
238-
val.getValue()->dump();
239-
);
232+
LLVM_DEBUG(llvm::dbgs() << "Captured Uniquely Identified addresses for "
233+
<< function->getName() << ":\n";
234+
for (SILValue val
235+
: capturedUIValues) val->dump(););
240236
}
241237

242238
private:

0 commit comments

Comments
 (0)