Skip to content

Commit 641149b

Browse files
committed
CSE: Don't look through ownership instructions for "escaped" values
CSE relies on OSSA RAUW for lifetime extension when replacing a redundant instruction. OSSA RAUW however does not handle lifetime extension for the base value of an escaped value. Values escape from ownership via pointer escape, bitwise escape, forwarding unowned operations and have none or unowned ownership. For all such values do not look through ownership instructions while determining equality. It is possible to CSE such values with equivalent operands, because the operand use guarantees lifetime of the base operand.
1 parent ea3cf9e commit 641149b

File tree

4 files changed

+163
-116
lines changed

4 files changed

+163
-116
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
643643
NonTypeDependentOperandValueRange getNonTypeDependentOperandValues() const;
644644

645645
TransformedOperandValueRange
646-
getOperandValues(std::function<SILValue(SILValue)> transformFn,
646+
getOperandValues(std::function<SILValue(const Operand *)> transformFn,
647647
bool skipTypeDependentOperands) const;
648648

649649
SILValue getOperand(unsigned Num) const {
@@ -720,8 +720,8 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
720720
/// Returns true if the given instruction is completely identical to RHS,
721721
/// using \p opEqual to compare operands.
722722
///
723-
template <typename OpCmp>
724-
bool isIdenticalTo(const SILInstruction *RHS, OpCmp &&opEqual) const {
723+
bool isIdenticalTo(const SILInstruction *RHS,
724+
std::function<bool(SILValue, SILValue)> opEqual) const {
725725
// Quick check if both instructions have the same kind, number of operands,
726726
// and types. This should filter out most cases.
727727
if (getKind() != RHS->getKind() ||
@@ -742,6 +742,29 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
742742
return hasIdenticalState(RHS);
743743
}
744744

745+
bool isIdenticalTo(
746+
const SILInstruction *RHS,
747+
std::function<bool(const Operand *, const Operand *)> opEqual) const {
748+
// Quick check if both instructions have the same kind, number of operands,
749+
// and types. This should filter out most cases.
750+
if (getKind() != RHS->getKind() ||
751+
getNumOperands() != RHS->getNumOperands()) {
752+
return false;
753+
}
754+
755+
if (!getResults().hasSameTypes(RHS->getResults()))
756+
return false;
757+
758+
// Check operands.
759+
for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
760+
if (!opEqual(&getOperandRef(i), &RHS->getOperandRef(i)))
761+
return false;
762+
763+
// Check any special state of instructions that are not represented in the
764+
// instructions operands/type.
765+
return hasIdenticalState(RHS);
766+
}
767+
745768
/// Returns true if the instruction may have side effects.
746769
///
747770
/// Instructions that store into memory or change retain counts as well as
@@ -972,19 +995,20 @@ struct SILInstruction::NonTypeDependentOperandToValue {
972995

973996
struct SILInstruction::OperandToTransformedValue {
974997
const SILInstruction &i;
975-
std::function<SILValue(SILValue)> transformFn;
998+
std::function<SILValue(const Operand *)> transformFn;
976999
bool skipTypeDependentOps;
9771000

978-
OperandToTransformedValue(const SILInstruction &i,
979-
std::function<SILValue(SILValue)> transformFn,
980-
bool skipTypeDependentOps)
1001+
OperandToTransformedValue(
1002+
const SILInstruction &i,
1003+
std::function<SILValue(const Operand *)> transformFn,
1004+
bool skipTypeDependentOps)
9811005
: i(i), transformFn(transformFn),
9821006
skipTypeDependentOps(skipTypeDependentOps) {}
9831007

9841008
Optional<SILValue> operator()(const Operand &use) const {
9851009
if (skipTypeDependentOps && i.isTypeDependentOperand(use))
9861010
return None;
987-
return transformFn(use.get());
1011+
return transformFn(&use);
9881012
}
9891013
};
9901014

@@ -1005,10 +1029,9 @@ SILInstruction::getNonTypeDependentOperandValues() const
10051029
NonTypeDependentOperandToValue(*this));
10061030
}
10071031

1008-
inline auto
1009-
SILInstruction::getOperandValues(std::function<SILValue(SILValue)> transformFn,
1010-
bool skipTypeDependentOperands) const
1011-
-> TransformedOperandValueRange {
1032+
inline auto SILInstruction::getOperandValues(
1033+
std::function<SILValue(const Operand *)> transformFn,
1034+
bool skipTypeDependentOperands) const -> TransformedOperandValueRange {
10121035
return TransformedOperandValueRange(
10131036
getAllOperands(),
10141037
OperandToTransformedValue(*this, transformFn, skipTypeDependentOperands));
@@ -6539,7 +6562,8 @@ class SelectEnumInstBase
65396562

65406563
SILValue getOperand() const { return getAllOperands()[0].get(); }
65416564
SILValue getEnumOperand() const { return getOperand(); }
6542-
6565+
const Operand &getEnumOperandRef() const { return getAllOperands()[0]; }
6566+
65436567
std::pair<EnumElementDecl*, SILValue>
65446568
getCase(unsigned i) const {
65456569
return std::make_pair(getEnumElementDeclStorage()[i],

0 commit comments

Comments
 (0)