Skip to content

Commit b3e76ae

Browse files
committed
Add PhiOperand and PhiValue types.
This is necessitated by the SILArgument representation. It has the tragic property that adding unrelated phis invalidates existing phis. Therefore, the optimizer can't do book-keeping of phi values by refering directly to SILValues or Operands. Instead, it must only refer to SILBasicBlocks and argument indices.
1 parent 2095c0c commit b3e76ae

File tree

3 files changed

+143
-10
lines changed

3 files changed

+143
-10
lines changed

include/swift/SIL/SILBasicBlock.h

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,4 +488,141 @@ struct ilist_traits<::swift::SILBasicBlock>
488488

489489
} // end llvm namespace
490490

491+
//===----------------------------------------------------------------------===//
492+
// PhiOperand & PhiValue
493+
//===----------------------------------------------------------------------===//
494+
495+
namespace swift {
496+
497+
/// Represent a phi argument without storing pointers to branches or their
498+
/// operands which are invalidated by adding new, unrelated phi values. Because
499+
/// this only stores a block pointer, it remains valid as long as the CFG is
500+
/// immutable and the index of the phi value does not change.
501+
///
502+
/// Note: this should not be confused with SILPhiArgument which should be
503+
/// renamed to SILPhiValue and only used for actual phis.
504+
///
505+
/// Warning: This is invalid for CondBranchInst arguments. Clients assume that
506+
/// any instructions inserted at the phi argument is post-dominated by that phi
507+
/// argument. This warning can be removed once the SILVerifier fully prohibits
508+
/// CondBranchInst arguments at all SIL stages.
509+
struct PhiOperand {
510+
SILBasicBlock *predBlock = nullptr;
511+
unsigned argIndex = 0;
512+
513+
PhiOperand() = default;
514+
515+
PhiOperand(Operand *operand) {
516+
auto *branch = dyn_cast<BranchInst>(operand->getUser());
517+
if (!branch)
518+
return;
519+
520+
predBlock = branch->getParent();
521+
argIndex = operand->getOperandNumber();
522+
}
523+
524+
explicit operator bool() const { return predBlock != nullptr; }
525+
526+
bool operator==(PhiOperand other) const {
527+
return predBlock == other.predBlock && argIndex == other.argIndex;
528+
}
529+
530+
bool operator!=(PhiOperand other) const { return !(*this == other); }
531+
532+
BranchInst *getBranch() const {
533+
return cast<BranchInst>(predBlock->getTerminator());
534+
}
535+
536+
Operand *getOperand() const {
537+
return &getBranch()->getAllOperands()[argIndex];
538+
}
539+
540+
SILPhiArgument *getValue() const {
541+
auto *branch = cast<BranchInst>(predBlock->getTerminator());
542+
return cast<SILPhiArgument>(branch->getDestBB()->getArgument(argIndex));
543+
}
544+
545+
SILValue getSource() const {
546+
return getOperand()->get();
547+
}
548+
549+
operator Operand *() const { return getOperand(); }
550+
Operand *operator*() const { return getOperand(); }
551+
Operand *operator->() const { return getOperand(); }
552+
};
553+
554+
/// Represent a phi value without referencing the SILValue, which is invalidated
555+
/// by adding new, unrelated phi values. Because this only stores a block
556+
/// pointer, it remains valid as long as the CFG is immutable and the index of
557+
/// the phi value does not change.
558+
struct PhiValue {
559+
SILBasicBlock *phiBlock = nullptr;
560+
unsigned argIndex = 0;
561+
562+
PhiValue() = default;
563+
564+
PhiValue(SILValue value) {
565+
auto *blockArg = dyn_cast<SILPhiArgument>(value);
566+
if (!blockArg || !blockArg->isPhiArgument())
567+
return;
568+
569+
phiBlock = blockArg->getParent();
570+
argIndex = blockArg->getIndex();
571+
}
572+
573+
explicit operator bool() const { return phiBlock != nullptr; }
574+
575+
bool operator==(PhiValue other) const {
576+
return phiBlock == other.phiBlock && argIndex == other.argIndex;
577+
}
578+
579+
bool operator!=(PhiValue other) const { return !(*this == other); }
580+
581+
SILPhiArgument *getValue() const {
582+
return cast<SILPhiArgument>(phiBlock->getArgument(argIndex));
583+
}
584+
585+
operator SILValue() const { return getValue(); }
586+
SILValue operator*() const { return getValue(); }
587+
SILValue operator->() const { return getValue(); }
588+
};
589+
590+
} // namespace swift
591+
592+
namespace llvm {
593+
594+
template <> struct DenseMapInfo<swift::PhiOperand> {
595+
static swift::PhiOperand getEmptyKey() { return swift::PhiOperand(); }
596+
static swift::PhiOperand getTombstoneKey() {
597+
swift::PhiOperand phiOper;
598+
phiOper.predBlock =
599+
llvm::DenseMapInfo<swift::SILBasicBlock *>::getTombstoneKey();
600+
return phiOper;
601+
}
602+
static unsigned getHashValue(swift::PhiOperand phiOper) {
603+
return llvm::hash_combine(phiOper.predBlock, phiOper.argIndex);
604+
}
605+
static bool isEqual(swift::PhiOperand lhs, swift::PhiOperand rhs) {
606+
return lhs == rhs;
607+
}
608+
};
609+
610+
template <> struct DenseMapInfo<swift::PhiValue> {
611+
static swift::PhiValue getEmptyKey() { return swift::PhiValue(); }
612+
static swift::PhiValue getTombstoneKey() {
613+
swift::PhiValue phiValue;
614+
phiValue.phiBlock =
615+
llvm::DenseMapInfo<swift::SILBasicBlock *>::getTombstoneKey();
616+
return phiValue;
617+
}
618+
static unsigned getHashValue(swift::PhiValue phiValue) {
619+
return llvm::hash_combine(phiValue.phiBlock, phiValue.argIndex);
620+
}
621+
static bool isEqual(swift::PhiValue lhs, swift::PhiValue rhs) {
622+
return lhs == rhs;
623+
}
624+
};
625+
626+
} // end namespace llvm
627+
491628
#endif

include/swift/SILOptimizer/Utils/OwnershipOptUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ struct OwnershipFixupContext {
4040
JointPostDominanceSetComputer &jointPostDomSetComputer;
4141

4242
SmallVector<Operand *, 8> transitiveBorrowedUses;
43-
SmallVector<std::pair<SILBasicBlock *, unsigned>, 8> recursiveReborrows;
43+
SmallVector<PhiOperand, 8> recursiveReborrows;
4444

4545
/// Extra state initialized by OwnershipRAUWFixupHelper::get() that we use
4646
/// when RAUWing addresses. This ensures we do not need to recompute this

lib/SILOptimizer/Utils/OwnershipOptUtils.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,7 @@ static bool canFixUpOwnershipForRAUW(SILValue oldValue, SILValue newValue,
180180
// TODO: if non-phi reborrows even exist, handle them using a separate
181181
// SILValue list since we don't want to refer directly to phi SILValues.
182182
reborrows.insert(borrowingOper.getBorrowIntroducingUserResult().value);
183-
auto *branch = endScope->getUser();
184-
context.recursiveReborrows.push_back(
185-
{branch->getParent(), endScope->getOperandNumber()});
183+
context.recursiveReborrows.push_back(endScope);
186184
};
187185
if (!findTransitiveGuaranteedUses(oldValue, context.transitiveBorrowedUses,
188186
visitReborrow))
@@ -452,7 +450,7 @@ OwnershipLifetimeExtender::createPlusZeroBorrow(SILValue newValue,
452450
//===----------------------------------------------------------------------===//
453451

454452
static void eliminateReborrowsOfRecursiveBorrows(
455-
ArrayRef<std::pair<SILBasicBlock *, unsigned>> transitiveReborrows,
453+
ArrayRef<PhiOperand> transitiveReborrows,
456454
SmallVectorImpl<Operand *> &usePoints, InstModCallbacks &callbacks) {
457455
SmallVector<std::pair<SILPhiArgument *, SILPhiArgument *>, 8>
458456
baseBorrowedValuePair;
@@ -462,8 +460,8 @@ static void eliminateReborrowsOfRecursiveBorrows(
462460
// edge from the base value and using that for the reborrow instead of the
463461
// actual value. We of course insert an end_borrow for our original incoming
464462
// value.
465-
auto *bi = cast<BranchInst>(it.first->getTerminator());
466-
auto &op = bi->getOperandRef(it.second);
463+
auto *bi = cast<BranchInst>(it.predBlock->getTerminator());
464+
auto &op = bi->getOperandRef(it.argIndex);
467465
BorrowingOperand borrowingOperand(&op);
468466
SILValue value = borrowingOperand->get();
469467
SILBuilderWithScope reborrowBuilder(bi);
@@ -1288,9 +1286,7 @@ OwnershipReplaceSingleUseHelper::OwnershipReplaceSingleUseHelper(
12881286
if (reborrowOperand.isReborrow()) {
12891287
// Check that the old lifetime can be extended and record the necessary
12901288
// book-keeping in the OwnershipFixupContext.
1291-
auto *branch = reborrowOperand->getUser();
1292-
ctx->recursiveReborrows.push_back(
1293-
{branch->getParent(), reborrowOperand->getOperandNumber()});
1289+
ctx->recursiveReborrows.push_back(use);
12941290
}
12951291
}
12961292
}

0 commit comments

Comments
 (0)