Skip to content

Commit 3cbf31c

Browse files
authored
Merge pull request #35677 from atrick/add-phioperand
Add PhiOperand and PhiValue types.
2 parents a6e0050 + b3e76ae commit 3cbf31c

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)