Skip to content

Commit 868fc6a

Browse files
committed
Basic SILGen for @isolated(any).
The main piece that's still missing here is support for closures; they actually mostly work, but they infer the wrong isolation for actor-isolated closures (it's not expressed in the type, so obviously they're non-isolated), so it's not really functional. We also have a significant problem where reabstraction thunks collide incorrectly because we don't mangle (or represent!) formal isolation into SILFunctionType; that's another follow-up. Otherwise, I think SILGen is working.
1 parent d35dcc8 commit 868fc6a

File tree

15 files changed

+482
-62
lines changed

15 files changed

+482
-62
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ ERROR(deserialize_function_type_mismatch,Fatal,
130130
"type mismatch of function '%0', declared as %1 but used in a swift module as %2",
131131
(StringRef, Type, Type))
132132

133+
ERROR(without_actually_escaping_on_isolated_any,none,
134+
"withoutActuallyEscaping is currently unimplemented for @isolated(any) "
135+
"function values", ())
136+
133137
// Capture before declaration diagnostics.
134138
ERROR(capture_before_declaration,none,
135139
"closure captures %0 before it is declared", (Identifier))

include/swift/AST/Types.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5512,10 +5512,10 @@ class SILFunctionType final
55125512
StringRef getMessage() const;
55135513
};
55145514

5515-
/// Returns no-error if this SILFunctionType is ABI compatible with \p
5516-
/// other. Otherwise, it returns a true error with a message in
5517-
/// std::error_code. This is only meant to be used in assertions. When
5518-
/// assertions are disabled, this just returns true.
5515+
/// Returns no-error if this SILFunctionType can be trivially
5516+
/// converted (i.e. without introducing a thunk) to the given
5517+
/// function type. Otherwise, it returns an error with a message in
5518+
/// std::error_code.
55195519
ABICompatibilityCheckResult
55205520
isABICompatibleWith(CanSILFunctionType other,
55215521
SILFunction &context) const;

include/swift/Demangling/TypeDecoder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,7 @@ class TypeDecoder {
866866
} else if (Node->getChild(firstChildIdx)->getKind() ==
867867
NodeKind::IsolatedAnyFunctionType) {
868868
extFlags = extFlags.withIsolatedAny();
869+
++firstChildIdx;
869870
}
870871

871872
FunctionMetadataDifferentiabilityKind diffKind;

include/swift/SIL/AbstractionPattern.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,16 @@ class AbstractionPattern {
15661566
bool ignoreFinalParam,
15671567
llvm::function_ref<void(FunctionParamGenerator &param)> function) const;
15681568

1569+
/// Return the start index of the given formal parameter in the lowered
1570+
/// parameter sequence corresponding to a function with this abstraction
1571+
/// pattern.
1572+
unsigned getLoweredParamIndex(unsigned formalIndex) const;
1573+
1574+
/// If this abstraction pattern is recursively expanded and flattened
1575+
/// in the normal way for parameters and results, how many values does
1576+
/// it correspond to?
1577+
unsigned getFlattenedValueCount() const;
1578+
15691579
/// Given that the value being abstracted is optional, return the
15701580
/// abstraction pattern for its object type.
15711581
AbstractionPattern getOptionalObjectType() const;

include/swift/SIL/SILInstruction.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3957,15 +3957,18 @@ class ExtractExecutorInst
39573957
};
39583958

39593959
/// Extract the isolation of an @isolated(any) function value.
3960+
///
3961+
/// The operand and result must always have guaranteed ownership.
39603962
class FunctionExtractIsolationInst
39613963
: public UnaryInstructionBase<SILInstructionKind::FunctionExtractIsolationInst,
3962-
SingleValueInstruction>
3964+
OwnershipForwardingSingleValueInstruction>
39633965
{
39643966
friend SILBuilder;
39653967

39663968
FunctionExtractIsolationInst(SILDebugLocation debugLoc, SILValue fnValue,
39673969
SILType type)
3968-
: UnaryInstructionBase(debugLoc, fnValue, type) { }
3970+
: UnaryInstructionBase(debugLoc, fnValue, type,
3971+
OwnershipKind::Guaranteed) { }
39693972

39703973
public:
39713974
SILValue getFunction() const { return getOperand(); }
@@ -11047,6 +11050,7 @@ OwnershipForwardingSingleValueInstruction::classof(SILInstructionKind kind) {
1104711050
case SILInstructionKind::BridgeObjectToRefInst:
1104811051
case SILInstructionKind::ThinToThickFunctionInst:
1104911052
case SILInstructionKind::UnconditionalCheckedCastInst:
11053+
case SILInstructionKind::FunctionExtractIsolationInst:
1105011054
return true;
1105111055
default:
1105211056
return false;

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,6 +1355,56 @@ CanType AbstractionPattern::getObjCMethodAsyncCompletionHandlerForeignType(
13551355
return foreignCHTy;
13561356
}
13571357

1358+
unsigned AbstractionPattern::getLoweredParamIndex(unsigned formalIndex) const {
1359+
switch (getKind()) {
1360+
// In the most general abstraction pattern, tuple parameters are
1361+
// not expanded, so the lowered parameter index matches the formal
1362+
// index.
1363+
case Kind::Opaque:
1364+
case Kind::OpaqueFunction:
1365+
case Kind::OpaqueDerivativeFunction:
1366+
return formalIndex;
1367+
1368+
case Kind::Type: {
1369+
// Total the flattened value count of the parameters prior to the
1370+
// given formal index.
1371+
unsigned loweredIndex = 0;
1372+
for (auto i : range(formalIndex)) {
1373+
loweredIndex += getFunctionParamType(i).getFlattenedValueCount();
1374+
}
1375+
return loweredIndex;
1376+
}
1377+
1378+
default:
1379+
// FIXME: to implement this, we'd need to adjust for the implicit
1380+
// rearrangement and hidden arguments that we can get from import.
1381+
// It's definitely doable, but it's currently unnecessary given the
1382+
// limited situations in which we use this method. I'm very sorry
1383+
// if you hit this time bomb.
1384+
llvm_unreachable("not yet implemented");
1385+
}
1386+
}
1387+
1388+
unsigned AbstractionPattern::getFlattenedValueCount() const {
1389+
// The count is always 1 unless the original type is a tuple.
1390+
if (!isTuple())
1391+
return 1;
1392+
1393+
// Add up the elements.
1394+
unsigned count = 0;
1395+
for (auto elt : getTupleElementTypes()) {
1396+
// Expansion components turn into a single pack parameter.
1397+
if (elt.isPackExpansion()) {
1398+
count++;
1399+
1400+
// Recursively expand scalar components.
1401+
} else {
1402+
count += elt.getFlattenedValueCount();
1403+
}
1404+
}
1405+
return count;
1406+
}
1407+
13581408
AbstractionPattern
13591409
AbstractionPattern::getFunctionParamType(unsigned index) const {
13601410
switch (getKind()) {

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3166,7 +3166,7 @@ CanSILFunctionType swift::buildSILFunctionThunkType(
31663166
if (fn->getLoweredFunctionType()->isPseudogeneric())
31673167
extInfoBuilder = extInfoBuilder.withIsPseudogeneric();
31683168

3169-
// Add the function type as the parameter.
3169+
// Add the formal parameters of the expected type to the thunk.
31703170
auto contextConvention =
31713171
fn->getTypeLowering(sourceType).isTrivial()
31723172
? ParameterConvention::Direct_Unowned
@@ -3175,6 +3175,17 @@ CanSILFunctionType swift::buildSILFunctionThunkType(
31753175
params.append(expectedType->getParameters().begin(),
31763176
expectedType->getParameters().end());
31773177

3178+
// Thunk functions can never be @isolated(any); we have to erase to that
3179+
// by partial application. Remove the attribute and add the capture
3180+
// parameter. This must always be the first capture.
3181+
if (extInfoBuilder.hasErasedIsolation()) {
3182+
extInfoBuilder = extInfoBuilder.withErasedIsolation(false);
3183+
auto paramTy = SILType::getOpaqueIsolationType(fn->getASTContext());
3184+
params.push_back({paramTy.getASTType(),
3185+
ParameterConvention::Direct_Guaranteed});
3186+
}
3187+
3188+
// The next capture is the source function.
31783189
if (!differentiationThunkKind ||
31793190
*differentiationThunkKind == DifferentiationThunkKind::Reabstraction) {
31803191
params.push_back({sourceType,
@@ -4839,6 +4850,10 @@ using ABICompatibilityCheckResult =
48394850
ABICompatibilityCheckResult
48404851
SILFunctionType::isABICompatibleWith(CanSILFunctionType other,
48414852
SILFunction &context) const {
4853+
// Most of the checks here are symmetric, but for those that aren't,
4854+
// the question is whether the ABI makes it safe to use a value of
4855+
// this type as if it had type `other`.
4856+
48424857
// The calling convention and function representation can't be changed.
48434858
if (getRepresentation() != other->getRepresentation())
48444859
return ABICompatibilityCheckResult::DifferentFunctionRepresentations;
@@ -4853,8 +4868,8 @@ SILFunctionType::isABICompatibleWith(CanSILFunctionType other,
48534868
}
48544869

48554870
// @isolated(any) imposes an additional requirement on the context
4856-
// storage and cannot be added.
4857-
if (other->hasErasedIsolation() != hasErasedIsolation())
4871+
// storage and cannot be added. It can safely be removed, however.
4872+
if (other->hasErasedIsolation() && !hasErasedIsolation())
48584873
return ABICompatibilityCheckResult::DifferentErasedIsolation;
48594874

48604875
// Check the results.
@@ -4908,11 +4923,14 @@ SILFunctionType::isABICompatibleWith(CanSILFunctionType other,
49084923

49094924
if (param1.getConvention() != param2.getConvention())
49104925
return {ABICompatibilityCheckResult::DifferingParameterConvention, i};
4926+
// Note that the diretionality here is reversed from the other cases
4927+
// because of contravariance: parameters of the *second* type will be
4928+
// trivially converted to be parameters of the *first* type.
49114929
if (!areABICompatibleParamsOrReturns(
4912-
param1.getSILStorageType(context.getModule(), this,
4913-
context.getTypeExpansionContext()),
49144930
param2.getSILStorageType(context.getModule(), other,
49154931
context.getTypeExpansionContext()),
4932+
param1.getSILStorageType(context.getModule(), this,
4933+
context.getTypeExpansionContext()),
49164934
&context))
49174935
return {ABICompatibilityCheckResult::ABIIncompatibleParameterType, i};
49184936
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7089,12 +7089,15 @@ void SILVTable::verify(const SILModule &M) const {
70897089

70907090
if (M.getStage() != SILStage::Lowered &&
70917091
!M.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
7092+
// Note the direction of the compatibility check: the witness
7093+
// function must be compatible with being used as the requirement
7094+
// type.
70927095
SILVerifier(*entry.getImplementation(), /*calleeCache=*/nullptr,
70937096
/*SingleFunction=*/true,
70947097
/*checkLinearLifetime=*/ false)
70957098
.requireABICompatibleFunctionTypes(
7096-
baseInfo.getSILType().castTo<SILFunctionType>(),
70977099
entry.getImplementation()->getLoweredFunctionType(),
7100+
baseInfo.getSILType().castTo<SILFunctionType>(),
70987101
"vtable entry for " + baseName + " must be ABI-compatible",
70997102
*entry.getImplementation());
71007103
}

lib/SILGen/SILGenApply.cpp

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,28 +2247,6 @@ ManagedValue SILGenFunction::emitStringLiteral(SILLocation loc,
22472247
// Argument Emission
22482248
//===----------------------------------------------------------------------===//
22492249

2250-
/// Count the number of SILParameterInfos that are needed in order to
2251-
/// pass the given argument.
2252-
static unsigned getFlattenedValueCount(AbstractionPattern origType) {
2253-
// The count is always 1 unless the original type is a tuple.
2254-
if (!origType.isTuple())
2255-
return 1;
2256-
2257-
// Add up the elements.
2258-
unsigned count = 0;
2259-
for (auto elt : origType.getTupleElementTypes()) {
2260-
// Expansion components turn into a single pack parameter.
2261-
if (elt.isPackExpansion()) {
2262-
count++;
2263-
2264-
// Recursively expand scalar components.
2265-
} else {
2266-
count += getFlattenedValueCount(elt);
2267-
}
2268-
}
2269-
return count;
2270-
}
2271-
22722250
/// Count the number of SILParameterInfos that are needed in order to
22732251
/// pass the given argument.
22742252
static unsigned getFlattenedValueCount(AbstractionPattern origType,
@@ -2277,7 +2255,7 @@ static unsigned getFlattenedValueCount(AbstractionPattern origType,
22772255
if (foreignSelf.isStatic())
22782256
return 0;
22792257

2280-
return getFlattenedValueCount(origType);
2258+
return origType.getFlattenedValueCount();
22812259
}
22822260

22832261
namespace {
@@ -3756,7 +3734,7 @@ class ArgEmitter {
37563734

37573735
void emitExpandedBorrowed(Expr *arg, AbstractionPattern origParamType) {
37583736
CanType substArgType = arg->getType()->getCanonicalType();
3759-
auto count = getFlattenedValueCount(origParamType);
3737+
auto count = origParamType.getFlattenedValueCount();
37603738
auto claimedParams = claimNextParameters(count);
37613739

37623740
SILType loweredSubstArgType = SGF.getLoweredType(substArgType);
@@ -5642,7 +5620,9 @@ RValue SILGenFunction::emitApply(
56425620
case ActorIsolation::ActorInstance:
56435621
if (unsigned paramIndex =
56445622
implicitActorHopTarget->getActorInstanceParameter()) {
5645-
executor = emitLoadActorExecutor(loc, args[paramIndex-1]);
5623+
auto isolatedIndex = calleeTypeInfo.origFormalType
5624+
->getLoweredParamIndex(paramIndex - 1);
5625+
executor = emitLoadActorExecutor(loc, args[isolatedIndex]);
56465626
} else {
56475627
executor = emitLoadActorExecutor(loc, args.back());
56485628
}
@@ -5654,7 +5634,8 @@ RValue SILGenFunction::emitApply(
56545634
break;
56555635

56565636
case ActorIsolation::Erased:
5657-
llvm_unreachable("hop to erased isolation currently unimplemented");
5637+
executor = emitLoadErasedExecutor(loc, fn);
5638+
break;
56585639

56595640
case ActorIsolation::Unspecified:
56605641
case ActorIsolation::Nonisolated:

0 commit comments

Comments
 (0)