Skip to content

Commit f8bcfe2

Browse files
committed
[RAUW] Allow RAUWing some lexical values.
RAUWing a lexical value with a non-lexical value is illegal because it would result in the value's lifetime being shortened without regard to deinit barriers. RAUWing _with_ a lexical value is LEGAL so long as doing so doesn't extend its lifetime.
1 parent d23139f commit f8bcfe2

File tree

2 files changed

+71
-15
lines changed

2 files changed

+71
-15
lines changed

include/swift/SILOptimizer/Utils/OwnershipOptUtils.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ class OwnershipRAUWHelper {
212212
/// their value ownership. This ignores any current uses of \p oldValue. To
213213
/// determine whether \p oldValue can be replaced as-is with it's existing
214214
/// uses, create an instance of OwnershipRAUWHelper and check its validity.
215-
static bool hasValidRAUWOwnership(SILValue oldValue, SILValue newValue);
215+
static bool hasValidRAUWOwnership(SILValue oldValue, SILValue newValue,
216+
ArrayRef<Operand *> oldUses);
216217

217218
private:
218219
OwnershipFixupContext *ctx;
@@ -283,6 +284,10 @@ class OwnershipRAUWHelper {
283284
SILValue getReplacementAddress();
284285
};
285286

287+
/// Whether the provided uses lie within the current liveness of the
288+
/// specified lexical value.
289+
bool areUsesWithinLexicalValueLifetime(SILValue, ArrayRef<Operand *>);
290+
286291
/// A utility composed ontop of OwnershipFixupContext that knows how to replace
287292
/// a single use of a value with another value with a different ownership. We
288293
/// allow for the values to have different types.

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -297,13 +297,28 @@ static void cleanupOperandsBeforeDeletion(SILInstruction *oldValue,
297297
// directly checking ownership requirements. This does not determine whether the
298298
// scope of the newValue can be fully extended.
299299
bool OwnershipRAUWHelper::hasValidRAUWOwnership(SILValue oldValue,
300-
SILValue newValue) {
300+
SILValue newValue,
301+
ArrayRef<Operand *> oldUses) {
301302
auto newOwnershipKind = newValue.getOwnershipKind();
302303

303304
// If the either value is lexical, replacing its uses may result in
304305
// shortening or lengthening its lifetime in ways that don't respect lexical
305306
// scope and deinit barriers.
306-
if (oldValue->isLexical() || newValue->isLexical())
307+
//
308+
// Specifically, we have the following cases:
309+
//
310+
// +--------+--------+
311+
// |oldValue|newValue|
312+
// +--------+--------+
313+
// | not | not | legal
314+
// +--------+--------+
315+
// |lexical | not | illegal
316+
// +--------+--------+
317+
// | * |lexical | legal so long as it doesn't extend newValue's lifetime
318+
// +--------+--------+
319+
if ((oldValue->isLexical() && !newValue->isLexical()) ||
320+
(newValue->isLexical() &&
321+
!areUsesWithinLexicalValueLifetime(newValue, oldUses)))
307322
return false;
308323

309324
// If our new kind is ValueOwnershipKind::None, then we are fine. We
@@ -353,20 +368,51 @@ bool OwnershipRAUWHelper::hasValidRAUWOwnership(SILValue oldValue,
353368
// extend the lifetime of \p oldValue to cover the new uses.
354369
static bool canFixUpOwnershipForRAUW(SILValue oldValue, SILValue newValue,
355370
OwnershipFixupContext &context) {
356-
if (!OwnershipRAUWHelper::hasValidRAUWOwnership(oldValue, newValue))
357-
return false;
371+
switch (oldValue.getOwnershipKind()) {
372+
case OwnershipKind::Guaranteed:
373+
// Check that the old lifetime can be extended and record the necessary
374+
// book-keeping in the OwnershipFixupContext.
375+
context.clear();
376+
377+
// Check that no transitive uses have a PointerEscape, and record the leaf
378+
// uses for liveness extension.
379+
if (!findExtendedTransitiveGuaranteedUses(oldValue,
380+
context.guaranteedUsePoints))
381+
return false;
382+
return OwnershipRAUWHelper::hasValidRAUWOwnership(
383+
oldValue, newValue, context.guaranteedUsePoints);
384+
default: {
385+
SmallVector<Operand *, 8> ownedUsePoints;
386+
// If newValue is lexical, find the uses of oldValue so that it can be
387+
// determined whether the replacement would illegally extend the lifetime
388+
// of newValue.
389+
if (newValue->isLexical() &&
390+
!findUsesOfSimpleValue(oldValue, &ownedUsePoints))
391+
return false;
392+
return OwnershipRAUWHelper::hasValidRAUWOwnership(oldValue, newValue,
393+
ownedUsePoints);
394+
}
395+
}
396+
}
397+
398+
bool swift::areUsesWithinLexicalValueLifetime(SILValue value,
399+
ArrayRef<Operand *> uses) {
400+
assert(value->isLexical());
358401

359-
if (oldValue.getOwnershipKind() != OwnershipKind::Guaranteed)
402+
// The lexical lifetime of a function argument is the whole body of the
403+
// function.
404+
if (isa<SILFunctionArgument>(value))
360405
return true;
361406

362-
// Check that the old lifetime can be extended and record the necessary
363-
// book-keeping in the OwnershipFixupContext.
364-
context.clear();
407+
if (auto borrowedValue = BorrowedValue(value)) {
408+
PrunedLiveness liveness;
409+
auto *function = value->getFunction();
410+
borrowedValue.computeLiveness(liveness);
411+
DeadEndBlocks deadEndBlocks(function);
412+
return liveness.areUsesWithinBoundary(uses, &deadEndBlocks);
413+
}
365414

366-
// Check that no transitive uses have a PointerEscape, and record the leaf
367-
// uses for liveness extension.
368-
return findExtendedTransitiveGuaranteedUses(oldValue,
369-
context.guaranteedUsePoints);
415+
return false;
370416
}
371417

372418
//===----------------------------------------------------------------------===//
@@ -1118,7 +1164,9 @@ SILValue OwnershipRAUWPrepare::prepareReplacement(SILValue newValue) {
11181164
if (oldValue->use_empty())
11191165
return newValue;
11201166

1121-
assert(OwnershipRAUWHelper::hasValidRAUWOwnership(oldValue, newValue) &&
1167+
assert(
1168+
OwnershipRAUWHelper::hasValidRAUWOwnership(oldValue, newValue,
1169+
ctx.guaranteedUsePoints) &&
11221170
"Should have checked if can perform this operation before calling it?!");
11231171
// If our new value is just none, we can pass anything to it so just RAUW
11241172
// and return.
@@ -1576,7 +1624,10 @@ OwnershipReplaceSingleUseHelper::OwnershipReplaceSingleUseHelper(
15761624

15771625
// Otherwise, lets check if we can perform this RAUW operation. If we can't,
15781626
// set ctx to nullptr to invalidate the helper and return.
1579-
if (!OwnershipRAUWHelper::hasValidRAUWOwnership(use->get(), newValue)) {
1627+
SmallVector<Operand *, 1> oldUses;
1628+
oldUses.push_back(use);
1629+
if (!OwnershipRAUWHelper::hasValidRAUWOwnership(use->get(), newValue,
1630+
oldUses)) {
15801631
invalidate();
15811632
return;
15821633
}

0 commit comments

Comments
 (0)