diff --git a/include/swift/SIL/OwnershipUtils.h b/include/swift/SIL/OwnershipUtils.h index 349ee45531ba2..35d11727a9f75 100644 --- a/include/swift/SIL/OwnershipUtils.h +++ b/include/swift/SIL/OwnershipUtils.h @@ -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, @@ -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(value); if (dyn_cast_or_null(phiArg->getSingleTerminator())) { @@ -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: @@ -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: diff --git a/lib/SIL/Utils/OwnershipUtils.cpp b/lib/SIL/Utils/OwnershipUtils.cpp index 8ccc42453f021..836895a103a9c 100644 --- a/lib/SIL/Utils/OwnershipUtils.cpp +++ b/lib/SIL/Utils/OwnershipUtils.cpp @@ -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; diff --git a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp index d9df231b33c74..8b22cc85b36af 100644 --- a/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp +++ b/lib/SILOptimizer/Transforms/SemanticARCOpts.cpp @@ -54,6 +54,7 @@ class OwnershipPhiOperand { public: enum Kind { Branch, + Struct, }; private: @@ -65,6 +66,7 @@ class OwnershipPhiOperand { static Optional get(const Operand *op) { switch (op->getUser()->getKind()) { case SILInstructionKind::BranchInst: + case SILInstructionKind::StructInst: return {{const_cast(op)}}; default: return None; @@ -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?!"); } @@ -100,6 +104,8 @@ class OwnershipPhiOperand { switch (getKind()) { case Kind::Branch: return true; + case Kind::Struct: + return false; } } @@ -113,6 +119,8 @@ class OwnershipPhiOperand { bool visitResults(function_ref visitor) const { switch (getKind()) { + case Kind::Struct: + return visitor(cast(getInst())); case Kind::Branch: { auto *br = cast(getInst()); unsigned opNum = getOperandNumber(); @@ -576,6 +584,11 @@ static SILValue convertIntroducerToGuaranteed(OwnedValueIntroducer introducer) { phiArg->setOwnershipKind(ValueOwnershipKind::Guaranteed); return phiArg; } + case OwnedValueIntroducerKind::Struct: { + auto *si = cast(introducer.value); + si->setOwnershipKind(ValueOwnershipKind::Guaranteed); + return si; + } case OwnedValueIntroducerKind::Copy: case OwnedValueIntroducerKind::LoadCopy: case OwnedValueIntroducerKind::Apply: @@ -1084,6 +1097,20 @@ static bool getIncomingJoinedLiveRangeOperands( }); } + if (auto *svi = dyn_cast(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?!"); } diff --git a/test/SILOptimizer/semantic-arc-opts.sil b/test/SILOptimizer/semantic-arc-opts.sil index 1c42c761f9996..f36740dc8c9d2 100644 --- a/test/SILOptimizer/semantic-arc-opts.sil +++ b/test/SILOptimizer/semantic-arc-opts.sil @@ -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 : $() +} \ No newline at end of file