Skip to content

Commit 8229b37

Browse files
committed
Performance annotations: add attributes @_noLocks and @_noAllocation
1 parent 60f3d61 commit 8229b37

File tree

16 files changed

+113
-11
lines changed

16 files changed

+113
-11
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,3 +625,12 @@ for more details.
625625

626626
Marks a var decl as a variable that must be copied explicitly using the builtin
627627
function Builtin.copy.
628+
629+
## `@_noAllocation`, `@_noLocks`
630+
631+
These attributes are performance annotations. If a function is annotated with
632+
such an attribute, the compiler issues a diagnostic message if the function
633+
calls a runtime function which allocates memory or locks, respectively.
634+
The `@_noLocks` attribute implies `@_noAllocation` because a memory allocation
635+
also locks.
636+

docs/SIL.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,15 @@ Specifies for which types specialized code should be generated.
11071107
sil-function-attribute ::= '[clang "' identifier '"]'
11081108

11091109
The clang node owner.
1110+
::
1111+
1112+
sil-function-attribute ::= '[' performance-constraint ']'
1113+
performance-constraint :: 'no_locks'
1114+
performance-constraint :: 'no_allocation'
1115+
1116+
Specifies the performance constraints for the function, which defines which type
1117+
of runtime functions are allowed to be called from the function.
1118+
11101119

11111120
Basic Blocks
11121121
~~~~~~~~~~~~

include/swift/AST/Attr.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,16 @@ SIMPLE_DECL_ATTR(_noImplicitCopy, NoImplicitCopy,
679679
OnVar,
680680
122)
681681

682+
SIMPLE_DECL_ATTR(_noLocks, NoLocks,
683+
OnAbstractFunction | OnSubscript | UserInaccessible |
684+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
685+
123)
686+
687+
SIMPLE_DECL_ATTR(_noAllocation, NoAllocation,
688+
OnAbstractFunction | OnSubscript | UserInaccessible |
689+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
690+
124)
691+
682692
// If you're adding a new underscored attribute here, please document it in
683693
// docs/ReferenceGuides/UnderscoredAttributes.md.
684694

include/swift/SIL/SILFunction.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ enum IsExactSelfClass_t {
6060
IsExactSelfClass,
6161
};
6262

63+
enum class PerformanceConstraints : uint8_t {
64+
None = 0,
65+
NoAllocation = 1,
66+
NoLocks = 2,
67+
};
68+
6369
class SILSpecializeAttr final {
6470
friend SILFunction;
6571
public:
@@ -232,6 +238,8 @@ class SILFunction
232238

233239
Purpose specialPurpose = Purpose::None;
234240

241+
PerformanceConstraints perfConstraints = PerformanceConstraints::None;
242+
235243
/// This is the number of uses of this SILFunction inside the SIL.
236244
/// It does not include references from debug scopes.
237245
unsigned RefCount = 0;
@@ -813,6 +821,12 @@ class SILFunction
813821
OptMode = unsigned(mode);
814822
}
815823

824+
PerformanceConstraints getPerfConstraints() const { return perfConstraints; }
825+
826+
void setPerfConstraints(PerformanceConstraints perfConstr) {
827+
perfConstraints = perfConstr;
828+
}
829+
816830
/// \returns True if the function is optimizable (i.e. not marked as no-opt),
817831
/// or is raw SIL (so that the mandatory passes still run).
818832
bool shouldOptimize() const;

lib/SIL/IR/SILFunction.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ void SILFunction::init(SILLinkage Linkage, StringRef Name,
187187
this->IsStaticallyLinked = false;
188188
this->IsWithoutActuallyEscapingThunk = false;
189189
this->OptMode = unsigned(OptimizationMode::NotSet);
190+
this->perfConstraints = PerformanceConstraints::None;
190191
this->EffectsKindAttr = unsigned(E);
191192
assert(!Transparent || !IsDynamicReplaceable);
192193
validateSubclassScope(classSubclassScope, isThunk, nullptr);

lib/SIL/IR/SILFunctionBuilder.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ void SILFunctionBuilder::addFunctionAttributes(
105105
if (Attrs.hasAttribute<SILGenNameAttr>() || Attrs.hasAttribute<CDeclAttr>())
106106
F->setHasCReferences(true);
107107

108+
if (Attrs.hasAttribute<NoLocksAttr>()) {
109+
F->setPerfConstraints(PerformanceConstraints::NoLocks);
110+
} else if (Attrs.hasAttribute<NoAllocationAttr>()) {
111+
F->setPerfConstraints(PerformanceConstraints::NoAllocation);
112+
}
113+
108114
// Validate `@differentiable` attributes by calling `getParameterIndices`.
109115
// This is important for:
110116
// - Skipping invalid `@differentiable` attributes in non-primary files.

lib/SIL/IR/SILPrinter.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2871,6 +2871,13 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
28712871
default: break;
28722872
}
28732873

2874+
PerformanceConstraints perf = getPerfConstraints();
2875+
switch (perf) {
2876+
case PerformanceConstraints::None: break;
2877+
case PerformanceConstraints::NoLocks: OS << "[no_locks] "; break;
2878+
case PerformanceConstraints::NoAllocation: OS << "[no_allocation] "; break;
2879+
}
2880+
28742881
if (getEffectsKind() == EffectsKind::ReadOnly)
28752882
OS << "[readonly] ";
28762883
else if (getEffectsKind() == EffectsKind::ReadNone)

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,7 @@ static bool parseDeclSILOptional(bool *isTransparent,
943943
SILFunction::Purpose *specialPurpose,
944944
Inline_t *inlineStrategy,
945945
OptimizationMode *optimizationMode,
946+
PerformanceConstraints *perfConstraints,
946947
bool *isLet,
947948
bool *isWeakImported,
948949
AvailabilityContext *availability,
@@ -1019,6 +1020,10 @@ static bool parseDeclSILOptional(bool *isTransparent,
10191020
*optimizationMode = OptimizationMode::ForSpeed;
10201021
else if (optimizationMode && SP.P.Tok.getText() == "Osize")
10211022
*optimizationMode = OptimizationMode::ForSize;
1023+
else if (perfConstraints && SP.P.Tok.getText() == "no_locks")
1024+
*perfConstraints = PerformanceConstraints::NoLocks;
1025+
else if (perfConstraints && SP.P.Tok.getText() == "no_allocation")
1026+
*perfConstraints = PerformanceConstraints::NoAllocation;
10221027
else if (inlineStrategy && SP.P.Tok.getText() == "always_inline")
10231028
*inlineStrategy = AlwaysInline;
10241029
else if (MRK && SP.P.Tok.getText() == "readnone")
@@ -6187,6 +6192,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
61876192
bool isWithoutActuallyEscapingThunk = false;
61886193
Inline_t inlineStrategy = InlineDefault;
61896194
OptimizationMode optimizationMode = OptimizationMode::NotSet;
6195+
PerformanceConstraints perfConstr = PerformanceConstraints::None;
61906196
SmallVector<std::string, 1> Semantics;
61916197
SmallVector<ParsedSpecAttr, 4> SpecAttrs;
61926198
ValueDecl *ClangDecl = nullptr;
@@ -6198,7 +6204,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
61986204
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
61996205
&isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction,
62006206
&objCReplacementFor, &specialPurpose, &inlineStrategy,
6201-
&optimizationMode, nullptr, &isWeakImported, &availability,
6207+
&optimizationMode, &perfConstr, nullptr, &isWeakImported, &availability,
62026208
&isWithoutActuallyEscapingThunk, &Semantics,
62036209
&SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
62046210
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
@@ -6242,6 +6248,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
62426248
isWithoutActuallyEscapingThunk);
62436249
FunctionState.F->setInlineStrategy(inlineStrategy);
62446250
FunctionState.F->setOptimizationMode(optimizationMode);
6251+
FunctionState.F->setPerfConstraints(perfConstr);
62456252
FunctionState.F->setEffectsKind(MRK);
62466253
if (ClangDecl)
62476254
FunctionState.F->setClangNodeOwner(ClangDecl);
@@ -6410,7 +6417,7 @@ bool SILParserState::parseSILGlobal(Parser &P) {
64106417
if (parseSILLinkage(GlobalLinkage, P) ||
64116418
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
64126419
nullptr, nullptr, nullptr, nullptr, nullptr,
6413-
nullptr, nullptr,
6420+
nullptr, nullptr, nullptr,
64146421
&isLet, nullptr, nullptr, nullptr, nullptr, nullptr,
64156422
nullptr, nullptr, State, M) ||
64166423
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
@@ -6462,7 +6469,7 @@ bool SILParserState::parseSILProperty(Parser &P) {
64626469
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
64636470
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
64646471
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
6465-
nullptr, nullptr, nullptr, SP, M))
6472+
nullptr, nullptr, nullptr, nullptr, SP, M))
64666473
return true;
64676474

64686475
ValueDecl *VD;
@@ -6531,7 +6538,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
65316538
if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr,
65326539
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
65336540
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
6534-
nullptr, nullptr, nullptr,
6541+
nullptr, nullptr, nullptr, nullptr,
65356542
VTableState, M))
65366543
return true;
65376544

@@ -7037,7 +7044,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
70377044
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
70387045
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
70397046
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7040-
nullptr, nullptr, nullptr,
7047+
nullptr, nullptr, nullptr, nullptr,
70417048
WitnessState, M))
70427049
return true;
70437050

lib/Sema/TypeCheckAttr.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
9292
IGNORED_ATTR(RequiresStoredPropertyInits)
9393
IGNORED_ATTR(RestatedObjCConformance)
9494
IGNORED_ATTR(Semantics)
95+
IGNORED_ATTR(NoLocks)
96+
IGNORED_ATTR(NoAllocation)
9597
IGNORED_ATTR(EmitAssemblyVisionRemarks)
9698
IGNORED_ATTR(ShowInInterface)
9799
IGNORED_ATTR(SILGenName)

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,8 @@ namespace {
14661466
UNINTERESTING_ATTR(InheritsConvenienceInitializers)
14671467
UNINTERESTING_ATTR(Inline)
14681468
UNINTERESTING_ATTR(Optimize)
1469+
UNINTERESTING_ATTR(NoLocks)
1470+
UNINTERESTING_ATTR(NoAllocation)
14691471
UNINTERESTING_ATTR(Inlinable)
14701472
UNINTERESTING_ATTR(Effects)
14711473
UNINTERESTING_ATTR(Final)

0 commit comments

Comments
 (0)