Skip to content

Commit 619b4cd

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 escaped base values. 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 b284955 commit 619b4cd

File tree

4 files changed

+218
-123
lines changed

4 files changed

+218
-123
lines changed

include/swift/SIL/SILInstruction.h

Lines changed: 40 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,9 @@ 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
724+
isIdenticalTo(const SILInstruction *RHS,
725+
llvm::function_ref<bool(SILValue, SILValue)> opEqual) const {
725726
// Quick check if both instructions have the same kind, number of operands,
726727
// and types. This should filter out most cases.
727728
if (getKind() != RHS->getKind() ||
@@ -742,6 +743,29 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
742743
return hasIdenticalState(RHS);
743744
}
744745

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

973997
struct SILInstruction::OperandToTransformedValue {
974998
const SILInstruction &i;
975-
std::function<SILValue(SILValue)> transformFn;
999+
std::function<SILValue(const Operand *)> transformFn;
9761000
bool skipTypeDependentOps;
9771001

978-
OperandToTransformedValue(const SILInstruction &i,
979-
std::function<SILValue(SILValue)> transformFn,
980-
bool skipTypeDependentOps)
1002+
OperandToTransformedValue(
1003+
const SILInstruction &i,
1004+
std::function<SILValue(const Operand *)> transformFn,
1005+
bool skipTypeDependentOps)
9811006
: i(i), transformFn(transformFn),
9821007
skipTypeDependentOps(skipTypeDependentOps) {}
9831008

9841009
Optional<SILValue> operator()(const Operand &use) const {
9851010
if (skipTypeDependentOps && i.isTypeDependentOperand(use))
9861011
return None;
987-
return transformFn(use.get());
1012+
return transformFn(&use);
9881013
}
9891014
};
9901015

@@ -1005,10 +1030,9 @@ SILInstruction::getNonTypeDependentOperandValues() const
10051030
NonTypeDependentOperandToValue(*this));
10061031
}
10071032

1008-
inline auto
1009-
SILInstruction::getOperandValues(std::function<SILValue(SILValue)> transformFn,
1010-
bool skipTypeDependentOperands) const
1011-
-> TransformedOperandValueRange {
1033+
inline auto SILInstruction::getOperandValues(
1034+
std::function<SILValue(const Operand *)> transformFn,
1035+
bool skipTypeDependentOperands) const -> TransformedOperandValueRange {
10121036
return TransformedOperandValueRange(
10131037
getAllOperands(),
10141038
OperandToTransformedValue(*this, transformFn, skipTypeDependentOperands));
@@ -6539,7 +6563,8 @@ class SelectEnumInstBase
65396563

65406564
SILValue getOperand() const { return getAllOperands()[0].get(); }
65416565
SILValue getEnumOperand() const { return getOperand(); }
6542-
6566+
const Operand &getEnumOperandRef() const { return getAllOperands()[0]; }
6567+
65436568
std::pair<EnumElementDecl*, SILValue>
65446569
getCase(unsigned i) const {
65456570
return std::make_pair(getEnumElementDeclStorage()[i],
@@ -8717,6 +8742,8 @@ class IndexingInst : public SingleValueInstruction {
87178742
ArrayRef<Operand> getAllOperands() const { return Operands.asArray(); }
87188743
MutableArrayRef<Operand> getAllOperands() { return Operands.asArray(); }
87198744

8745+
const Operand &getBaseOperandRef() const { return getAllOperands()[Base]; }
8746+
87208747
DEFINE_ABSTRACT_SINGLE_VALUE_INST_BOILERPLATE(IndexingInst)
87218748
};
87228749

0 commit comments

Comments
 (0)