Skip to content

Commit 04007f2

Browse files
authored
Merge pull request swiftlang#30201 from gottesmm/pr-6331d582c9865bfa1aca1fee9d93aeac11f93f4b
[ownership] Convert LiveRange to use Operands.
2 parents 6e71842 + fced239 commit 04007f2

File tree

4 files changed

+76
-53
lines changed

4 files changed

+76
-53
lines changed

include/swift/SIL/SILValue.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,9 @@ class Operand {
669669
return constraint == UseLifetimeConstraint::MustBeInvalidated;
670670
}
671671

672+
SILBasicBlock *getParentBlock() const;
673+
SILFunction *getParentFunction() const;
674+
672675
private:
673676
void removeFromCurrent() {
674677
if (!Back) return;

lib/SIL/SILValue.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,3 +322,17 @@ llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &os,
322322
}
323323
return os;
324324
}
325+
326+
//===----------------------------------------------------------------------===//
327+
// Operand
328+
//===----------------------------------------------------------------------===//
329+
330+
SILBasicBlock *Operand::getParentBlock() const {
331+
auto *self = const_cast<Operand *>(this);
332+
return self->getUser()->getParent();
333+
}
334+
335+
SILFunction *Operand::getParentFunction() const {
336+
auto *self = const_cast<Operand *>(this);
337+
return self->getUser()->getFunction();
338+
}

lib/SILOptimizer/Mandatory/MandatoryInlining.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ static void fixupReferenceCounts(
136136
// am going to change this to use a different API on the linear lifetime
137137
// checker that makes this clearer.
138138
LinearLifetimeChecker checker(visitedBlocks, deadEndBlocks);
139-
auto error = checker.checkValue(pai, {{applySite.getCalleeOperand()}}, {},
139+
auto error = checker.checkValue(pai, {applySite.getCalleeOperand()}, {},
140140
errorBehavior, &leakingBlocks);
141141
if (error.getFoundLeak()) {
142142
while (!leakingBlocks.empty()) {

lib/SILOptimizer/Transforms/SemanticARCOpts.cpp

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,16 @@ namespace {
4747

4848
class LiveRange {
4949
/// A list of destroy_values of the live range.
50-
SmallVector<SILInstruction *, 2> destroys;
50+
SmallVector<Operand *, 2> destroyingUses;
5151

5252
/// A list of forwarding instructions that forward our destroys ownership, but
5353
/// that are also able to forward guaranteed ownership.
54-
SmallVector<SILInstruction *, 2> generalForwardingInsts;
54+
SmallVector<Operand *, 2> generalForwardingUses;
5555

5656
/// Consuming users that we were not able to understand as a forwarding
5757
/// instruction or a destroy_value. These must be passed a strongly control
5858
/// equivalent +1 value.
59-
SmallVector<SILInstruction *, 2> unknownConsumingUsers;
59+
SmallVector<Operand *, 2> unknownConsumingUses;
6060

6161
public:
6262
LiveRange(SILValue value);
@@ -68,18 +68,40 @@ class LiveRange {
6868
///
6969
/// Semantically this implies that a value is never passed off as +1 to memory
7070
/// or another function implying it can be used everywhere at +0.
71-
bool hasConsumingUse() const { return unknownConsumingUsers.size(); }
71+
bool hasConsumingUse() const { return unknownConsumingUses.size(); }
7272

73-
ArrayRef<SILInstruction *> getDestroys() const { return destroys; }
74-
ArrayRef<SILInstruction *> getNonConsumingForwardingInsts() const {
75-
return generalForwardingInsts;
73+
ArrayRef<Operand *> getDestroyingUses() const { return destroyingUses; }
74+
75+
private:
76+
struct OperandToUser;
77+
78+
public:
79+
using DestroyingInstsRange =
80+
TransformRange<ArrayRef<Operand *>, OperandToUser>;
81+
DestroyingInstsRange getDestroyingInsts() const;
82+
83+
ArrayRef<Operand *> getNonConsumingForwardingUses() const {
84+
return generalForwardingUses;
7685
}
7786
};
7887

7988
} // end anonymous namespace
8089

90+
struct LiveRange::OperandToUser {
91+
OperandToUser() {}
92+
93+
SILInstruction *operator()(const Operand *use) const {
94+
auto *nonConstUse = const_cast<Operand *>(use);
95+
return nonConstUse->getUser();
96+
}
97+
};
98+
99+
LiveRange::DestroyingInstsRange LiveRange::getDestroyingInsts() const {
100+
return DestroyingInstsRange(getDestroyingUses(), OperandToUser());
101+
}
102+
81103
LiveRange::LiveRange(SILValue value)
82-
: destroys(), generalForwardingInsts(), unknownConsumingUsers() {
104+
: destroyingUses(), generalForwardingUses(), unknownConsumingUses() {
83105
assert(value.getOwnershipKind() == ValueOwnershipKind::Owned);
84106

85107
// We know that our silvalue produces an @owned value. Look through all of our
@@ -109,8 +131,8 @@ LiveRange::LiveRange(SILValue value)
109131

110132
// Ok, we know now that we have a consuming use. See if we have a destroy
111133
// value, quickly up front. If we do have one, stash it and continue.
112-
if (auto *dvi = dyn_cast<DestroyValueInst>(user)) {
113-
destroys.push_back(dvi);
134+
if (isa<DestroyValueInst>(user)) {
135+
destroyingUses.push_back(op);
114136
continue;
115137
}
116138

@@ -134,13 +156,13 @@ LiveRange::LiveRange(SILValue value)
134156
return v.getOwnershipKind() ==
135157
ValueOwnershipKind::Owned;
136158
})) {
137-
unknownConsumingUsers.push_back(user);
159+
unknownConsumingUses.push_back(op);
138160
continue;
139161
}
140162

141163
// Ok, this is a forwarding instruction whose ownership we can flip from
142164
// owned -> guaranteed.
143-
generalForwardingInsts.push_back(user);
165+
generalForwardingUses.push_back(op);
144166

145167
// If we have a non-terminator, just visit its users recursively to see if
146168
// the the users force the live range to be alive.
@@ -303,14 +325,16 @@ bool IsAddressWrittenToDefUseAnalysis::isWrittenToHelper(SILValue initialValue)
303325
// Convert Forwarding Insts from Owned -> Guaranteed
304326
//===----------------------------------------------------------------------===//
305327

306-
static void convertForwardingInstsFromOwnedToGuaranteed(
307-
ArrayRef<SILInstruction *> guaranteedForwardingInsts) {
328+
static void convertForwardingUsesFromOwnedToGuaranteed(
329+
ArrayRef<Operand *> guaranteedForwardingUses) {
308330
// Then change all of our guaranteed forwarding insts to have guaranteed
309331
// ownership kind instead of what ever they previously had (ignoring trivial
310332
// results);
311-
while (!guaranteedForwardingInsts.empty()) {
312-
auto *i = guaranteedForwardingInsts.back();
313-
guaranteedForwardingInsts = guaranteedForwardingInsts.drop_back();
333+
while (!guaranteedForwardingUses.empty()) {
334+
auto *use = guaranteedForwardingUses.back();
335+
guaranteedForwardingUses = guaranteedForwardingUses.drop_back();
336+
337+
auto *i = use->getUser();
314338

315339
// If this is a term inst, just convert all of its incoming values that are
316340
// owned to be guaranteed.
@@ -745,7 +769,7 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
745769
return borrowScope.isLocalScope();
746770
});
747771

748-
auto destroys = lr.getDestroys();
772+
auto destroys = lr.getDestroyingUses();
749773
if (destroys.empty() && haveAnyLocalScopes) {
750774
return false;
751775
}
@@ -766,23 +790,17 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
766790
// non-local scopes.
767791
{
768792
bool foundNonDeadEnd = false;
769-
for (auto *dvi : destroys) {
770-
foundNonDeadEnd |= !getDeadEndBlocks().isDeadEnd(dvi->getParent());
793+
for (auto *d : destroys) {
794+
foundNonDeadEnd |= !getDeadEndBlocks().isDeadEnd(d->getParentBlock());
771795
}
772796
if (!foundNonDeadEnd && haveAnyLocalScopes)
773797
return false;
774-
// TODO: In a future commit, when LiveRange converts to work with
775-
// operands, this will not be needed. This is just to simplify
776-
// patches.
777-
SmallVector<Operand *, 8> destroyOperands;
778-
transform(destroys, std::back_inserter(destroyOperands),
779-
[](SILInstruction *i) { return &i->getAllOperands()[0]; });
780798
SmallVector<Operand *, 8> scratchSpace;
781799
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
782800
if (llvm::any_of(borrowScopeIntroducers,
783801
[&](BorrowScopeIntroducingValue borrowScope) {
784802
return !borrowScope.areUsesWithinScope(
785-
destroyOperands, scratchSpace, visitedBlocks,
803+
destroys, scratchSpace, visitedBlocks,
786804
getDeadEndBlocks());
787805
})) {
788806
return false;
@@ -792,15 +810,15 @@ bool SemanticARCOptVisitor::performGuaranteedCopyValueOptimization(CopyValueInst
792810
// Otherwise, we know that our copy_value/destroy_values are all completely
793811
// within the guaranteed value scope. First delete the destroys/copies.
794812
while (!destroys.empty()) {
795-
auto *dvi = destroys.back();
813+
auto *d = destroys.back();
796814
destroys = destroys.drop_back();
797-
eraseInstruction(dvi);
815+
eraseInstruction(d->getUser());
798816
++NumEliminatedInsts;
799817
}
800818

801819
eraseAndRAUWSingleValueInstruction(cvi, cvi->getOperand());
802-
convertForwardingInstsFromOwnedToGuaranteed(
803-
lr.getNonConsumingForwardingInsts());
820+
convertForwardingUsesFromOwnedToGuaranteed(
821+
lr.getNonConsumingForwardingUses());
804822

805823
++NumEliminatedInsts;
806824
return true;
@@ -1153,17 +1171,10 @@ class StorageGuaranteesLoadVisitor
11531171

11541172
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
11551173
LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks());
1174+
11561175
// Returns true on success. So we invert.
1157-
auto destroys = liveRange.getDestroys();
1158-
// TODO: Once LiveRange uses operands, eliminate this!
1159-
SmallVector<Operand *, 16> destroyOperands;
1160-
transform(destroys, std::back_inserter(destroyOperands),
1161-
[](SILInstruction *i) {
1162-
assert(isa<DestroyValueInst>(i));
1163-
return &cast<DestroyValueInst>(i)->getAllOperands()[0];
1164-
});
1165-
bool foundError =
1166-
!checker.validateLifetime(baseObject, endScopeInsts, destroyOperands);
1176+
bool foundError = !checker.validateLifetime(baseObject, endScopeInsts,
1177+
liveRange.getDestroyingUses());
11671178
return answer(foundError);
11681179
}
11691180

@@ -1196,17 +1207,12 @@ class StorageGuaranteesLoadVisitor
11961207

11971208
// Then make sure that all of our load [copy] uses are within the
11981209
// destroy_addr.
1199-
SmallVector<Operand *, 16> destroyOperands;
1200-
transform(liveRange.getDestroys(), std::back_inserter(destroyOperands),
1201-
[](SILInstruction *i) {
1202-
return &cast<DestroyValueInst>(i)->getAllOperands()[0];
1203-
});
12041210
SmallPtrSet<SILBasicBlock *, 4> visitedBlocks;
12051211
LinearLifetimeChecker checker(visitedBlocks, ARCOpt.getDeadEndBlocks());
12061212
// Returns true on success. So we invert.
12071213
bool foundError = !checker.validateLifetime(
12081214
stack, destroyAddrOperands /*consuming users*/,
1209-
destroyOperands /*non consuming users*/);
1215+
liveRange.getDestroyingUses() /*non consuming users*/);
12101216
return answer(foundError);
12111217
}
12121218

@@ -1258,8 +1264,7 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
12581264
// to find the post-dominating block set of these destroy value to ensure that
12591265
// we do not insert multiple end_borrow.
12601266
assert(lifetimeFrontier.empty());
1261-
auto destroyValues = lr.getDestroys();
1262-
ValueLifetimeAnalysis analysis(li, destroyValues);
1267+
ValueLifetimeAnalysis analysis(li, lr.getDestroyingInsts());
12631268
bool foundCriticalEdges = !analysis.computeFrontier(
12641269
lifetimeFrontier, ValueLifetimeAnalysis::DontModifyCFG,
12651270
&getDeadEndBlocks());
@@ -1273,10 +1278,11 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
12731278
}
12741279

12751280
// Then delete all of our destroy_value.
1281+
auto destroyValues = lr.getDestroyingUses();
12761282
while (!destroyValues.empty()) {
12771283
auto *dvi = destroyValues.back();
12781284
destroyValues = destroyValues.drop_back();
1279-
eraseInstruction(dvi);
1285+
eraseInstruction(dvi->getUser());
12801286
++NumEliminatedInsts;
12811287
}
12821288

@@ -1285,8 +1291,8 @@ bool SemanticARCOptVisitor::visitLoadInst(LoadInst *li) {
12851291

12861292
// And then change the ownership all of our owned forwarding users to be
12871293
// guaranteed.
1288-
convertForwardingInstsFromOwnedToGuaranteed(
1289-
lr.getNonConsumingForwardingInsts());
1294+
convertForwardingUsesFromOwnedToGuaranteed(
1295+
lr.getNonConsumingForwardingUses());
12901296

12911297
++NumEliminatedInsts;
12921298
++NumLoadCopyConvertedToLoadBorrow;

0 commit comments

Comments
 (0)