Skip to content

Commit 7880a2f

Browse files
authored
Merge pull request #36152 from atrick/fix-rauwclone
OSSA: Rewrite address cloning code to fix issues and fix an infinite loop in the ownership verifier.
2 parents 5e16e75 + 66752e9 commit 7880a2f

File tree

7 files changed

+204
-120
lines changed

7 files changed

+204
-120
lines changed

include/swift/SIL/MemAccessUtils.h

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,9 @@ inline Operand *getAccessProjectionOperand(SingleValueInstruction *svi) {
12831283
/// address must be at operand(0).
12841284
///
12851285
/// Some of these casts, such as address_to_pointer, may also occur inside of a
1286-
/// formal access. TODO: Add stricter structural guarantee such that these never
1286+
/// formal access.
1287+
///
1288+
/// TODO: Add stricter structural guarantee such that these never
12871289
/// occur within an access. It's important to be able to get the accessed
12881290
/// address without looking though type casts or pointer_to_address [strict],
12891291
/// which we can't do if those operations are behind access projections.
@@ -1497,35 +1499,54 @@ Result AccessUseDefChainVisitor<Impl, Result>::visit(SILValue sourceAddr) {
14971499

14981500
namespace swift {
14991501

1500-
/// Clone all projections and casts on the access use-def chain until either the
1501-
/// specified predicate is true or the access base is reached.
1502+
/// Clone all projections and casts on the access use-def chain until the
1503+
/// checkBase predicate returns a valid base.
15021504
///
1503-
/// This will not clone ref_element_addr or ref_tail_addr because those aren't
1504-
/// part of the access chain.
1505-
template <typename UnaryPredicate>
1505+
/// See comments on the cloneUseDefChain() API.
1506+
template <typename CheckBase>
15061507
class AccessUseDefChainCloner
1507-
: public AccessUseDefChainVisitor<AccessUseDefChainCloner<UnaryPredicate>,
1508+
: public AccessUseDefChainVisitor<AccessUseDefChainCloner<CheckBase>,
15081509
SILValue> {
1509-
UnaryPredicate predicate;
1510+
CheckBase checkBase;
15101511
SILInstruction *insertionPoint;
1512+
SILValue placeHolder = SILValue();
15111513

15121514
public:
1513-
AccessUseDefChainCloner(UnaryPredicate predicate,
1514-
SILInstruction *insertionPoint)
1515-
: predicate(predicate), insertionPoint(insertionPoint) {}
1515+
AccessUseDefChainCloner(CheckBase checkBase, SILInstruction *insertionPoint)
1516+
: checkBase(checkBase), insertionPoint(insertionPoint) {}
15161517

1517-
// Recursive main entry point
1518+
// Main entry point
15181519
SILValue cloneUseDefChain(SILValue addr) {
1519-
if (!predicate(addr))
1520-
return addr;
1520+
placeHolder = SILValue();
1521+
return cloneRecursive(addr);
1522+
}
1523+
1524+
// Secondary entry point to check that cloning will succeed.
1525+
bool canCloneUseDefChain(SILValue addr) {
1526+
// Use any valid address as a placeholder. It is innaccessible.
1527+
placeHolder = addr;
1528+
return cloneRecursive(addr);
1529+
}
1530+
1531+
SILValue cloneRecursive(SILValue addr) {
1532+
if (SILValue base = checkBase(addr))
1533+
return base;
15211534

15221535
return this->visit(addr);
15231536
}
15241537

15251538
// Recursively clone an address on the use-def chain.
1526-
SingleValueInstruction *cloneProjection(SingleValueInstruction *projectedAddr,
1527-
Operand *sourceOper) {
1528-
SILValue projectedSource = cloneUseDefChain(sourceOper->get());
1539+
//
1540+
// Helper for cloneUseDefChain.
1541+
SILValue cloneProjection(SingleValueInstruction *projectedAddr,
1542+
Operand *sourceOper) {
1543+
SILValue projectedSource = cloneRecursive(sourceOper->get());
1544+
if (!projectedSource)
1545+
return nullptr;
1546+
1547+
if (placeHolder)
1548+
return placeHolder;
1549+
15291550
SILInstruction *clone = projectedAddr->clone(insertionPoint);
15301551
clone->setOperand(sourceOper->getOperandNumber(), projectedSource);
15311552
return cast<SingleValueInstruction>(clone);
@@ -1549,6 +1570,11 @@ class AccessUseDefChainCloner
15491570
}
15501571

15511572
SILValue visitStorageCast(SingleValueInstruction *cast, Operand *sourceOper) {
1573+
// The cloner does not currently know how to create compensating
1574+
// end_borrows or fix mark_dependence operands.
1575+
if (isa<BeginBorrowInst>(cast) || isa<MarkDependenceInst>(cast))
1576+
return SILValue();
1577+
15521578
return cloneProjection(cast, sourceOper);
15531579
}
15541580

@@ -1558,14 +1584,37 @@ class AccessUseDefChainCloner
15581584
}
15591585
};
15601586

1561-
template <typename UnaryPredicate>
1587+
/// Clone all projections and casts on the access use-def chain until the
1588+
/// checkBase predicate returns a valid base.
1589+
///
1590+
/// This will not clone ref_element_addr or ref_tail_addr because those aren't
1591+
/// part of the access chain.
1592+
///
1593+
/// CheckBase is a unary predicate that takes the next source address and either
1594+
/// returns a valid SILValue to use as the base of the cloned access path, or an
1595+
/// invalid SILValue to continue cloning.
1596+
///
1597+
/// CheckBase must return a valid SILValue either before attempting to clone the
1598+
/// access base. The most basic valid predicate is:
1599+
///
1600+
/// auto checkBase = [&](SILValue srcAddr) {
1601+
/// return (srcAddr == accessBase) ? srcAddr : SILValue();
1602+
/// }
1603+
template <typename CheckBase>
15621604
SILValue cloneUseDefChain(SILValue addr, SILInstruction *insertionPoint,
1563-
UnaryPredicate shouldFollowUse) {
1564-
return AccessUseDefChainCloner<UnaryPredicate>(shouldFollowUse,
1565-
insertionPoint)
1605+
CheckBase checkBase) {
1606+
return AccessUseDefChainCloner<CheckBase>(checkBase, insertionPoint)
15661607
.cloneUseDefChain(addr);
15671608
}
15681609

1610+
/// Analog to cloneUseDefChain to check validity. begin_borrow and
1611+
/// mark_dependence currently cannot be cloned.
1612+
template <typename CheckBase>
1613+
bool canCloneUseDefChain(SILValue addr, CheckBase checkBase) {
1614+
return AccessUseDefChainCloner<CheckBase>(checkBase, nullptr)
1615+
.canCloneUseDefChain(addr);
1616+
}
1617+
15691618
} // end namespace swift
15701619

15711620
//===----------------------------------------------------------------------===//

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ bool InteriorPointerOperand::findTransitiveUsesForAddress(
768768
}
769769

770770
// If we are the value use, look through it.
771-
llvm::copy(mdi->getValue()->getUses(), std::back_inserter(worklist));
771+
llvm::copy(mdi->getUses(), std::back_inserter(worklist));
772772
continue;
773773
}
774774

lib/SILOptimizer/LoopTransforms/LICM.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,11 +1340,21 @@ hoistLoadsAndStores(AccessPath accessPath, SILLoop *loop) {
13401340
}
13411341
}
13421342
assert(storeAddr && "hoistLoadsAndStores requires a store in the loop");
1343-
SILValue initialAddr = cloneUseDefChain(
1344-
storeAddr, preheader->getTerminator(), [&](SILValue srcAddr) {
1345-
// Clone projections until the address dominates preheader.
1346-
return !DomTree->dominates(srcAddr->getParentBlock(), preheader);
1347-
});
1343+
auto checkBase = [&](SILValue srcAddr) {
1344+
// Clone projections until the address dominates preheader.
1345+
if (DomTree->dominates(srcAddr->getParentBlock(), preheader))
1346+
return srcAddr;
1347+
1348+
// return an invalid SILValue to continue cloning.
1349+
return SILValue();
1350+
};
1351+
SILValue initialAddr =
1352+
cloneUseDefChain(storeAddr, preheader->getTerminator(), checkBase);
1353+
// cloneUseDefChain may currently fail if a begin_borrow or mark_dependence is
1354+
// in the chain.
1355+
if (!initialAddr)
1356+
return;
1357+
13481358
LoadInst *initialLoad =
13491359
B.createLoad(preheader->getTerminator()->getLoc(), initialAddr,
13501360
LoadOwnershipQualifier::Unqualified);

lib/SILOptimizer/SILCombiner/SILCombine.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ static llvm::cl::opt<bool> EnableSinkingOwnedForwardingInstToUses(
4949
llvm::cl::desc("Enable sinking of owened forwarding insts"),
5050
llvm::cl::init(true), llvm::cl::Hidden);
5151

52+
// Allow disabling general optimization for targetted unit tests.
53+
static llvm::cl::opt<bool> EnableSILCombineCanonicalize(
54+
"sil-combine-canonicalize",
55+
llvm::cl::desc("Canonicalization during sil-combine"), llvm::cl::init(true),
56+
llvm::cl::Hidden);
57+
5258
//===----------------------------------------------------------------------===//
5359
// Utility Methods
5460
//===----------------------------------------------------------------------===//
@@ -141,6 +147,9 @@ class SILCombineCanonicalize final : CanonicalizeInstruction {
141147
}
142148

143149
bool tryCanonicalize(SILInstruction *inst) {
150+
if (!EnableSILCombineCanonicalize)
151+
return false;
152+
144153
changed = false;
145154
canonicalize(inst);
146155
return changed;

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 20 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -788,89 +788,6 @@ SILBasicBlock::iterator OwnershipRAUWUtility::perform() {
788788
// Interior Pointer Operand Rebasing
789789
//===----------------------------------------------------------------------===//
790790

791-
namespace {
792-
793-
/// Clone all projections and casts on the access use-def chain until either the
794-
/// specified predicate is true or the access base is reached.
795-
///
796-
/// This will not clone ref_element_addr or ref_tail_addr because those aren't
797-
/// part of the access chain.
798-
class InteriorPointerAddressRebaseUseDefChainCloner
799-
: public AccessUseDefChainVisitor<
800-
InteriorPointerAddressRebaseUseDefChainCloner, SILValue> {
801-
SILValue oldAddressValue;
802-
SingleValueInstruction *oldIntPtr;
803-
SingleValueInstruction *newIntPtr;
804-
SILInstruction *insertPt;
805-
806-
public:
807-
InteriorPointerAddressRebaseUseDefChainCloner(
808-
SILValue oldAddressValue, SingleValueInstruction *oldIntPtr,
809-
SingleValueInstruction *newIntPtr, SILInstruction *insertPt)
810-
: oldAddressValue(oldAddressValue), oldIntPtr(oldIntPtr),
811-
newIntPtr(newIntPtr), insertPt(insertPt) {}
812-
813-
// Recursive main entry point
814-
SILValue cloneUseDefChain(SILValue currentOldAddr) {
815-
// If we have finally hit oldIntPtr, we are done.
816-
if (currentOldAddr == oldIntPtr)
817-
return currentOldAddr;
818-
return this->visit(currentOldAddr);
819-
}
820-
821-
// Recursively clone an address on the use-def chain.
822-
SingleValueInstruction *cloneProjection(SingleValueInstruction *projectedAddr,
823-
Operand *sourceOper) {
824-
SILValue sourceOperVal = sourceOper->get();
825-
SILValue projectedSource = cloneUseDefChain(sourceOperVal);
826-
// If we hit the end of our chain, then make newIntPtr the operand so that
827-
// we have successfully rebased.
828-
if (sourceOperVal == projectedSource)
829-
projectedSource = newIntPtr;
830-
SILInstruction *clone = projectedAddr->clone(insertPt);
831-
clone->setOperand(sourceOper->getOperandNumber(), projectedSource);
832-
return cast<SingleValueInstruction>(clone);
833-
}
834-
835-
SILValue visitBase(SILValue base, AccessedStorage::Kind kind) {
836-
assert(false && "access base cannot be cloned");
837-
return SILValue();
838-
}
839-
840-
SILValue visitNonAccess(SILValue base) {
841-
assert(false && "unknown address root cannot be cloned");
842-
return SILValue();
843-
}
844-
845-
SILValue visitPhi(SILPhiArgument *phi) {
846-
assert(false && "unexpected phi on access path");
847-
return SILValue();
848-
}
849-
850-
SILValue visitStorageCast(SingleValueInstruction *cast, Operand *sourceOper) {
851-
// We are ok with cloning storage casts.
852-
return cloneProjection(cast, sourceOper);
853-
}
854-
855-
SILValue visitAccessProjection(SingleValueInstruction *projectedAddr,
856-
Operand *sourceOper) {
857-
return cloneProjection(projectedAddr, sourceOper);
858-
}
859-
};
860-
861-
} // namespace
862-
863-
/// \p oldAddressValue is an address rooted in \p oldIntPtr. Clone the use-def
864-
/// chain from \p oldAddressValue to \p oldIntPtr, but starting from \p
865-
/// newAddressValue.
866-
static SILValue cloneInteriorProjectionUseDefChain(
867-
SILValue oldAddressValue, SingleValueInstruction *oldIntPtr,
868-
SingleValueInstruction *newIntPtr, SILInstruction *insertPt) {
869-
InteriorPointerAddressRebaseUseDefChainCloner cloner(
870-
oldAddressValue, oldIntPtr, newIntPtr, insertPt);
871-
return cloner.cloneUseDefChain(oldAddressValue);
872-
}
873-
874791
SILBasicBlock::iterator
875792
OwnershipRAUWHelper::replaceAddressUses(SingleValueInstruction *oldValue,
876793
SILValue newValue) {
@@ -907,19 +824,18 @@ OwnershipRAUWHelper::replaceAddressUses(SingleValueInstruction *oldValue,
907824
// the access path from newValue to intPtr but upon newIntPtr. Then we make it
908825
// use newIntPtr.
909826
auto *intPtrUser = cast<SingleValueInstruction>(intPtr->getUser());
910-
SILValue initialAddr = cloneInteriorProjectionUseDefChain(
911-
newValue /*address we originally wanted to replace*/,
912-
intPtrUser /*the interior pointer of that value*/,
913-
newIntPtrUser /*the interior pointer we need to recreate the chain upon*/,
914-
oldValue /*insert point*/);
915827

916-
// If we got back newValue, then we need to set initialAddr to be int ptr
917-
// user.
918-
if (initialAddr == newValue)
919-
initialAddr = newIntPtrUser;
828+
// This cloner invocation must match the canCloneUseDefChain check in the
829+
// constructor.
830+
auto checkBase = [&](SILValue srcAddr) {
831+
return (srcAddr == intPtrUser) ? SILValue(newIntPtrUser) : SILValue();
832+
};
833+
SILValue clonedAddr =
834+
cloneUseDefChain(newValue, /*insetPt*/ oldValue, checkBase);
835+
assert(clonedAddr != newValue && "expect at least the base to be replaced");
920836

921837
// Now that we have an addr that is setup appropriately, RAUW!
922-
return replaceAllUsesAndErase(oldValue, initialAddr, ctx->callbacks);
838+
return replaceAllUsesAndErase(oldValue, clonedAddr, ctx->callbacks);
923839
}
924840

925841
//===----------------------------------------------------------------------===//
@@ -1015,6 +931,17 @@ OwnershipRAUWHelper::OwnershipRAUWHelper(OwnershipFixupContext &inputCtx,
1015931
return;
1016932
}
1017933

934+
// This cloner check must match the later cloner invocation in
935+
// replaceAddressUses()
936+
auto *intPtrUser = cast<SingleValueInstruction>(intPtr->getUser());
937+
auto checkBase = [&](SILValue srcAddr) {
938+
return (srcAddr == intPtrUser) ? SILValue(intPtrUser) : SILValue();
939+
};
940+
if (!canCloneUseDefChain(newValue, checkBase)) {
941+
ctx = nullptr;
942+
return;
943+
}
944+
1018945
// For now, just gather up uses
1019946
auto &oldValueUses = ctx->extraAddressFixupInfo.allAddressUsesFromOldValue;
1020947
if (InteriorPointerOperand::findTransitiveUsesForAddress(oldValue,

0 commit comments

Comments
 (0)