Skip to content

Commit 85965ed

Browse files
committed
[semantic-arc] Optimize more lifetime joining when a copy_value, destroy_value are in the same block.
Specifically the optimization that is being performed here is the elimination of lifetimes that hand off ownership in between two regions of code. Example: ``` %1 = copy_value %0 ... destroy_value %0 ... apply %consumingUser(%1) ``` We really want to handle this case since it is a natural thing that comes up in programs and will let me eliminate the *evil* usage of emitDestroyValueOperation in TypeLowering without needing to modify huge amounts of tests.
1 parent 63e43b6 commit 85965ed

File tree

6 files changed

+1184
-136
lines changed

6 files changed

+1184
-136
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,34 @@ class ForwardingOperand {
7575
public:
7676
static Optional<ForwardingOperand> get(Operand *use);
7777

78+
Operand *getUse() const { return use; }
7879
ValueOwnershipKind getOwnershipKind() const;
7980
void setOwnershipKind(ValueOwnershipKind newKind) const;
8081
void replaceOwnershipKind(ValueOwnershipKind oldKind,
8182
ValueOwnershipKind newKind) const;
8283

83-
OwnershipForwardingInst *getUser() const {
84+
const OwnershipForwardingInst *operator->() const {
8485
return cast<OwnershipForwardingInst>(use->getUser());
8586
}
87+
OwnershipForwardingInst *operator->() {
88+
return cast<OwnershipForwardingInst>(use->getUser());
89+
}
90+
const OwnershipForwardingInst &operator*() const {
91+
return *cast<OwnershipForwardingInst>(use->getUser());
92+
}
93+
OwnershipForwardingInst &operator*() {
94+
return *cast<OwnershipForwardingInst>(use->getUser());
95+
}
96+
97+
/// Call \p visitor with each value that contains the final forwarded
98+
/// ownership of. E.x.: result of a unchecked_ref_cast, phi arguments of a
99+
/// switch_enum.
100+
bool visitForwardedValues(function_ref<bool(SILValue)> visitor);
101+
102+
/// If statically this forwarded operand has a single forwarded value that the
103+
/// operand forwards ownership into, return that value. Return false
104+
/// otherwise.
105+
SILValue getSingleForwardedValue() const;
86106
};
87107

88108
/// Returns true if the instruction is a 'reborrow'.

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ Optional<ForwardingOperand> ForwardingOperand::get(Operand *use) {
847847
}
848848

849849
ValueOwnershipKind ForwardingOperand::getOwnershipKind() const {
850-
return getUser()->getOwnershipKind();
850+
return (*this)->getOwnershipKind();
851851
}
852852

853853
void ForwardingOperand::setOwnershipKind(ValueOwnershipKind newKind) const {
@@ -973,3 +973,45 @@ void ForwardingOperand::replaceOwnershipKind(ValueOwnershipKind oldKind,
973973
}
974974
llvm_unreachable("Out of sync with ForwardingOperand::get?!");
975975
}
976+
977+
SILValue ForwardingOperand::getSingleForwardedValue() const {
978+
assert(isGuaranteedForwardingUse(use));
979+
if (auto *svi = dyn_cast<SingleValueInstruction>(use->getUser()))
980+
return svi;
981+
return SILValue();
982+
}
983+
984+
bool ForwardingOperand::visitForwardedValues(
985+
function_ref<bool(SILValue)> visitor) {
986+
auto *user = use->getUser();
987+
988+
assert(isGuaranteedForwardingUse(use));
989+
990+
// See if we have a single value instruction... if we do that is always the
991+
// transitive result.
992+
if (auto *svi = dyn_cast<SingleValueInstruction>(user)) {
993+
return visitor(svi);
994+
}
995+
996+
if (auto *mvri = dyn_cast<MultipleValueInstruction>(user)) {
997+
return llvm::all_of(mvri->getResults(), [&](SILValue value) {
998+
if (value.getOwnershipKind() == OwnershipKind::None)
999+
return true;
1000+
return visitor(value);
1001+
});
1002+
}
1003+
1004+
// This is an instruction like switch_enum and checked_cast_br that are
1005+
// "transforming terminators"... We know that this means that we should at
1006+
// most have a single phi argument.
1007+
auto *ti = cast<TermInst>(user);
1008+
return llvm::all_of(ti->getSuccessorBlocks(), [&](SILBasicBlock *succBlock) {
1009+
// If we do not have any arguments, then continue.
1010+
if (succBlock->args_empty())
1011+
return true;
1012+
1013+
auto args = succBlock->getSILPhiArguments();
1014+
assert(args.size() == 1 && "Transforming terminator with multiple args?!");
1015+
return visitor(args[0]);
1016+
});
1017+
}

0 commit comments

Comments
 (0)