Skip to content

Commit fced239

Browse files
committed
[semantic-arc] Change LiveRange to work with Operand instead of Operand->getUser().
This is just better information to have since one wants to not only know the instruction, but also the specific value used on the instruction since behavior can vary depending upon that. The operand is what ties the two together so it is a natural fit. Now that this is done, I am going to work on refactoring out converting a LiveRange from @owned -> @guaranteed. It will be a consuming operation using a move operator since once the transformation has completed, the LiveRange no longer exists. I need this refactored functionality since I am going to need it when eliminating phi-webs.
1 parent 15c7e3a commit fced239

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)