Skip to content

Commit 957a79f

Browse files
committed
[region-isolation] Track operands instead of SILInstructions for Transfer instructions.
This is another NFC refactor in preparation for changing how we emit errors. Specifically, we need access to not only the instruction, but also the specific operand that the transfer occurs at. This ensures that we can look up the specific type information later when we emit an error rather than tracking this information throughout the entire pass.
1 parent fc73210 commit 957a79f

File tree

5 files changed

+132
-97
lines changed

5 files changed

+132
-97
lines changed

include/swift/SIL/ApplySite.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,20 @@ class ApplySite {
500500
llvm_unreachable("covered switch");
501501
}
502502

503+
MutableArrayRef<Operand> getOperandsWithoutSelf() {
504+
switch (ApplySiteKind(Inst->getKind())) {
505+
case ApplySiteKind::ApplyInst:
506+
return cast<ApplyInst>(Inst)->getOperandsWithoutSelf();
507+
case ApplySiteKind::BeginApplyInst:
508+
return cast<BeginApplyInst>(Inst)->getOperandsWithoutSelf();
509+
case ApplySiteKind::TryApplyInst:
510+
return cast<TryApplyInst>(Inst)->getOperandsWithoutSelf();
511+
case ApplySiteKind::PartialApplyInst:
512+
llvm_unreachable("Unhandled case");
513+
}
514+
llvm_unreachable("covered switch");
515+
}
516+
503517
/// Returns true if \p op is an operand that passes an indirect
504518
/// result argument to the apply site.
505519
bool isIndirectResultOperand(const Operand &op) const;

include/swift/SIL/SILInstruction.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2901,6 +2901,16 @@ class ApplyInstBase<Impl, Base, true>
29012901
return opsWithoutSelf;
29022902
}
29032903

2904+
MutableArrayRef<Operand> getOperandsWithoutSelf() {
2905+
assert(getNumArguments() && "Should only be called when Callee has "
2906+
"at least a self parameter.");
2907+
MutableArrayRef<Operand> ops = this->getArgumentOperands();
2908+
if (!hasSelfArgument())
2909+
return ops;
2910+
auto opsWithoutSelf = ops.drop_back();
2911+
return opsWithoutSelf;
2912+
}
2913+
29042914
llvm::Optional<SILResultInfo> getSingleResult() const {
29052915
auto SubstCallee = getSubstCalleeType();
29062916
if (SubstCallee->getNumResults() != 1)

include/swift/SILOptimizer/Utils/PartitionUtils.h

Lines changed: 79 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -117,30 +117,37 @@ class PartitionOp {
117117
using Element = PartitionPrimitives::Element;
118118

119119
private:
120-
PartitionOpKind OpKind;
121-
llvm::SmallVector<Element, 2> OpArgs;
120+
PartitionOpKind opKind;
121+
llvm::SmallVector<Element, 2> opArgs;
122122

123123
/// Record the SILInstruction that this PartitionOp was generated from, if
124124
/// generated during compilation from a SILBasicBlock
125-
SILInstruction *sourceInst;
125+
PointerUnion<SILInstruction *, Operand *> source;
126126

127127
/// Record an AST expression corresponding to this PartitionOp, currently
128128
/// populated only for Transfer expressions to indicate the value being
129129
/// transferred
130130
Expr *sourceExpr;
131131

132132
// TODO: can the following declarations be merged?
133-
PartitionOp(PartitionOpKind OpKind, Element arg1,
133+
PartitionOp(PartitionOpKind opKind, Element arg1,
134134
SILInstruction *sourceInst = nullptr, Expr *sourceExpr = nullptr)
135-
: OpKind(OpKind), OpArgs({arg1}), sourceInst(sourceInst),
135+
: opKind(opKind), opArgs({arg1}), source(sourceInst),
136136
sourceExpr(sourceExpr) {
137-
assert((OpKind != PartitionOpKind::Transfer || sourceInst) &&
137+
assert((opKind != PartitionOpKind::Transfer || sourceInst) &&
138+
"Transfer needs a sourceInst");
139+
}
140+
141+
PartitionOp(PartitionOpKind opKind, Element arg1,
142+
Operand *sourceOperand, Expr *sourceExpr = nullptr)
143+
: opKind(opKind), opArgs({arg1}), source(sourceOperand), sourceExpr(sourceExpr) {
144+
assert((opKind != PartitionOpKind::Transfer || source) &&
138145
"Transfer needs a sourceInst");
139146
}
140147

141148
PartitionOp(PartitionOpKind OpKind, Element arg1, Element arg2,
142149
SILInstruction *sourceInst = nullptr, Expr *sourceExpr = nullptr)
143-
: OpKind(OpKind), OpArgs({arg1, arg2}), sourceInst(sourceInst),
150+
: opKind(OpKind), opArgs({arg1, arg2}), source(sourceInst),
144151
sourceExpr(sourceExpr) {
145152
assert((OpKind != PartitionOpKind::Transfer || sourceInst) &&
146153
"Transfer needs a sourceInst");
@@ -159,9 +166,9 @@ class PartitionOp {
159166
return PartitionOp(PartitionOpKind::AssignFresh, tgt, sourceInst);
160167
}
161168

162-
static PartitionOp Transfer(Element tgt, SILInstruction *transferringInst,
169+
static PartitionOp Transfer(Element tgt, Operand *transferringOp,
163170
Expr *sourceExpr = nullptr) {
164-
return PartitionOp(PartitionOpKind::Transfer, tgt, transferringInst,
171+
return PartitionOp(PartitionOpKind::Transfer, tgt, transferringOp,
165172
sourceExpr);
166173
}
167174

@@ -176,30 +183,30 @@ class PartitionOp {
176183
}
177184

178185
bool operator==(const PartitionOp &other) const {
179-
return OpKind == other.OpKind
180-
&& OpArgs == other.OpArgs
181-
&& sourceInst == other.sourceInst;
186+
return opKind == other.opKind && opArgs == other.opArgs &&
187+
source == other.source;
182188
};
183189

184190
bool operator<(const PartitionOp &other) const {
185-
if (OpKind != other.OpKind)
186-
return OpKind < other.OpKind;
187-
if (OpArgs != other.OpArgs)
188-
return OpArgs < other.OpArgs;
189-
return sourceInst < other.sourceInst;
191+
if (opKind != other.opKind)
192+
return opKind < other.opKind;
193+
if (opArgs != other.opArgs)
194+
return opArgs < other.opArgs;
195+
return source < other.source;
190196
}
191197

192-
PartitionOpKind getKind() const { return OpKind; }
198+
PartitionOpKind getKind() const { return opKind; }
193199

194-
ArrayRef<Element> getOpArgs() const { return OpArgs; }
200+
ArrayRef<Element> getOpArgs() const { return opArgs; }
195201

196-
SILInstruction *getSourceInst(bool assertNonNull = false) const {
197-
assert(!assertNonNull ||
198-
sourceInst && "PartitionOps should be assigned SILInstruction"
199-
" sources when used for the core analysis");
200-
return sourceInst;
202+
SILInstruction *getSourceInst() const {
203+
if (source.is<Operand *>())
204+
return source.get<Operand *>()->getUser();
205+
return source.get<SILInstruction *>();
201206
}
202207

208+
Operand *getSourceOp() const { return source.get<Operand *>(); }
209+
203210
SILLocation getSourceLoc() const { return getSourceInst(true)->getLoc(); }
204211

205212
Expr *getSourceExpr() const {
@@ -209,44 +216,44 @@ class PartitionOp {
209216
SWIFT_DEBUG_DUMP { print(llvm::dbgs()); }
210217

211218
void print(llvm::raw_ostream &os, bool extraSpace = false) const {
212-
switch (OpKind) {
219+
switch (opKind) {
213220
case PartitionOpKind::Assign: {
214221
constexpr static char extraSpaceLiteral[10] = " ";
215222
os << "assign ";
216223
if (extraSpace)
217224
os << extraSpaceLiteral;
218-
os << "%%" << OpArgs[0] << " = %%" << OpArgs[1];
225+
os << "%%" << opArgs[0] << " = %%" << opArgs[1];
219226
break;
220227
}
221228
case PartitionOpKind::AssignFresh:
222-
os << "assign_fresh %%" << OpArgs[0];
229+
os << "assign_fresh %%" << opArgs[0];
223230
break;
224231
case PartitionOpKind::Transfer: {
225232
constexpr static char extraSpaceLiteral[10] = " ";
226233
os << "transfer ";
227234
if (extraSpace)
228235
os << extraSpaceLiteral;
229-
os << "%%" << OpArgs[0];
236+
os << "%%" << opArgs[0];
230237
break;
231238
}
232239
case PartitionOpKind::Merge: {
233240
constexpr static char extraSpaceLiteral[10] = " ";
234241
os << "merge ";
235242
if (extraSpace)
236243
os << extraSpaceLiteral;
237-
os << "%%" << OpArgs[0] << " with %%" << OpArgs[1];
244+
os << "%%" << opArgs[0] << " with %%" << opArgs[1];
238245
break;
239246
}
240247
case PartitionOpKind::Require: {
241248
constexpr static char extraSpaceLiteral[10] = " ";
242249
os << "require ";
243250
if (extraSpace)
244251
os << extraSpaceLiteral;
245-
os << "%%" << OpArgs[0];
252+
os << "%%" << opArgs[0];
246253
break;
247254
}
248255
}
249-
os << ": " << *getSourceInst(true);
256+
os << ": " << *getSourceInst();
250257
}
251258
};
252259

@@ -288,7 +295,7 @@ class Partition {
288295
/// multi map here. The implication of this is that when we are performing
289296
/// dataflow we use a union operation to combine CFG elements and just take
290297
/// the first instruction that we see.
291-
llvm::SmallDenseMap<Region, SILInstruction *, 2> regionToTransferredInstMap;
298+
llvm::SmallDenseMap<Region, Operand *, 2> regionToTransferredOpMap;
292299

293300
public:
294301
Partition() : elementToRegionMap({}), canonical(true) {}
@@ -342,12 +349,12 @@ class Partition {
342349

343350
/// Mark val as transferred. Returns true if we inserted \p
344351
/// transferOperand. We return false otherwise.
345-
bool markTransferred(Element val, SILInstruction *transferOperand) {
352+
bool markTransferred(Element val, Operand *transferOperand) {
346353
// First see if our val is tracked. If it is not tracked, insert it and mark
347354
// its new region as transferred.
348355
if (!isTracked(val)) {
349356
elementToRegionMap.insert_or_assign(val, fresh_label);
350-
regionToTransferredInstMap.insert({fresh_label, transferOperand});
357+
regionToTransferredOpMap.insert({fresh_label, transferOperand});
351358
fresh_label = Region(fresh_label + 1);
352359
canonical = false;
353360
return true;
@@ -357,7 +364,7 @@ class Partition {
357364
auto iter1 = elementToRegionMap.find(val);
358365
assert(iter1 != elementToRegionMap.end());
359366
auto iter2 =
360-
regionToTransferredInstMap.try_emplace(iter1->second, transferOperand);
367+
regionToTransferredOpMap.try_emplace(iter1->second, transferOperand);
361368
return iter2.second;
362369
}
363370

@@ -384,10 +391,10 @@ class Partition {
384391

385392
// Then if sndRegionNumber is transferred in sndReduced, make sure
386393
// mergedRegion is transferred in fstReduced.
387-
auto iter = sndReduced.regionToTransferredInstMap.find(sndRegionNumber);
388-
if (iter != sndReduced.regionToTransferredInstMap.end()) {
389-
fstReduced.regionToTransferredInstMap.try_emplace(mergedRegion,
390-
iter->second);
394+
auto iter = sndReduced.regionToTransferredOpMap.find(sndRegionNumber);
395+
if (iter != sndReduced.regionToTransferredOpMap.end()) {
396+
fstReduced.regionToTransferredOpMap.try_emplace(mergedRegion,
397+
iter->second);
391398
}
392399
continue;
393400
}
@@ -420,9 +427,9 @@ class Partition {
420427
// due to our traversal being in order. Thus just add this to fst_reduced.
421428
assert(sndEltNumber == Element(sndRegionNumber));
422429
fstReduced.elementToRegionMap.insert({sndEltNumber, sndRegionNumber});
423-
auto iter = sndReduced.regionToTransferredInstMap.find(sndRegionNumber);
424-
if (iter != sndReduced.regionToTransferredInstMap.end()) {
425-
fstReduced.regionToTransferredInstMap.insert(
430+
auto iter = sndReduced.regionToTransferredOpMap.find(sndRegionNumber);
431+
if (iter != sndReduced.regionToTransferredOpMap.end()) {
432+
fstReduced.regionToTransferredOpMap.insert(
426433
{sndRegionNumber, iter->second});
427434
}
428435
if (fstReduced.fresh_label < sndRegionNumber)
@@ -489,7 +496,7 @@ class Partition {
489496

490497
os << "[";
491498
for (auto [regionNo, elementNumbers] : multimap.getRange()) {
492-
bool isTransferred = regionToTransferredInstMap.count(regionNo);
499+
bool isTransferred = regionToTransferredOpMap.count(regionNo);
493500
os << (isTransferred ? "{" : "(");
494501
int j = 0;
495502
for (Element i : elementNumbers) {
@@ -504,17 +511,17 @@ class Partition {
504511
auto iter = elementToRegionMap.find(val);
505512
if (iter == elementToRegionMap.end())
506513
return false;
507-
return regionToTransferredInstMap.count(iter->second);
514+
return regionToTransferredOpMap.count(iter->second);
508515
}
509516

510517
/// Return the instruction that transferred \p val's region or nullptr
511518
/// otherwise.
512-
SILInstruction *getTransferred(Element val) const {
519+
Operand *getTransferred(Element val) const {
513520
auto iter = elementToRegionMap.find(val);
514521
if (iter == elementToRegionMap.end())
515522
return nullptr;
516-
auto iter2 = regionToTransferredInstMap.find(iter->second);
517-
if (iter2 == regionToTransferredInstMap.end())
523+
auto iter2 = regionToTransferredOpMap.find(iter->second);
524+
if (iter2 == regionToTransferredOpMap.end())
518525
return nullptr;
519526
return iter2->second;
520527
}
@@ -535,7 +542,7 @@ class Partition {
535542
llvm::SmallDenseSet<Region, 8> seenRegion;
536543
for (auto &[eltNo, regionNo] : elementToRegionMap) {
537544
// See if all of our regionToTransferMap keys are regions in labels.
538-
if (regionToTransferredInstMap.count(regionNo))
545+
if (regionToTransferredOpMap.count(regionNo))
539546
seenRegion.insert(regionNo);
540547

541548
// Labels should not exceed fresh_label.
@@ -555,7 +562,7 @@ class Partition {
555562
return fail(eltNo, 3);
556563
}
557564

558-
if (seenRegion.size() != regionToTransferredInstMap.size()) {
565+
if (seenRegion.size() != regionToTransferredOpMap.size()) {
559566
llvm::report_fatal_error(
560567
"FAIL! regionToTransferMap has a region that isn't being tracked?!");
561568
}
@@ -596,12 +603,15 @@ class Partition {
596603

597604
// Then relabel our regionToTransferredInst map if we need to by swapping
598605
// out the old map and updating.
599-
llvm::SmallDenseMap<Region, SILInstruction *, 2> oldMap =
600-
std::move(regionToTransferredInstMap);
601-
for (auto &[oldReg, inst] : oldMap) {
606+
//
607+
// TODO: If we just used an array for this, we could just rewrite and
608+
// re-sort and not have to deal with potential allocations.
609+
llvm::SmallDenseMap<Region, Operand *, 2> oldMap =
610+
std::move(regionToTransferredOpMap);
611+
for (auto &[oldReg, op] : oldMap) {
602612
auto iter = oldRegionToRelabeledMap.find(oldReg);
603613
assert(iter != oldRegionToRelabeledMap.end());
604-
regionToTransferredInstMap[iter->second] = inst;
614+
regionToTransferredOpMap[iter->second] = op;
605615
}
606616

607617
assert(is_canonical_correct());
@@ -628,19 +638,19 @@ class Partition {
628638

629639
// Rename snd to use first region.
630640
horizontalUpdate(elementToRegionMap, snd, fstRegion);
631-
auto iter = regionToTransferredInstMap.find(sndRegion);
632-
if (iter != regionToTransferredInstMap.end()) {
633-
regionToTransferredInstMap.try_emplace(fstRegion, iter->second);
634-
regionToTransferredInstMap.erase(iter);
641+
auto iter = regionToTransferredOpMap.find(sndRegion);
642+
if (iter != regionToTransferredOpMap.end()) {
643+
regionToTransferredOpMap.try_emplace(fstRegion, iter->second);
644+
regionToTransferredOpMap.erase(iter);
635645
}
636646
} else {
637647
result = sndRegion;
638648

639649
horizontalUpdate(elementToRegionMap, fst, sndRegion);
640-
auto iter = regionToTransferredInstMap.find(fstRegion);
641-
if (iter != regionToTransferredInstMap.end()) {
642-
regionToTransferredInstMap.try_emplace(sndRegion, iter->second);
643-
regionToTransferredInstMap.erase(iter);
650+
auto iter = regionToTransferredOpMap.find(fstRegion);
651+
if (iter != regionToTransferredOpMap.end()) {
652+
regionToTransferredOpMap.try_emplace(sndRegion, iter->second);
653+
regionToTransferredOpMap.erase(iter);
644654
}
645655
}
646656

@@ -702,9 +712,11 @@ struct PartitionOpEvaluator {
702712
///
703713
/// 2. The element in the PartitionOp that was asked to be alive.
704714
///
705-
/// 3. The instruction that originally transferred the region.
706-
std::function<void(const PartitionOp &, Element, SILInstruction *)>
707-
failureCallback = nullptr;
715+
/// 3. The operand of the instruction that originally transferred the
716+
/// region. Can be used to get the immediate value transferred or the
717+
/// transferring instruction.
718+
std::function<void(const PartitionOp &, Element, Operand *)> failureCallback =
719+
nullptr;
708720

709721
/// A list of elements that cannot be transferred. Whenever we transfer, we
710722
/// check this list to see if we are transferring the element and then call
@@ -727,10 +739,10 @@ struct PartitionOpEvaluator {
727739

728740
/// A wrapper around the failure callback that checks if it is nullptr.
729741
void handleFailure(const PartitionOp &op, Element elt,
730-
SILInstruction *transferringInst) const {
742+
Operand *transferringOp) const {
731743
if (!failureCallback)
732744
return;
733-
failureCallback(op, elt, transferringInst);
745+
failureCallback(op, elt, transferringOp);
734746
}
735747

736748
/// A wrapper around transferNonTransferrableCallback that only calls it if it
@@ -829,7 +841,7 @@ struct PartitionOpEvaluator {
829841
return handleTransferNonTransferrable(op, op.getOpArgs()[0]);
830842

831843
// Mark op.getOpArgs()[0] as transferred.
832-
p.markTransferred(op.getOpArgs()[0], op.getSourceInst(true));
844+
p.markTransferred(op.getOpArgs()[0], op.getSourceOp());
833845
break;
834846
}
835847
case PartitionOpKind::Merge:

0 commit comments

Comments
 (0)