From e357fb45c56df0d2bc92ea8d4cd8ef5efd082d74 Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Wed, 2 Nov 2022 10:40:50 -0700 Subject: [PATCH] [OpaqueValues] Handle Builtin.copy. Specify the operand ownership of the Builtin differently depending on whether lowered addresses are used. Handle rewriting the value version of the builtin as the address version of the builtin in AddressLowering. --- lib/SIL/IR/OperandOwnership.cpp | 9 ++++- .../Mandatory/AddressLowering.cpp | 29 ++++++++++++++++ .../opaque_values_Onone_stdlib.swift | 34 +++++++++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 test/SILOptimizer/opaque_values_Onone_stdlib.swift diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index fade6f9b17c..99d70ff4244 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -821,7 +821,14 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, PoundAssert) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GlobalStringTablePointer) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TypePtrAuthDiscriminator) BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, TargetOSVersionAtLeast) -BUILTIN_OPERAND_OWNERSHIP(UnownedInstantaneousUse, Copy) +OperandOwnership OperandOwnershipBuiltinClassifier::visitCopy(BuiltinInst *bi, + StringRef) { + if (bi->getFunction()->getConventions().useLoweredAddresses()) { + return OperandOwnership::UnownedInstantaneousUse; + } else { + return OperandOwnership::DestroyingConsume; + } +} BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, StartAsyncLet) BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, EndAsyncLet) BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, StartAsyncLetWithLocalBuffer) diff --git a/lib/SILOptimizer/Mandatory/AddressLowering.cpp b/lib/SILOptimizer/Mandatory/AddressLowering.cpp index 774266ffc91..ba7a52a835e 100644 --- a/lib/SILOptimizer/Mandatory/AddressLowering.cpp +++ b/lib/SILOptimizer/Mandatory/AddressLowering.cpp @@ -2617,6 +2617,19 @@ protected: vmi->setOperand(opAddr); } + void visitBuiltinInst(BuiltinInst *bi) { + switch (bi->getBuiltinKind().getValueOr(BuiltinValueKind::None)) { + case BuiltinValueKind::Copy: { + SILValue opAddr = addrMat.materializeAddress(use->get()); + bi->setOperand(0, opAddr); + break; + } + default: + bi->dump(); + llvm::report_fatal_error("^^^ Unimplemented builtin opaque value use."); + } + } + void visitBeginBorrowInst(BeginBorrowInst *borrow); void visitEndBorrowInst(EndBorrowInst *end) {} @@ -3112,6 +3125,22 @@ protected: ApplyRewriter(bai, pass).convertBeginApplyWithOpaqueYield(); } + void visitBuiltinInst(BuiltinInst *bi) { + switch (bi->getBuiltinKind().getValueOr(BuiltinValueKind::None)) { + case BuiltinValueKind::Copy: { + SILValue addr = addrMat.materializeAddress(bi); + builder.createBuiltin( + bi->getLoc(), bi->getName(), + SILType::getEmptyTupleType(bi->getType().getASTContext()), + bi->getSubstitutions(), {addr, bi->getOperand(0)}); + break; + } + default: + bi->dump(); + llvm::report_fatal_error("^^^ Unimplemented builtin opaque value def."); + } + } + // Rewrite the apply for an indirect result. void visitDestructureTupleInst(DestructureTupleInst *destructure) { SILValue srcVal = destructure->getOperand(); diff --git a/test/SILOptimizer/opaque_values_Onone_stdlib.swift b/test/SILOptimizer/opaque_values_Onone_stdlib.swift new file mode 100644 index 00000000000..19c4ab8bc0e --- /dev/null +++ b/test/SILOptimizer/opaque_values_Onone_stdlib.swift @@ -0,0 +1,34 @@ +// RUN: %target-swift-frontend -parse-stdlib -enable-experimental-move-only -module-name main -enable-sil-opaque-values -parse-as-library -emit-sil -Onone %s | %FileCheck %s + +// Like opaque_values_Onone.swift but for code that needs to be compiled with +// -parse-stdlib. + +class X {} + +func consume(_ x : __owned X) {} + +func foo(@_noImplicitCopy _ x: __owned X) { + consume(_copy(x)) + consume(x) +} + +// CHECK-LABEL: sil [transparent] [_semantics "lifetimemanagement.copy"] @_copy : {{.*}} { +// CHECK: {{bb[0-9]+}}([[OUT_ADDR:%[^,]+]] : $*T, [[IN_ADDR:%[^,]+]] : $*T): +// CHECK: [[TMP_ADDR:%[^,]+]] = alloc_stack $T +// CHECK: copy_addr [[IN_ADDR]] to [init] [[TMP_ADDR]] : $*T +// CHECK: [[REGISTER_5:%[^,]+]] = builtin "copy"([[OUT_ADDR]] : $*T, [[TMP_ADDR]] : $*T) : $() +// CHECK: dealloc_stack [[TMP_ADDR]] : $*T +// CHECK: return {{%[^,]+}} : $() +// CHECK-LABEL: } // end sil function '_copy' +@_transparent +@_semantics("lifetimemanagement.copy") +@_silgen_name("_copy") +public func _copy(_ value: T) -> T { + #if $BuiltinCopy + Builtin.copy(value) + #else + value + #endif +} + +