Skip to content

Commit 61fe8a9

Browse files
committed
introduce @_manualOwnership performance attribute
This attribute forces programmers to acknowledge every copy that is required to happen in the body of the function. Only those copies that make sense according to Swift's ownership rules should be "required". The way this is implemented as of now is to flag each non-explicit copy in a function, coming from SILGen, as an error through PerformanceDiagnostics.
1 parent 76c1aea commit 61fe8a9

21 files changed

+288
-3
lines changed

SwiftCompilerSources/Sources/SIL/Function.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
293293
case noRuntime
294294
case noExistentials
295295
case noObjCRuntime
296+
case manualOwnership
296297
}
297298

298299
public var performanceConstraints: PerformanceConstraints {
@@ -303,6 +304,7 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
303304
case .NoRuntime: return .noRuntime
304305
case .NoExistentials: return .noExistentials
305306
case .NoObjCBridging: return .noObjCRuntime
307+
case .ManualOwnership: return .manualOwnership
306308
default: fatalError("unknown performance constraint")
307309
}
308310
}

include/swift/AST/DeclAttr.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,10 @@ SIMPLE_DECL_ATTR(_noObjCBridging, NoObjCBridging,
815815
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
816816
155)
817817

818-
// Unused '156': Used to be `_distributedThunkTarget` but completed implementation in Swift 6.0 does not need it after all
818+
SIMPLE_DECL_ATTR(_manualOwnership, ManualOwnership,
819+
OnAbstractFunction | OnSubscript,
820+
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | ForbiddenInABIAttr,
821+
156)
819822

820823
DECL_ATTR(_allowFeatureSuppression, AllowFeatureSuppression,
821824
OnAnyDecl,

include/swift/AST/DiagnosticsSIL.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,8 @@ ERROR(wrong_linkage_for_serialized_function,none,
428428
"function has wrong linkage to be called from %0", (StringRef))
429429
NOTE(performance_called_from,none,
430430
"called from here", ())
431+
ERROR(manualownership_copy,none,
432+
"explicit 'copy' required here", ())
431433

432434
// 'transparent' diagnostics
433435
ERROR(circular_transparent,none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,10 @@ ERROR(attr_static_exclusive_only_mutating,none,
21452145
ERROR(attr_static_exclusive_no_setters,none,
21462146
"variable of type %0 must not have a setter", (Type))
21472147

2148+
// @_manualOwnership
2149+
ERROR(attr_manual_ownership_experimental,none,
2150+
"'@_manualOwnership' requires '-enable-experimental-feature ManualOwnership'", ())
2151+
21482152
// @extractConstantsFromMembers
21492153
ERROR(attr_extractConstantsFromMembers_experimental,none,
21502154
"'@extractConstantsFromMembers' requires "

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,9 @@ EXPERIMENTAL_FEATURE(LifetimeDependence, true)
447447
/// Enable the `@_staticExclusiveOnly` attribute.
448448
EXPERIMENTAL_FEATURE(StaticExclusiveOnly, true)
449449

450+
/// Enable the `@_manualOwnership` attribute.
451+
EXPERIMENTAL_FEATURE(ManualOwnership, false)
452+
450453
/// Enable the @extractConstantsFromMembers attribute.
451454
EXPERIMENTAL_FEATURE(ExtractConstantsFromMembers, false)
452455

include/swift/SIL/SILBridging.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,8 @@ struct BridgedFunction {
463463
NoLocks = 2,
464464
NoRuntime = 3,
465465
NoExistentials = 4,
466-
NoObjCBridging = 5
466+
NoObjCBridging = 5,
467+
ManualOwnership = 6,
467468
};
468469

469470
enum class InlineStrategy {

include/swift/SIL/SILBuilder.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,14 @@ class SILBuilder {
280280
return false;
281281
}
282282

283+
/// If we have a SILFunction, return true if it has a ManualOwnership
284+
/// PerformanceConstraint, which corresponds to an attribute on the FuncDecl.
285+
bool hasManualOwnershipAttr() const {
286+
if (F)
287+
return F->getPerfConstraints() == PerformanceConstraints::ManualOwnership;
288+
return false;
289+
}
290+
283291
//===--------------------------------------------------------------------===//
284292
// Insertion Point Management
285293
//===--------------------------------------------------------------------===//

include/swift/SIL/SILCloner.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,6 +1698,16 @@ template<typename ImplClass>
16981698
void
16991699
SILCloner<ImplClass>::visitCopyAddrInst(CopyAddrInst *Inst) {
17001700
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
1701+
// When cloning into a function using manual ownership, convert to explicit
1702+
// copies, in order to preserve the local nature of the perf constraint.
1703+
if (getBuilder().hasManualOwnershipAttr() && getBuilder().hasOwnership()) {
1704+
recordClonedInstruction(
1705+
Inst, getBuilder().createExplicitCopyAddr(
1706+
getOpLocation(Inst->getLoc()), getOpValue(Inst->getSrc()),
1707+
getOpValue(Inst->getDest()), Inst->isTakeOfSrc(),
1708+
Inst->isInitializationOfDest()));
1709+
return;
1710+
}
17011711
recordClonedInstruction(
17021712
Inst, getBuilder().createCopyAddr(
17031713
getOpLocation(Inst->getLoc()), getOpValue(Inst->getSrc()),
@@ -2092,6 +2102,15 @@ void SILCloner<ImplClass>::visitCopyValueInst(CopyValueInst *Inst) {
20922102
return recordFoldedValue(Inst, newValue);
20932103
}
20942104

2105+
// When cloning into a function using manual ownership, convert to explicit
2106+
// copies, in order to preserve the local nature of the perf constraint.
2107+
if (getBuilder().hasManualOwnershipAttr() && getBuilder().hasOwnership()) {
2108+
recordClonedInstruction(
2109+
Inst, getBuilder().createExplicitCopyValue(getOpLocation(Inst->getLoc()),
2110+
getOpValue(Inst->getOperand())));
2111+
return;
2112+
}
2113+
20952114
recordClonedInstruction(
20962115
Inst, getBuilder().createCopyValue(getOpLocation(Inst->getLoc()),
20972116
getOpValue(Inst->getOperand())));

include/swift/SIL/SILFunction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,8 @@ enum class PerformanceConstraints : uint8_t {
9393
NoLocks = 2,
9494
NoRuntime = 3,
9595
NoExistentials = 4,
96-
NoObjCBridging = 5
96+
NoObjCBridging = 5,
97+
ManualOwnership = 6,
9798
};
9899

99100
class SILSpecializeAttr final {

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5030,6 +5030,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, Label>,
50305030
TRIVIAL_ATTR_PRINTER(NoLocks, no_locks)
50315031
TRIVIAL_ATTR_PRINTER(NoMetadata, no_metadata)
50325032
TRIVIAL_ATTR_PRINTER(NoObjCBridging, no_objc_bridging)
5033+
TRIVIAL_ATTR_PRINTER(ManualOwnership, manual_ownership)
50335034
TRIVIAL_ATTR_PRINTER(NoRuntime, no_runtime)
50345035
TRIVIAL_ATTR_PRINTER(NonEphemeral, non_ephemeral)
50355036
TRIVIAL_ATTR_PRINTER(NonEscapable, non_escapable)

0 commit comments

Comments
 (0)