[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.
This commit is contained in:
Michael Gottesman
2025-07-10 09:19:51 -07:00
parent a28d065893
commit ee3027c2ca
3 changed files with 98 additions and 19 deletions

View File

@@ -680,11 +680,13 @@ static bool parseDeclSILOptional(
SILFunction::Purpose *specialPurpose, Inline_t *inlineStrategy,
OptimizationMode *optimizationMode, PerformanceConstraints *perfConstraints,
bool *isPerformanceConstraint, bool *markedAsUsed, StringRef *section,
bool *isLet, bool *isWeakImported, bool *needStackProtection, bool *isSpecialized,
AvailabilityRange *availability, bool *isWithoutActuallyEscapingThunk,
bool *isLet, bool *isWeakImported, bool *needStackProtection,
bool *isSpecialized, AvailabilityRange *availability,
bool *isWithoutActuallyEscapingThunk,
SmallVectorImpl<std::string> *Semantics,
SmallVectorImpl<ParsedSpecAttr> *SpecAttrs, ValueDecl **ClangDecl,
EffectsKind *MRK, SILParser &SP, SILModule &M) {
EffectsKind *MRK, ActorIsolation *actorIsolation, SILParser &SP,
SILModule &M) {
while (SP.P.consumeIf(tok::l_square)) {
if (isLet && SP.P.Tok.is(tok::kw_let)) {
*isLet = true;
@@ -785,7 +787,27 @@ static bool parseDeclSILOptional(
*isPerformanceConstraint = true;
else if (markedAsUsed && SP.P.Tok.getText() == "used")
*markedAsUsed = true;
else if (section && SP.P.Tok.getText() == "section") {
else if (actorIsolation && SP.P.Tok.getText() == "isolation") {
SP.P.consumeToken(tok::identifier);
if (SP.P.Tok.getKind() != tok::string_literal) {
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
return true;
}
StringRef rawString = SP.P.Tok.getText().drop_front().drop_back();
// TODO: By using a raw string here, we can perhaps put in a simple string
// representation of an actor that can be parsed back. For now this is
// just a quick hack so we can write tests.
auto optIsolation = ActorIsolation::forSILString(
SP.P.Context.getIdentifier(rawString).str());
if (!optIsolation) {
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
return true;
}
*actorIsolation = *optIsolation;
SP.P.consumeToken(tok::string_literal);
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
continue;
} else if (section && SP.P.Tok.getText() == "section") {
SP.P.consumeToken(tok::identifier);
if (SP.P.Tok.getKind() != tok::string_literal) {
SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list);
@@ -799,8 +821,7 @@ static bool parseDeclSILOptional(
SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list);
continue;
}
else if (inlineStrategy && SP.P.Tok.getText() == "always_inline")
} else if (inlineStrategy && SP.P.Tok.getText() == "always_inline")
*inlineStrategy = AlwaysInline;
else if (MRK && SP.P.Tok.getText() == "readnone")
*MRK = EffectsKind::ReadNone;
@@ -7320,6 +7341,7 @@ bool SILParserState::parseDeclSIL(Parser &P) {
SILFunction *DynamicallyReplacedFunction = nullptr;
SILFunction *AdHocWitnessFunction = nullptr;
Identifier objCReplacementFor;
ActorIsolation actorIsolation;
if (parseSILLinkage(FnLinkage, P) ||
parseDeclSILOptional(
&isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA,
@@ -7330,8 +7352,9 @@ bool SILParserState::parseDeclSIL(Parser &P) {
&objCReplacementFor, &specialPurpose, &inlineStrategy,
&optimizationMode, &perfConstr, &isPerformanceConstraint,
&markedAsUsed, &section, nullptr, &isWeakImported,
&needStackProtection, nullptr, &availability, &isWithoutActuallyEscapingThunk,
&Semantics, &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) ||
&needStackProtection, nullptr, &availability,
&isWithoutActuallyEscapingThunk, &Semantics, &SpecAttrs, &ClangDecl,
&MRK, &actorIsolation, FunctionState, M) ||
P.parseToken(tok::at_sign, diag::expected_sil_function_name) ||
P.parseIdentifier(FnName, FnNameLoc, /*diagnoseDollarPrefix=*/false,
diag::expected_sil_function_name) ||
@@ -7391,6 +7414,8 @@ bool SILParserState::parseDeclSIL(Parser &P) {
for (auto &Attr : Semantics) {
FunctionState.F->addSemanticsAttr(Attr);
}
if (actorIsolation)
FunctionState.F->setActorIsolation(actorIsolation);
// Now that we have a SILFunction parse the body, if present.
bool isDefinition = false;
@@ -7580,11 +7605,11 @@ bool SILParserState::parseSILGlobal(Parser &P) {
SILParser State(P);
if (parseSILLinkage(GlobalLinkage, P) ||
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr,
parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, &isLet,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
&isLet, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, State, M) ||
P.parseToken(tok::at_sign, diag::expected_sil_value_name) ||
P.parseIdentifier(GlobalName, NameLoc, /*diagnoseDollarPrefix=*/false,
@@ -7638,7 +7663,7 @@ bool SILParserState::parseSILProperty(Parser &P) {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, SP, M))
nullptr, nullptr, nullptr, nullptr, SP, M))
return true;
ValueDecl *VD;
@@ -7708,7 +7733,7 @@ bool SILParserState::parseSILVTable(Parser &P) {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, VTableState, M))
nullptr, nullptr, nullptr, nullptr, VTableState, M))
return true;
@@ -7831,7 +7856,8 @@ bool SILParserState::parseSILMoveOnlyDeinit(Parser &parser) {
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, moveOnlyDeinitTableState, M))
nullptr, nullptr, nullptr, nullptr,
moveOnlyDeinitTableState, M))
return true;
// Parse the class name.
@@ -8371,12 +8397,12 @@ bool SILParserState::parseSILWitnessTable(Parser &P) {
SerializedKind_t isSerialized = IsNotSerialized;
bool isSpecialized = false;
if (parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, &isSpecialized, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, WitnessState, M))
if (parseDeclSILOptional(
nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, &isSpecialized, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr, WitnessState, M))
return true;
// Parse the protocol conformance.