Skip to content

[semantic-arc-opts] Teach semantic-arc-opts how to handle structs with multiple non-trivial values. #32173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/swift/SIL/OwnershipUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,10 @@ struct OwnedValueIntroducerKind {
/// branch predecessors.
Phi,

/// An owned value that is from a struct that has multiple operands that are
/// owned.
Struct,

/// An owned value that is a function argument.
FunctionArgument,

Expand All @@ -522,6 +526,8 @@ struct OwnedValueIntroducerKind {
return OwnedValueIntroducerKind(Apply);
case ValueKind::BeginApplyResult:
return OwnedValueIntroducerKind(BeginApply);
case ValueKind::StructInst:
return OwnedValueIntroducerKind(Struct);
case ValueKind::SILPhiArgument: {
auto *phiArg = cast<SILPhiArgument>(value);
if (dyn_cast_or_null<TryApplyInst>(phiArg->getSingleTerminator())) {
Expand Down Expand Up @@ -614,6 +620,7 @@ struct OwnedValueIntroducer {
case OwnedValueIntroducerKind::TryApply:
case OwnedValueIntroducerKind::LoadTake:
case OwnedValueIntroducerKind::Phi:
case OwnedValueIntroducerKind::Struct:
case OwnedValueIntroducerKind::FunctionArgument:
case OwnedValueIntroducerKind::PartialApplyInit:
case OwnedValueIntroducerKind::AllocBoxInit:
Expand All @@ -631,6 +638,7 @@ struct OwnedValueIntroducer {
switch (kind) {
case OwnedValueIntroducerKind::Phi:
return true;
case OwnedValueIntroducerKind::Struct:
case OwnedValueIntroducerKind::Copy:
case OwnedValueIntroducerKind::LoadCopy:
case OwnedValueIntroducerKind::Apply:
Expand Down
3 changes: 3 additions & 0 deletions lib/SIL/Utils/OwnershipUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,9 @@ void OwnedValueIntroducerKind::print(llvm::raw_ostream &os) const {
case OwnedValueIntroducerKind::Phi:
os << "Phi";
return;
case OwnedValueIntroducerKind::Struct:
os << "Struct";
return;
case OwnedValueIntroducerKind::FunctionArgument:
os << "FunctionArgument";
return;
Expand Down
27 changes: 27 additions & 0 deletions lib/SILOptimizer/Transforms/SemanticARCOpts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class OwnershipPhiOperand {
public:
enum Kind {
Branch,
Struct,
};

private:
Expand All @@ -65,6 +66,7 @@ class OwnershipPhiOperand {
static Optional<OwnershipPhiOperand> get(const Operand *op) {
switch (op->getUser()->getKind()) {
case SILInstructionKind::BranchInst:
case SILInstructionKind::StructInst:
return {{const_cast<Operand *>(op)}};
default:
return None;
Expand All @@ -75,6 +77,8 @@ class OwnershipPhiOperand {
switch (op->getUser()->getKind()) {
case SILInstructionKind::BranchInst:
return Kind::Branch;
case SILInstructionKind::StructInst:
return Kind::Struct;
default:
llvm_unreachable("unhandled case?!");
}
Expand All @@ -100,6 +104,8 @@ class OwnershipPhiOperand {
switch (getKind()) {
case Kind::Branch:
return true;
case Kind::Struct:
return false;
}
}

Expand All @@ -113,6 +119,8 @@ class OwnershipPhiOperand {

bool visitResults(function_ref<bool(SILValue)> visitor) const {
switch (getKind()) {
case Kind::Struct:
return visitor(cast<StructInst>(getInst()));
case Kind::Branch: {
auto *br = cast<BranchInst>(getInst());
unsigned opNum = getOperandNumber();
Expand Down Expand Up @@ -576,6 +584,11 @@ static SILValue convertIntroducerToGuaranteed(OwnedValueIntroducer introducer) {
phiArg->setOwnershipKind(ValueOwnershipKind::Guaranteed);
return phiArg;
}
case OwnedValueIntroducerKind::Struct: {
auto *si = cast<StructInst>(introducer.value);
si->setOwnershipKind(ValueOwnershipKind::Guaranteed);
return si;
}
case OwnedValueIntroducerKind::Copy:
case OwnedValueIntroducerKind::LoadCopy:
case OwnedValueIntroducerKind::Apply:
Expand Down Expand Up @@ -1084,6 +1097,20 @@ static bool getIncomingJoinedLiveRangeOperands(
});
}

if (auto *svi = dyn_cast<SingleValueInstruction>(joinedLiveRange)) {
return llvm::all_of(svi->getAllOperands(), [&](const Operand &op) {
// skip type dependent operands.
if (op.isTypeDependent())
return true;

auto phiOp = OwnershipPhiOperand::get(&op);
if (!phiOp)
return false;
resultingOperands.push_back(*phiOp);
return true;
});
}

llvm_unreachable("Unhandled joined live range?!");
}

Expand Down
13 changes: 13 additions & 0 deletions test/SILOptimizer/semantic-arc-opts.sil
Original file line number Diff line number Diff line change
Expand Up @@ -2548,3 +2548,16 @@ bb1:
bb2(%39 : @owned $Klass):
unreachable
}

// CHECK-LABEL: sil [ossa] @struct_with_multiple_nontrivial_operands : $@convention(thin) (@guaranteed Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
// CHECK-NOT: copy_value
// CHECK: } // end sil function 'struct_with_multiple_nontrivial_operands'
sil [ossa] @struct_with_multiple_nontrivial_operands : $@convention(thin) (@guaranteed Builtin.NativeObject, @guaranteed Builtin.NativeObject) -> () {
bb0(%0 : @guaranteed $Builtin.NativeObject, %1 : @guaranteed $Builtin.NativeObject):
%0a = copy_value %0 : $Builtin.NativeObject
%1a = copy_value %1 : $Builtin.NativeObject
%2 = struct $NativeObjectPair(%0a : $Builtin.NativeObject, %1a : $Builtin.NativeObject)
destroy_value %2 : $NativeObjectPair
%9999 = tuple()
return %9999 : $()
}