Skip to content

Commit 06921cf

Browse files
committed
[SIL] Hollow out Builtin.copy, deprecate _copy.
The copy operator has been implemented and doesn't use it. Remove `Builtin.copy` and `_copy` as much as currently possible. Source compatibility requires that `_copy` remain in the stdlib. It is deprecated here and just uses the copy operator. Handling old swiftinterfaces requires that `Builtin.copy` be defined. Redefine it here as a passthrough--SILGen machinery will produce the necessary copy_addr. rdar://127502242
1 parent 6fdaea5 commit 06921cf

20 files changed

+98
-260
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/AddressUtils.swift

-6
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,6 @@ extension AddressUseVisitor {
165165

166166
case let builtin as BuiltinInst:
167167
switch builtin.id {
168-
case .Copy where builtin.operands[1] == operand: // source
169-
return loadedAddressUse(of: operand, into: builtin.operands[0])
170-
171-
case .Copy where builtin.operands[0] == operand: // dest
172-
return leafAddressUse(of: operand)
173-
174168
// Builtins that cannot load a nontrivial value.
175169
case .TSanInoutAccess, .ResumeThrowingContinuationReturning,
176170
.ResumeNonThrowingContinuationReturning, .GenericAdd,

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

-6
Original file line numberDiff line numberDiff line change
@@ -909,12 +909,6 @@ extension LifetimeDependenceDefUseWalker {
909909
case let tai as TupleAddrConstructorInst:
910910
return visitStoredUses(of: operand, into: tai.destinationOperand.value)
911911

912-
case let bi as BuiltinInst where bi.id == .Copy:
913-
// This must be a non-address-lowered form of Builtin.Copy that
914-
// produces an owned value.
915-
assert(bi.ownership == .owned)
916-
return walkDownUses(of: bi, using: operand)
917-
918912
default:
919913
return nonForwardingUse(of: operand)
920914
}

include/swift/AST/Builtins.def

+8-18
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,14 @@ BUILTIN_SIL_OPERATION(HopToActor, "hopToActor", None)
537537
/// Returns the number of items in a pack.
538538
BUILTIN_SIL_OPERATION(PackLength, "packLength", Special)
539539

540+
/// TODO: Remove. Only exists to avoid a reverse condfail.
541+
/// rdar://127516085 (Complete removal of Builtin.copy)
542+
///
543+
/// copy: <T>(T) -> T
544+
///
545+
/// Creates a copy of the source at the destination.
546+
BUILTIN_SIL_OPERATION(Copy, "copy", Special)
547+
540548
// BUILTIN_RUNTIME_CALL - A call into a runtime function.
541549
// These functions accept a single argument of any type.
542550
#ifndef BUILTIN_RUNTIME_CALL
@@ -804,24 +812,6 @@ BUILTIN_MISC_OPERATION(CreateTaskGroupWithFlags,
804812
BUILTIN_MISC_OPERATION(DestroyTaskGroup,
805813
"destroyTaskGroup", "", Special)
806814

807-
/// A builtin that can only be called from a transparent generic function. Takes
808-
/// two operands, the first operand the result address, the second operand the
809-
/// input address. Transforms into
810-
///
811-
/// %input = load [take] %inputAddr
812-
/// %result = explicit_copy_value %input
813-
/// store %result to [init] %resultAddr
814-
/// store %input to [init] %inputAddr
815-
///
816-
/// transparently inlined into a caller that has the generic of the callee
817-
/// specialized into a loadable type. If the transparent inlining does not
818-
/// specialize the type (due to being inlined into a non-generic context, the
819-
/// SILVerifier will abort).
820-
///
821-
/// Illegal to call except for in Swift._copy in the stdlib. This is enforced by
822-
/// the SILVerifier.
823-
BUILTIN_MISC_OPERATION(Copy, "copy", "", Special)
824-
825815
/// Unchecked pointer alignment assertion. Allows the compiler to assume
826816
/// alignment of the pointer to emit more efficient code.
827817
///

include/swift/AST/SemanticAttrs.def

-1
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ SEMANTICS_ATTR(FORCE_EMIT_OPT_REMARK_PREFIX, "optremark")
124124
SEMANTICS_ATTR(OBJC_FORBID_ASSOCIATED_OBJECTS, "objc.forbidAssociatedObjects")
125125

126126
SEMANTICS_ATTR(LIFETIMEMANAGEMENT_MOVE, "lifetimemanagement.move")
127-
SEMANTICS_ATTR(LIFETIMEMANAGEMENT_COPY, "lifetimemanagement.copy")
128127

129128
SEMANTICS_ATTR(NO_PERFORMANCE_ANALYSIS, "no_performance_analysis")
130129

include/swift/SIL/AddressWalker.h

-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,6 @@ TransitiveAddressWalker<Impl>::walk(SILValue projectedAddress) && {
251251
case BuiltinValueKind::TSanInoutAccess:
252252
case BuiltinValueKind::ResumeThrowingContinuationReturning:
253253
case BuiltinValueKind::ResumeNonThrowingContinuationReturning:
254-
case BuiltinValueKind::Copy:
255254
case BuiltinValueKind::GenericAdd:
256255
case BuiltinValueKind::GenericFAdd:
257256
case BuiltinValueKind::GenericAnd:

lib/IRGen/GenBuiltin.cpp

-10
Original file line numberDiff line numberDiff line change
@@ -1437,16 +1437,6 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
14371437
return;
14381438
}
14391439

1440-
if (Builtin.ID == BuiltinValueKind::Copy) {
1441-
auto input = args.claimNext();
1442-
auto result = args.claimNext();
1443-
SILType addrTy = argTypes[0];
1444-
const TypeInfo &addrTI = IGF.getTypeInfo(addrTy);
1445-
Address inputAttr = addrTI.getAddressForPointer(input);
1446-
Address resultAttr = addrTI.getAddressForPointer(result);
1447-
addrTI.initializeWithCopy(IGF, resultAttr, inputAttr, addrTy, false);
1448-
return;
1449-
}
14501440
if (Builtin.ID == BuiltinValueKind::AssumeAlignment) {
14511441
// A no-op pointer cast that passes on its first value. Common occurrences of
14521442
// this builtin should already be removed with the alignment guarantee moved

lib/SIL/IR/OperandOwnership.cpp

-8
Original file line numberDiff line numberDiff line change
@@ -899,14 +899,6 @@ BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, GetEnumTag)
899899
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, InjectEnumTag)
900900
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, DistributedActorAsAnyActor)
901901
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, AddressOfRawLayout)
902-
OperandOwnership OperandOwnershipBuiltinClassifier::visitCopy(BuiltinInst *bi,
903-
StringRef) {
904-
if (bi->getFunction()->getConventions().useLoweredAddresses()) {
905-
return OperandOwnership::UnownedInstantaneousUse;
906-
} else {
907-
return OperandOwnership::DestroyingConsume;
908-
}
909-
}
910902
BUILTIN_OPERAND_OWNERSHIP(DestroyingConsume, StartAsyncLet)
911903
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, EndAsyncLet)
912904
BUILTIN_OPERAND_OWNERSHIP(InstantaneousUse, EndAsyncLetLifetime)

lib/SIL/IR/ValueOwnership.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,6 @@ CONSTANT_OWNERSHIP_BUILTIN(None, CreateTaskGroup)
629629
CONSTANT_OWNERSHIP_BUILTIN(None, CreateTaskGroupWithFlags)
630630
CONSTANT_OWNERSHIP_BUILTIN(None, DestroyTaskGroup)
631631
CONSTANT_OWNERSHIP_BUILTIN(None, TaskRunInline)
632-
CONSTANT_OWNERSHIP_BUILTIN(None, Copy)
633632
CONSTANT_OWNERSHIP_BUILTIN(None, GetEnumTag)
634633
CONSTANT_OWNERSHIP_BUILTIN(None, InjectEnumTag)
635634
CONSTANT_OWNERSHIP_BUILTIN(Owned, DistributedActorAsAnyActor)

lib/SIL/Utils/MemAccessUtils.cpp

-5
Original file line numberDiff line numberDiff line change
@@ -2592,11 +2592,6 @@ static void visitBuiltinAddress(BuiltinInst *builtin,
25922592
visitor(&builtin->getAllOperands()[0]);
25932593
return;
25942594

2595-
// These effect both operands.
2596-
case BuiltinValueKind::Copy:
2597-
visitor(&builtin->getAllOperands()[1]);
2598-
return;
2599-
26002595
// These consume values out of their second operand.
26012596
case BuiltinValueKind::ResumeNonThrowingContinuationReturning:
26022597
case BuiltinValueKind::ResumeThrowingContinuationReturning:

lib/SIL/Verifier/SILVerifier.cpp

-16
Original file line numberDiff line numberDiff line change
@@ -2343,22 +2343,6 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
23432343
return;
23442344
}
23452345

2346-
if (builtinKind == BuiltinValueKind::Copy) {
2347-
// We expect that this builtin will be specialized during transparent
2348-
// inlining into explicit_copy_value if we inline into a non-generic
2349-
// context. If the builtin still remains and is not in the specific copy
2350-
// semantic function (which is the only function marked with
2351-
// semantics::LIFETIMEMANAGEMENT_COPY), then we know that we did
2352-
// transparent inlining into a function that did not result in the Builtin
2353-
// being specialized out which is user error.
2354-
//
2355-
// NOTE: Once we have opaque values, this restriction will go away. This
2356-
// is just so we can call Builtin.copy outside of the stdlib.
2357-
auto semanticName = semantics::LIFETIMEMANAGEMENT_COPY;
2358-
require(BI->getFunction()->hasSemanticsAttr(semanticName),
2359-
"_copy used within a generic context");
2360-
}
2361-
23622346
if (builtinKind == BuiltinValueKind::CreateAsyncTask) {
23632347
requireType(BI->getType(), _object(_tuple(_nativeObject, _rawPointer)),
23642348
"result of createAsyncTask");

lib/SILGen/SILGenBuiltin.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -2027,6 +2027,23 @@ static ManagedValue emitBuiltinAddressOfRawLayout(SILGenFunction &SGF,
20272027
return ManagedValue::forObjectRValueWithoutOwnership(bi);
20282028
}
20292029

2030+
/// TODO: Remove. Only exists to avoid a reverse condfail.
2031+
/// rdar://127516085 (Complete removal of Builtin.copy)
2032+
static ManagedValue emitBuiltinCopy(SILGenFunction &SGF, SILLocation loc,
2033+
SubstitutionMap subs,
2034+
ArrayRef<ManagedValue> args, SGFContext C) {
2035+
// Builtin.copy has no uses in current/future swiftinterfaces. It has a
2036+
// single use in old swiftinterfaces:
2037+
// func _copy<T>(_ t: T) -> T {
2038+
// Builtin.copy(t)
2039+
// }
2040+
// It is sufficient to have the builtin pass the value through. When the
2041+
// return is emitted, a copy will be made.
2042+
assert(args.size() == 1 && "not two arguments!?");
2043+
return ManagedValue::forOwnedAddressRValue(args[0].getValue(),
2044+
CleanupHandle::invalid());
2045+
}
2046+
20302047
std::optional<SpecializedEmitter>
20312048
SpecializedEmitter::forDecl(SILGenModule &SGM, SILDeclRef function) {
20322049
// Only consider standalone declarations in the Builtin module.

lib/SILOptimizer/Mandatory/AddressLowering.cpp

-13
Original file line numberDiff line numberDiff line change
@@ -3389,11 +3389,6 @@ class UseRewriter : SILInstructionVisitor<UseRewriter> {
33893389
bi->setOperand(use->getOperandNumber(), opAddr);
33903390
break;
33913391
}
3392-
case BuiltinValueKind::Copy: {
3393-
SILValue opAddr = addrMat.materializeAddress(use->get());
3394-
bi->setOperand(0, opAddr);
3395-
break;
3396-
}
33973392
case BuiltinValueKind::AddressOfBorrowOpaque:
33983393
visitAddressOfBorrowBuiltinInst(bi, /*stackProtected=*/true);
33993394
break;
@@ -4084,14 +4079,6 @@ class DefRewriter : SILInstructionVisitor<DefRewriter> {
40844079

40854080
void visitBuiltinInst(BuiltinInst *bi) {
40864081
switch (bi->getBuiltinKind().value_or(BuiltinValueKind::None)) {
4087-
case BuiltinValueKind::Copy: {
4088-
SILValue addr = addrMat.materializeAddress(bi);
4089-
builder.createBuiltin(
4090-
bi->getLoc(), bi->getName(),
4091-
SILType::getEmptyTupleType(bi->getType().getASTContext()),
4092-
bi->getSubstitutions(), {addr, bi->getOperand(0)});
4093-
break;
4094-
}
40954082
default:
40964083
bi->dump();
40974084
llvm::report_fatal_error("^^^ Unimplemented builtin opaque value def.");

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ static bool isBarrier(SILInstruction *inst) {
183183
case BuiltinValueKind::AssignCopyArrayFrontToBack:
184184
case BuiltinValueKind::AssignCopyArrayBackToFront:
185185
case BuiltinValueKind::AssignTakeArray:
186-
case BuiltinValueKind::Copy:
187186
case BuiltinValueKind::CancelAsyncTask:
188187
case BuiltinValueKind::StartAsyncLet:
189188
case BuiltinValueKind::CreateAsyncTask:

lib/SILOptimizer/Utils/SILInliner.cpp

-46
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,6 @@ class SILInlineCloner
320320
void visitHopToExecutorInst(HopToExecutorInst *Inst);
321321

322322
void visitTerminator(SILBasicBlock *BB);
323-
void visitBuiltinInst(BuiltinInst *BI);
324323

325324
/// This hook is called after either of the top-level visitors:
326325
/// cloneReachableBlocks or cloneSILFunction.
@@ -820,51 +819,6 @@ static void diagnose(ASTContext &Context, SourceLoc loc, Diag<T...> diag,
820819
Context.Diags.diagnose(loc, diag, std::forward<U>(args)...);
821820
}
822821

823-
void SILInlineCloner::visitBuiltinInst(BuiltinInst *Inst) {
824-
if (IKind == InlineKind::MandatoryInline) {
825-
if (auto kind = Inst->getBuiltinKind()) {
826-
if (*kind == BuiltinValueKind::Copy) {
827-
auto otherResultAddr = getOpValue(Inst->getOperand(0));
828-
auto otherSrcAddr = getOpValue(Inst->getOperand(1));
829-
auto otherType = otherSrcAddr->getType();
830-
831-
if (!otherType.isLoadable(*Inst->getFunction())) {
832-
// If otherType is not loadable, emit a diagnostic since it was used
833-
// on a generic or existential value.
834-
diagnose(Inst->getModule().getASTContext(),
835-
getOpLocation(Inst->getLoc()).getSourceLoc(),
836-
diag::copy_operator_used_on_generic_or_existential_value);
837-
return SILCloner<SILInlineCloner>::visitBuiltinInst(Inst);
838-
}
839-
840-
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
841-
// We stash otherValue in originalOtherValue in case we need to
842-
// perform a writeback.
843-
auto opLoc = getOpLocation(Inst->getLoc());
844-
845-
assert(otherType.isAddress());
846-
847-
// Perform a load_borrow and then copy that.
848-
SILValue otherValue =
849-
getBuilder().emitLoadBorrowOperation(opLoc, otherSrcAddr);
850-
851-
auto *mvi = getBuilder().createExplicitCopyValue(opLoc, otherValue);
852-
853-
getBuilder().emitStoreValueOperation(opLoc, mvi, otherResultAddr,
854-
StoreOwnershipQualifier::Init);
855-
// End the borrowed value.
856-
getBuilder().emitEndBorrowOperation(opLoc, otherValue);
857-
858-
// We know that Inst returns a tuple value that isn't used by anything
859-
// else, so this /should/ be safe.
860-
return recordClonedInstruction(Inst, mvi);
861-
}
862-
}
863-
}
864-
865-
return SILCloner<SILInlineCloner>::visitBuiltinInst(Inst);
866-
}
867-
868822
//===----------------------------------------------------------------------===//
869823
// Cost Model
870824
//===----------------------------------------------------------------------===//

stdlib/public/core/LifetimeManager.swift

+2-22
Original file line numberDiff line numberDiff line change
@@ -266,31 +266,11 @@ extension String {
266266
}
267267
#endif
268268

269-
/// Takes in a value at +0 and performs a Builtin.copy upon it.
270-
///
271-
/// IMPLEMENTATION NOTES: During transparent inlining, Builtin.copy becomes the
272-
/// explicit_copy_value instruction if we are inlining into a context where the
273-
/// specialized type is loadable. If the transparent function is called in a
274-
/// context where the inlined function specializes such that the specialized
275-
/// type is still not loadable, the compiler aborts (a). Once we have opaque
276-
/// values, this restriction will be lifted since after that address only types
277-
/// at SILGen time will be loadable objects.
278-
///
279-
/// (a). This is implemented by requiring that Builtin.copy only be called
280-
/// within a function marked with the semantic tag "lifetimemanagement.copy"
281-
/// which conveniently is only the function we are defining here: _copy.
282-
///
283-
/// NOTE: We mark this _alwaysEmitIntoClient to ensure that we are not creating
284-
/// new ABI that the stdlib must maintain if a user calls this ignoring the '_'
285-
/// implying it is stdlib SPI.
269+
@available(*, deprecated, message: "Use the copy operator")
286270
@_alwaysEmitIntoClient
287271
@inlinable
288272
@_transparent
289273
@_semantics("lifetimemanagement.copy")
290274
public func _copy<T>(_ value: T) -> T {
291-
#if $BuiltinCopy
292-
Builtin.copy(value)
293-
#else
294-
value
295-
#endif
275+
copy value
296276
}

0 commit comments

Comments
 (0)