Skip to content

Commit 1e4d3d2

Browse files
committed
[sil-inst-opt] Add a new utility swift::replaceSingleUse.
Given an Operand *op, this API executes op->set(newSILValue) except that: 1. If the user of op is an end scope, this API no-opts. This API is only used in contexts where we are rewriting uses and are not interesting in end scope instructions since we are moving uses from one scope to another scope. 2. If the user of op is not an end scope, but is a lifetime ending use of op->get(), we insert a destroy_value|end_borrow as appropriate on op->get() to ensure op->get()'s lifetime is still ended. We assume that if op->getUser() is lifetime ending, that our caller has ensured that we can end newValue's lifetime.
1 parent 1b14b5b commit 1e4d3d2

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,11 @@ SILBasicBlock::iterator replaceAllUsesAndErase(SingleValueInstruction *svi,
673673
SILValue newValue,
674674
InstModCallbacks &callbacks);
675675

676+
/// Low level routine that replaces the current value of \p use with \p
677+
/// newValue.
678+
SILBasicBlock::iterator replaceSingleUse(Operand *use, SILValue newValue,
679+
InstModCallbacks &callbacks);
680+
676681
} // end namespace swift
677682

678683
#endif

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,3 +1909,57 @@ swift::replaceAllUsesAndErase(SingleValueInstruction *svi, SILValue newValue,
19091909

19101910
return nextii;
19111911
}
1912+
1913+
/// Given that we are going to replace use's underlying value, if the use is a
1914+
/// lifetime ending use, insert an end scope scope use for the underlying value
1915+
/// before we RAUW.
1916+
static void cleanupUseOldValueBeforeRAUW(Operand *use, SILBuilder &builder,
1917+
SILLocation loc,
1918+
InstModCallbacks &callbacks) {
1919+
if (!use->isLifetimeEnding()) {
1920+
return;
1921+
}
1922+
1923+
switch (use->get().getOwnershipKind()) {
1924+
case OwnershipKind::Any:
1925+
llvm_unreachable("Invalid ownership for value");
1926+
case OwnershipKind::Owned: {
1927+
auto *dvi = builder.createDestroyValue(loc, use->get());
1928+
callbacks.createdNewInst(dvi);
1929+
return;
1930+
}
1931+
case OwnershipKind::Guaranteed: {
1932+
// Should only happen once we model destructures as true reborrows.
1933+
auto *ebi = builder.createEndBorrow(loc, use->get());
1934+
callbacks.createdNewInst(ebi);
1935+
return;
1936+
}
1937+
case OwnershipKind::None:
1938+
return;
1939+
case OwnershipKind::Unowned:
1940+
llvm_unreachable("Unowned object can never be consumed?!");
1941+
}
1942+
llvm_unreachable("Covered switch isn't covered");
1943+
}
1944+
1945+
SILBasicBlock::iterator swift::replaceSingleUse(Operand *use, SILValue newValue,
1946+
InstModCallbacks &callbacks) {
1947+
auto oldValue = use->get();
1948+
assert(oldValue != newValue && "Cannot RAUW a value with itself");
1949+
1950+
auto *user = use->getUser();
1951+
auto nextII = std::next(user->getIterator());
1952+
1953+
// If we have an end of scope marker, just return next. We are done.
1954+
if (isEndOfScopeMarker(user)) {
1955+
return nextII;
1956+
}
1957+
1958+
// Otherwise, first insert clean up our use's value if we need to and then set
1959+
// use to have a new value.
1960+
SILBuilderWithScope builder(user);
1961+
cleanupUseOldValueBeforeRAUW(use, builder, user->getLoc(), callbacks);
1962+
callbacks.setUseValue(use, newValue);
1963+
1964+
return nextII;
1965+
}

0 commit comments

Comments
 (0)