Skip to content

Commit 55e0523

Browse files
committed
Prepare replaceAllUses[AndErase]() API support for terminators
Setup the API for use with SimplifyCFG first, so the OSSA RAUW utility can be redesigned around it. The functionality is disabled because it won't be testable until that's all in place.
1 parent 1f94525 commit 55e0523

File tree

3 files changed

+87
-9
lines changed

3 files changed

+87
-9
lines changed

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,13 +647,35 @@ FullApplySite cloneFullApplySiteReplacingCallee(FullApplySite applySite,
647647
SILValue newCallee,
648648
SILBuilderContext &builderCtx);
649649

650+
/// Replace all uses of \p oldValue with \p newValue, notifying the callbacks
651+
/// of new uses and when end-of-scope instructions are deleted.
652+
SILBasicBlock::iterator replaceAllUses(SILValue oldValue, SILValue newValue,
653+
SILBasicBlock::iterator nextii,
654+
InstModCallbacks &callbacks);
655+
650656
/// This is a low level routine that makes all uses of \p svi uses of \p
651657
/// newValue (ignoring end scope markers) and then deletes \p svi and all end
652658
/// scope markers. Then returns the next inst to process.
653659
SILBasicBlock::iterator replaceAllUsesAndErase(SingleValueInstruction *svi,
654660
SILValue newValue,
655661
InstModCallbacks &callbacks);
656662

663+
/// Replace all uses of \p oldValue with \p newValue, delete the instruction
664+
/// that defines \p oldValue, and notify the callbacks of new uses and when
665+
/// the defining instruction and its end-of-scope instructions are deleted.
666+
///
667+
/// Precondition: \p oldValue must be a SingleValueInstruction or a terminator
668+
/// result. \p oldValue must be the only result with remaining uses. For
669+
/// terminators with multiple results, remove all other results for, e.g. via
670+
/// replaceAllUsesWithUndef().
671+
///
672+
/// If \p oldValue is a terminator result, a new branch instruction is inserted
673+
/// in place of the old terminator and all basic block successors become
674+
/// unreachable except for the successor containing the replaced result.
675+
SILBasicBlock::iterator replaceAllUsesAndErase(SILValue oldValue,
676+
SILValue newValue,
677+
InstModCallbacks &callbacks);
678+
657679
/// This API is equivalent to performing \p use->set(\p newValue) except that:
658680
///
659681
/// 1. If the user of \p use is an end scope, this API no-opts. This API is only

lib/SILOptimizer/Transforms/SimplifyCFG.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4018,6 +4018,8 @@ bool SimplifyCFG::simplifyArgument(SILBasicBlock *BB, unsigned i) {
40184018
return true;
40194019
}
40204020

4021+
// OWNERSHIP NOTE: This is always safe for guaranteed and owned arguments since
4022+
// in both cases the phi will consume its input.
40214023
static void tryToReplaceArgWithIncomingValue(SILBasicBlock *BB, unsigned i,
40224024
DominanceInfo *DT) {
40234025
auto *A = BB->getArgument(i);

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1925,15 +1925,19 @@ swift::cloneFullApplySiteReplacingCallee(FullApplySite applySite,
19251925
llvm_unreachable("Unhandled case?!");
19261926
}
19271927

1928-
SILBasicBlock::iterator
1929-
swift::replaceAllUsesAndErase(SingleValueInstruction *svi, SILValue newValue,
1930-
InstModCallbacks &callbacks) {
1931-
assert(svi != newValue && "Cannot RAUW a value with itself");
1932-
SILBasicBlock::iterator nextii = std::next(svi->getIterator());
1933-
1934-
// Only SingleValueInstructions are currently simplified.
1935-
while (!svi->use_empty()) {
1936-
Operand *use = *svi->use_begin();
1928+
// FIXME: For any situation where this may be called on an unbounded number of
1929+
// uses, it should perform a single callback invocation to notify the client
1930+
// that newValue has new uses rather than a callback for every new use.
1931+
//
1932+
// FIXME: This should almost certainly replace end_lifetime uses rather than
1933+
// deleting them.
1934+
SILBasicBlock::iterator swift::replaceAllUses(SILValue oldValue,
1935+
SILValue newValue,
1936+
SILBasicBlock::iterator nextii,
1937+
InstModCallbacks &callbacks) {
1938+
assert(oldValue != newValue && "Cannot RAUW a value with itself");
1939+
while (!oldValue->use_empty()) {
1940+
Operand *use = *oldValue->use_begin();
19371941
SILInstruction *user = use->getUser();
19381942
// Erase the end of scope marker.
19391943
if (isEndOfScopeMarker(user)) {
@@ -1944,12 +1948,62 @@ swift::replaceAllUsesAndErase(SingleValueInstruction *svi, SILValue newValue,
19441948
}
19451949
callbacks.setUseValue(use, newValue);
19461950
}
1951+
return nextii;
1952+
}
1953+
1954+
SILBasicBlock::iterator
1955+
swift::replaceAllUsesAndErase(SingleValueInstruction *svi, SILValue newValue,
1956+
InstModCallbacks &callbacks) {
1957+
SILBasicBlock::iterator nextii = replaceAllUses(
1958+
svi, newValue, std::next(svi->getIterator()), callbacks);
19471959

19481960
callbacks.deleteInst(svi);
19491961

19501962
return nextii;
19511963
}
19521964

1965+
SILBasicBlock::iterator
1966+
swift::replaceAllUsesAndErase(SILValue oldValue, SILValue newValue,
1967+
InstModCallbacks &callbacks) {
1968+
auto *blockArg = dyn_cast<SILPhiArgument>(oldValue);
1969+
if (!blockArg) {
1970+
// SingleValueInstruction SSA replacement.
1971+
return replaceAllUsesAndErase(cast<SingleValueInstruction>(oldValue),
1972+
newValue, callbacks);
1973+
}
1974+
llvm_unreachable("Untested");
1975+
#if 0 // FIXME: to be enabled in a following commit
1976+
TermInst *oldTerm = blockArg->getTerminatorForResult();
1977+
assert(oldTerm && "can only replace and erase terminators, not phis");
1978+
1979+
// Before:
1980+
// oldTerm bb1, bb2
1981+
// bb1(%oldValue):
1982+
// use %oldValue
1983+
// bb2:
1984+
//
1985+
// After:
1986+
// br bb1
1987+
// bb1:
1988+
// use %newValue
1989+
// bb2:
1990+
1991+
auto nextii = replaceAllUses(blockArg, newValue,
1992+
oldTerm->getParent()->end(), callbacks);
1993+
// Now that oldValue is replaced, the terminator should have no uses
1994+
// left. The caller should have removed uses from other results.
1995+
for (auto *succBB : oldTerm->getSuccessorBlocks()) {
1996+
assert(succBB->getNumArguments() == 1 && "expected terminator result");
1997+
succBB->eraseArgument(0);
1998+
}
1999+
auto *newBr = SILBuilderWithScope(oldTerm).createBranch(
2000+
oldTerm->getLoc(), blockArg->getParent());
2001+
callbacks.createdNewInst(newBr);
2002+
callbacks.deleteInst(oldTerm);
2003+
return nextii;
2004+
#endif
2005+
}
2006+
19532007
/// Given that we are going to replace use's underlying value, if the use is a
19542008
/// lifetime ending use, insert an end scope scope use for the underlying value
19552009
/// before we RAUW.

0 commit comments

Comments
 (0)