Skip to content

Commit ee3027c

Browse files
committed
[sil] Add the ability to mark a function with isolation just so we can write more concurrency tests in SIL.
Specifically, we write a string out like: sil [isolation "$REPRESENTATION OF ISOLATION"] @function : $@convention(thin) ... The idea is that by using a string, we avoid parsing issues of the isolation and have flexibility. I left in the way we put isolation into the comment above functions so I did not break any tests that rely on it. I also made it so that we only accept this with sil tests that pass in the flag "sil-print-function-isolation-info". I am going to for the next release put in a full real implementation of this that allows for actor isolation to become a true first class citizen in SIL. But for now this at least lets us write tests in the short term. Since this is temporary and behind a flag, I did not add support for serialization since this is just for writing textual SIL tests.
1 parent a28d065 commit ee3027c

File tree

3 files changed

+98
-19
lines changed

3 files changed

+98
-19
lines changed

lib/SIL/IR/SILPrinter.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ llvm::cl::opt<bool> SILPrintGenericSpecializationInfo(
9595
llvm::cl::desc("Include generic specialization"
9696
"information info in SIL output"));
9797

98+
llvm::cl::opt<bool> SILPrintFunctionIsolationInfo(
99+
"sil-print-function-isolation-info", llvm::cl::init(false),
100+
llvm::cl::desc("Print out isolation info on functions in a manner that SIL "
101+
"understands [e.x.: not in comments]"));
102+
98103
static std::string demangleSymbol(StringRef Name) {
99104
if (SILFullDemangle)
100105
return Demangle::demangleSymbolAsString(Name);
@@ -3630,6 +3635,15 @@ void SILFunction::print(SILPrintContext &PrintCtx) const {
36303635
OS << "[available " << availability.getVersionString() << "] ";
36313636
}
36323637

3638+
// This is here only for testing purposes.
3639+
if (SILPrintFunctionIsolationInfo) {
3640+
if (auto isolation = getActorIsolation()) {
3641+
OS << "[isolation \"";
3642+
isolation->printForSIL(OS);
3643+
OS << "\"] ";
3644+
}
3645+
}
3646+
36333647
switch (getInlineStrategy()) {
36343648
case NoInline: OS << "[noinline] "; break;
36353649
case AlwaysInline: OS << "[always_inline] "; break;

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -680,11 +680,13 @@ static bool parseDeclSILOptional(
680680
SILFunction::Purpose *specialPurpose, Inline_t *inlineStrategy,
681681
OptimizationMode *optimizationMode, PerformanceConstraints *perfConstraints,
682682
bool *isPerformanceConstraint, bool *markedAsUsed, StringRef *section,
683-
bool *isLet, bool *isWeakImported, bool *needStackProtection, bool *isSpecialized,
684-
AvailabilityRange *availability, bool *isWithoutActuallyEscapingThunk,
683+
bool *isLet, bool *isWeakImported, bool *needStackProtection,
684+
bool *isSpecialized, AvailabilityRange *availability,
685+
bool *isWithoutActuallyEscapingThunk,
685686
SmallVectorImpl<std::string> *Semantics,
686687
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs, ValueDecl **ClangDecl,
687-
EffectsKind *MRK, SILParser &SP, SILModule &M) {
688+
EffectsKind *MRK, ActorIsolation *actorIsolation, SILParser &SP,
689+
SILModule &M) {
688690
while (SP.P.consumeIf(tok::l_square)) {
689691
if (isLet && SP.P.Tok.is(tok::kw_let)) {
690692
*isLet = true;
@@ -785,7 +787,27 @@ static bool parseDeclSILOptional(
785787
*isPerformanceConstraint = true;
786788
else if (markedAsUsed && SP.P.Tok.getText() == "used")
787789
*markedAsUsed = true;
788-
else if (section && SP.P.Tok.getText() == "section") {
790+
else if (actorIsolation && SP.P.Tok.getText() == "isolation") {
791+
SP.P.consumeToken(tok::identifier);
792+
if (SP.P.Tok.getKind() != tok::string_literal) {
793+
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
794+
return true;
795+
}
796+
StringRef rawString = SP.P.Tok.getText().drop_front().drop_back();
797+
// TODO: By using a raw string here, we can perhaps put in a simple string
798+
// representation of an actor that can be parsed back. For now this is
799+
// just a quick hack so we can write tests.
800+
auto optIsolation = ActorIsolation::forSILString(
801+
SP.P.Context.getIdentifier(rawString).str());
802+
if (!optIsolation) {
803+
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
804+
return true;
805+
}
806+
*actorIsolation = *optIsolation;
807+
SP.P.consumeToken(tok::string_literal);
808+
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
809+
continue;
810+
} else if (section && SP.P.Tok.getText() == "section") {
789811
SP.P.consumeToken(tok::identifier);
790812
if (SP.P.Tok.getKind() != tok::string_literal) {
791813
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
@@ -799,8 +821,7 @@ static bool parseDeclSILOptional(
799821

800822
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
801823
continue;
802-
}
803-
else if (inlineStrategy && SP.P.Tok.getText() == "always_inline")
824+
} else if (inlineStrategy && SP.P.Tok.getText() == "always_inline")
804825
*inlineStrategy = AlwaysInline;
805826
else if (MRK && SP.P.Tok.getText() == "readnone")
806827
*MRK = EffectsKind::ReadNone;
@@ -7320,6 +7341,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
73207341
SILFunction *DynamicallyReplacedFunction = nullptr;
73217342
SILFunction *AdHocWitnessFunction = nullptr;
73227343
Identifier objCReplacementFor;
7344+
ActorIsolation actorIsolation;
73237345
if (parseSILLinkage(FnLinkage, P) ||
73247346
parseDeclSILOptional(
73257347
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
@@ -7330,8 +7352,9 @@ bool SILParserState::parseDeclSIL(Parser &P) {
73307352
&objCReplacementFor, &specialPurpose, &inlineStrategy,
73317353
&optimizationMode, &perfConstr, &isPerformanceConstraint,
73327354
&markedAsUsed, &section, nullptr, &isWeakImported,
7333-
&needStackProtection, nullptr, &availability, &isWithoutActuallyEscapingThunk,
7334-
&Semantics, &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
7355+
&needStackProtection, nullptr, &availability,
7356+
&isWithoutActuallyEscapingThunk, &Semantics, &SpecAttrs, &ClangDecl,
7357+
&MRK, &actorIsolation, FunctionState, M) ||
73357358
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
73367359
P.parseIdentifier(FnName, FnNameLoc, /*diagnoseDollarPrefix=*/false,
73377360
diag::expected_sil_function_name) ||
@@ -7391,6 +7414,8 @@ bool SILParserState::parseDeclSIL(Parser &P) {
73917414
for (auto &Attr : Semantics) {
73927415
FunctionState.F->addSemanticsAttr(Attr);
73937416
}
7417+
if (actorIsolation)
7418+
FunctionState.F->setActorIsolation(actorIsolation);
73947419
// Now that we have a SILFunction parse the body, if present.
73957420

73967421
bool isDefinition = false;
@@ -7580,11 +7605,11 @@ bool SILParserState::parseSILGlobal(Parser &P) {
75807605

75817606
SILParser State(P);
75827607
if (parseSILLinkage(GlobalLinkage, P) ||
7583-
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr,
7608+
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
75847609
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
75857610
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7611+
nullptr, nullptr, nullptr, nullptr, nullptr, &isLet,
75867612
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7587-
&isLet, nullptr, nullptr, nullptr, nullptr, nullptr,
75887613
nullptr, nullptr, nullptr, nullptr, State, M) ||
75897614
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
75907615
P.parseIdentifier(GlobalName, NameLoc, /*diagnoseDollarPrefix=*/false,
@@ -7638,7 +7663,7 @@ bool SILParserState::parseSILProperty(Parser &P) {
76387663
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
76397664
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
76407665
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7641-
nullptr, nullptr, nullptr, SP, M))
7666+
nullptr, nullptr, nullptr, nullptr, SP, M))
76427667
return true;
76437668

76447669
ValueDecl *VD;
@@ -7708,7 +7733,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
77087733
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
77097734
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
77107735
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7711-
nullptr, nullptr, nullptr, VTableState, M))
7736+
nullptr, nullptr, nullptr, nullptr, VTableState, M))
77127737
return true;
77137738

77147739

@@ -7831,7 +7856,8 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) {
78317856
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
78327857
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
78337858
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
7834-
nullptr, nullptr, nullptr, moveOnlyDeinitTableState, M))
7859+
nullptr, nullptr, nullptr, nullptr,
7860+
moveOnlyDeinitTableState, M))
78357861
return true;
78367862

78377863
// Parse the class name.
@@ -8371,12 +8397,12 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
83718397

83728398
SerializedKind_t isSerialized = IsNotSerialized;
83738399
bool isSpecialized = false;
8374-
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
8375-
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8376-
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8377-
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8378-
nullptr, nullptr, &isSpecialized, nullptr, nullptr, nullptr,
8379-
nullptr, nullptr, nullptr, WitnessState, M))
8400+
if (parseDeclSILOptional(
8401+
nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr,
8402+
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8403+
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
8404+
nullptr, nullptr, nullptr, nullptr, &isSpecialized, nullptr, nullptr,
8405+
nullptr, nullptr, nullptr, nullptr, nullptr, WitnessState, M))
83808406
return true;
83818407

83828408
// Parse the protocol conformance.

test/SIL/Parser/actor_isolation.sil

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %target-sil-opt -sil-print-function-isolation-info -enable-objc-interop -enable-sil-verify-all=true %s | %target-sil-opt -sil-print-function-isolation-info -enable-objc-interop -enable-sil-verify-all=true | %FileCheck %s
2+
3+
// REQUIRES: asserts
4+
5+
// CHECK: // func_with_caller_isolation_inheriting
6+
// CHECK: // Isolation: caller_isolation_inheriting
7+
// CHECK: sil [isolation "caller_isolation_inheriting"] @func_with_caller_isolation_inheriting : $@convention(thin) () -> () {
8+
sil [isolation "caller_isolation_inheriting"] @func_with_caller_isolation_inheriting : $@convention(thin) () -> () {
9+
bb0:
10+
%0 = tuple ()
11+
return %0 : $()
12+
}
13+
14+
// CHECK: // func_with_global_actor_isolation
15+
// CHECK: // Isolation: global_actor. type: <null>
16+
// CHECK: sil [isolation "global_actor"] @func_with_global_actor_isolation : $@convention(thin) () -> () {
17+
sil [isolation "global_actor"] @func_with_global_actor_isolation : $@convention(thin) () -> () {
18+
bb0:
19+
%0 = tuple ()
20+
return %0 : $()
21+
}
22+
23+
// CHECK: // func_with_actor_instance_isolation
24+
// CHECK: // Isolation: actor_instance
25+
// CHECK: sil [isolation "actor_instance"] @func_with_actor_instance_isolation : $@convention(thin) () -> () {
26+
sil [isolation "actor_instance"] @func_with_actor_instance_isolation : $@convention(thin) () -> () {
27+
bb0:
28+
%0 = tuple ()
29+
return %0 : $()
30+
}
31+
32+
// CHECK: // func_with_nonisolated_isolation
33+
// CHECK: // Isolation: nonisolated
34+
// CHECK: sil [isolation "nonisolated"] @func_with_nonisolated_isolation : $@convention(thin) () -> () {
35+
sil [isolation "nonisolated"] @func_with_nonisolated_isolation : $@convention(thin) () -> () {
36+
bb0:
37+
%0 = tuple ()
38+
return %0 : $()
39+
}

0 commit comments

Comments
 (0)