From 1d230eee57cebcf2b33e0c947ffc37ef8cedeb1b Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 7 Apr 2022 17:19:55 +0900 Subject: [PATCH] [Distributed] Retain ad-hoc `decodeNextArgument` in distributed thunk SIL has to force emission of `decodeNextArgument` and its retainment, so IRGen can reference it in distributed function accessor. (cherry picked from commit 79ad9278b2a4825a3b025cb28a6287ec8ee69582) (cherry picked from commit 870c712bd0ee66ef85e623c4a577c2a9871c21c2) (cherry picked from commit dadf3011f98c182b26a20c2e5f4f370659f17d6f) (cherry picked from commit 4e2c059e209eb351779e5c89258f19155badf7c2) (cherry picked from commit 560e96fcbe9a1af31f97fdc92d10462b3ebd2a73) (cherry picked from commit 41a4ceae153817f47c48b6abedec0476a7b038a7) (cherry picked from commit 8c8360a6a1ddc97553b202e6ec7149ca1eb7551f) (cherry picked from commit fc662bc8e1b437ba588f2355b5d9dd0b7e6754bc) --- include/swift/AST/Decl.h | 4 +- include/swift/AST/DiagnosticsParse.def | 2 + include/swift/AST/DistributedDecl.h | 11 ++++ include/swift/SIL/SILFunction.h | 46 ++++++++++++----- lib/AST/DistributedDecl.cpp | 45 ++++++++++++++++ lib/IRGen/GenDistributed.cpp | 20 +++----- lib/SIL/IR/SILFunctionBuilder.cpp | 47 +++++++++-------- lib/SIL/IR/SILModule.cpp | 2 + lib/SIL/IR/SILPrinter.cpp | 6 +++ lib/SIL/Parser/ParseSIL.cpp | 36 ++++++++++--- lib/SILOptimizer/Analysis/CallerAnalysis.cpp | 6 ++- .../FunctionSignatureOpts.cpp | 1 + .../IPO/DeadFunctionElimination.cpp | 6 +++ lib/Serialization/DeserializeSIL.cpp | 27 +++++++--- lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SILFormat.h | 1 + lib/Serialization/SerializeSIL.cpp | 17 +++++-- .../Distributed/DistributedActorSystem.swift | 5 +- .../LocalTestingDistributedActorSystem.swift | 2 +- .../Inputs/FakeDistributedActorSystems.swift | 14 ++++- ...adhoc_requirement_not_optimized_away.swift | 51 +++++++++++++++++++ ...tributed_actor_accessor_thunks_32bit.swift | 13 ++--- ...tributed_actor_accessor_thunks_64bit.swift | 12 ++--- test/SILGen/distributed_thunk.swift | 4 +- 24 files changed, 285 insertions(+), 95 deletions(-) create mode 100644 test/Distributed/Runtime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index eed276f6774e9..76c1b148017ac 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -3554,10 +3554,10 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext { VarDecl *getDistributedActorIDProperty() const; /// Find the 'RemoteCallTarget.init(_:)' initializer function. - ConstructorDecl* getDistributedRemoteCallTargetInitFunction() const; + ConstructorDecl *getDistributedRemoteCallTargetInitFunction() const; /// Find the 'RemoteCallArgument(label:name:value:)' initializer function. - ConstructorDecl* getDistributedRemoteCallArgumentInitFunction() const; + ConstructorDecl *getDistributedRemoteCallArgumentInitFunction() const; /// Collect the set of protocols to which this type should implicitly /// conform, such as AnyObject (for classes). diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index e1493f59fff94..b123a92839780 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -682,6 +682,8 @@ ERROR(expected_sil_function_type, none, "sil function expected to have SIL function type", ()) ERROR(sil_dynamically_replaced_func_not_found,none, "dynamically replaced function not found %0", (Identifier)) +ERROR(sil_adhoc_requirement_witness_func_not_found,none, + "ad-hoc requirement witness function not found %0", (Identifier)) ERROR(sil_specialize_target_func_not_found,none, "_specialize target function not found %0", (Identifier)) ERROR(sil_availability_expected_version,none, diff --git a/include/swift/AST/DistributedDecl.h b/include/swift/AST/DistributedDecl.h index 68bf4b34e6baa..fe4ac4fdfb0d1 100644 --- a/include/swift/AST/DistributedDecl.h +++ b/include/swift/AST/DistributedDecl.h @@ -53,10 +53,21 @@ Type getDistributedActorIDType(NominalTypeDecl *actor); Type getDistributedSerializationRequirementType( NominalTypeDecl *nominal, ProtocolDecl *protocol); +/// Given a distributed thunk declaration, inside a 'distributed actor', +/// finds the ad-hoc witness for 'decodeNextArgument' on the associated +/// 'ActorSystem.InvocationDecoder' of the actor, or null. +AbstractFunctionDecl * +getAssociatedDistributedInvocationDecoderDecodeNextArgumentFunction( + ValueDecl *thunk); + /// Get the specific 'InvocationEncoder' type of a specific distributed actor /// system. Type getDistributedActorSystemInvocationEncoderType(NominalTypeDecl *system); +/// Get the specific 'InvocationDecoder' type of a specific distributed actor +/// system. +Type getDistributedActorSystemInvocationDecoderType(NominalTypeDecl *system); + /// Get the specific 'ResultHandler' type of a specific distributed actor /// system. Type getDistributedActorSystemResultHandlerType(NominalTypeDecl *system); diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index be958f54030fa..91bd00948a1f1 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -212,6 +212,17 @@ class SILFunction /// @_dynamicReplacement(for:) function. SILFunction *ReplacedFunction = nullptr; + /// This SILFunction REFerences an ad-hoc protocol requirement witness in + /// order to keep it alive, such that it main be obtained in IRGen. Without + /// this explicit reference, the witness would seem not-used, and not be + /// accessible for IRGen. + /// + /// Specifically, one such case is the DistributedTargetInvocationDecoder's + /// 'decodeNextArgument' which must be retained, as it is only used from IRGen + /// and such, appears as-if unused in SIL and would get optimized away. + // TODO: Consider making this a general "references adhoc functions" and make it an array? + SILFunction *RefAdHocRequirementFunction = nullptr; + Identifier ObjCReplacementFor; /// The head of a single-linked list of currently alive BasicBlockBitfield. @@ -298,7 +309,7 @@ class SILFunction /// Whether the implementation can be dynamically replaced. unsigned IsDynamicReplaceable : 1; - + /// If true, this indicates that a class method implementation will always be /// invoked with a `self` argument of the exact base class type. unsigned ExactSelfClass : 1; @@ -466,16 +477,6 @@ class SILFunction ReplacedFunction = f; ReplacedFunction->incrementRefCount(); } - - SILFunction *getDistributedRecordArgumentFunction() const { - return ReplacedFunction; - } - void setDistributedRecordArgumentFunction(SILFunction *f) { - if (f == nullptr) - return; - f->incrementRefCount(); - } - /// This function should only be called when SILFunctions are bulk deleted. void dropDynamicallyReplacedFunction() { if (!ReplacedFunction) @@ -484,6 +485,27 @@ class SILFunction ReplacedFunction = nullptr; } + SILFunction *getReferencedAdHocRequirementWitnessFunction() const { + return RefAdHocRequirementFunction; + } + // Marks that this `SILFunction` uses the passed in ad-hoc protocol + // requirement witness `f` and therefore must retain it explicitly, + // otherwise we might not be able to get a reference to it. + void setReferencedAdHocRequirementWitnessFunction(SILFunction *f) { + assert(RefAdHocRequirementFunction == nullptr && "already set"); + + if (f == nullptr) + return; + RefAdHocRequirementFunction = f; + RefAdHocRequirementFunction->incrementRefCount(); + } + void dropReferencedAdHocRequirementWitnessFunction() { + if (!RefAdHocRequirementFunction) + return; + RefAdHocRequirementFunction->decrementRefCount(); + RefAdHocRequirementFunction = nullptr; + } + bool hasObjCReplacement() const { return !ObjCReplacementFor.empty(); } @@ -758,7 +780,7 @@ class SILFunction IsDynamicReplaceable = value; assert(!Transparent || !IsDynamicReplaceable); } - + IsExactSelfClass_t isExactSelfClass() const { return IsExactSelfClass_t(ExactSelfClass); } diff --git a/lib/AST/DistributedDecl.cpp b/lib/AST/DistributedDecl.cpp index 24bf91675e214..d885515d9eae9 100644 --- a/lib/AST/DistributedDecl.cpp +++ b/lib/AST/DistributedDecl.cpp @@ -97,6 +97,10 @@ Type swift::getConcreteReplacementForProtocolActorSystemType(ValueDecl *member) } Type swift::getDistributedActorSystemType(NominalTypeDecl *actor) { + assert(!dyn_cast(actor) && + "Use getConcreteReplacementForProtocolActorSystemType instead to get" + "the concrete ActorSystem, if bound, for this DistributedActor " + "constrained ProtocolDecl!"); assert(actor->isDistributedActor()); auto &C = actor->getASTContext(); @@ -168,6 +172,21 @@ Type swift::getDistributedActorSystemInvocationEncoderType(NominalTypeDecl *syst return conformance.getTypeWitnessByName(selfType, ctx.Id_InvocationEncoder); } +Type swift::getDistributedActorSystemInvocationDecoderType(NominalTypeDecl *system) { + assert(!system->isDistributedActor()); + auto &ctx = system->getASTContext(); + + auto DAS = ctx.getDistributedActorSystemDecl(); + if (!DAS) + return Type(); + + // Dig out the serialization requirement type. + auto module = system->getParentModule(); + Type selfType = system->getSelfInterfaceType(); + auto conformance = module->lookupConformance(selfType, DAS); + return conformance.getTypeWitnessByName(selfType, ctx.Id_InvocationDecoder); +} + Type swift::getDistributedSerializationRequirementType( NominalTypeDecl *nominal, ProtocolDecl *protocol) { assert(nominal); @@ -184,6 +203,32 @@ Type swift::getDistributedSerializationRequirementType( return conformance.getTypeWitnessByName(selfType, ctx.Id_SerializationRequirement); } +AbstractFunctionDecl * +swift::getAssociatedDistributedInvocationDecoderDecodeNextArgumentFunction( + ValueDecl *thunk) { + assert(thunk); + auto &C = thunk->getASTContext(); + + auto *actor = thunk->getDeclContext()->getSelfNominalTypeDecl(); + if (!actor) + return nullptr; + if (!actor->isDistributedActor()) + return nullptr; + + auto systemTy = getConcreteReplacementForProtocolActorSystemType(thunk); + if (!systemTy) + return nullptr; + + auto decoderTy = + getDistributedActorSystemInvocationDecoderType( + systemTy->getAnyNominal()); + if (!decoderTy) + return nullptr; + + return C.getDecodeNextArgumentOnDistributedInvocationDecoder( + decoderTy->getAnyNominal()); +} + Type ASTContext::getAssociatedTypeOfDistributedSystemOfActor( NominalTypeDecl *actor, Identifier member) { auto &ctx = actor->getASTContext(); diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index b8af5db569682..481bd6b31218d 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -813,21 +813,13 @@ ArgumentDecoderInfo DistributedAccessor::findArgumentDecoder( decoder = instance.claimNext(); } - if (isa(decoderDecl) || isa(decoderDecl) || - decoderDecl->isFinal()) { - auto *decodeSIL = IGM.getSILModule().lookUpFunction(SILDeclRef(decodeFn)); - auto *fnPtr = IGM.getAddrOfSILFunction(decodeSIL, NotForDefinition, - /*isDynamicallyReplacible=*/false); + auto *decodeSIL = IGM.getSILModule().lookUpFunction(SILDeclRef(decodeFn)); + auto *fnPtr = IGM.getAddrOfSILFunction(decodeSIL, NotForDefinition, + /*isDynamicallyReplacible=*/false); - auto methodPtr = FunctionPointer::forDirect( - classifyFunctionPointerKind(decodeSIL), fnPtr, - /*secondaryValue=*/nullptr, signature); - - return {decoder, decoderTy, witnessTable, methodPtr, methodTy}; - } - - auto methodPtr = - emitVirtualMethodValue(IGF, decoderTy, SILDeclRef(decodeFn), methodTy); + auto methodPtr = FunctionPointer::forDirect( + classifyFunctionPointerKind(decodeSIL), fnPtr, + /*secondaryValue=*/nullptr, signature); return {decoder, decoderTy, witnessTable, methodPtr, methodTy}; } diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index 84dd94b8a1b07..b53ccec81e574 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -14,6 +14,7 @@ #include "swift/AST/AttrKind.h" #include "swift/AST/Availability.h" #include "swift/AST/DiagnosticsParse.h" +#include "swift/AST/DistributedDecl.h" #include "swift/AST/Decl.h" #include "swift/AST/ParameterList.h" #include "swift/AST/SemanticAttrs.h" @@ -200,29 +201,35 @@ void SILFunctionBuilder::addFunctionAttributes( // Only assign replacements when the thing being replaced is function-like and // explicitly declared. auto *origDecl = decl->getDynamicallyReplacedDecl(); - auto *replacedDecl = dyn_cast_or_null(origDecl); - if (!replacedDecl) - return; - - // For @objc method replacement we normally use categories to perform the - // replacement. Except for methods in generic class where we can't. Instead, - // we special case this and use the native swift replacement mechanism. - if (decl->isObjC() && !decl->isNativeMethodReplacement()) { - F->setObjCReplacement(replacedDecl); - return; - } - - if (!constant.canBeDynamicReplacement()) - return; + if (auto *replacedDecl = dyn_cast_or_null(origDecl)) { + // For @objc method replacement we normally use categories to perform the + // replacement. Except for methods in generic class where we can't. Instead, + // we special case this and use the native swift replacement mechanism. + if (decl->isObjC() && !decl->isNativeMethodReplacement()) { + F->setObjCReplacement(replacedDecl); + return; + } - SILDeclRef declRef(replacedDecl, constant.kind, false); - auto *replacedFunc = getOrCreateDeclaration(replacedDecl, declRef); + if (constant.canBeDynamicReplacement()) { + SILDeclRef declRef(replacedDecl, constant.kind, false); + auto *replacedFunc = getOrCreateDeclaration(replacedDecl, declRef); - assert(replacedFunc->getLoweredFunctionType() == - F->getLoweredFunctionType() || - replacedFunc->getLoweredFunctionType()->hasOpaqueArchetype()); + assert(replacedFunc->getLoweredFunctionType() == + F->getLoweredFunctionType() || + replacedFunc->getLoweredFunctionType()->hasOpaqueArchetype()); - F->setDynamicallyReplacedFunction(replacedFunc); + F->setDynamicallyReplacedFunction(replacedFunc); + } + } else if (constant.isDistributedThunk()) { + auto decodeFuncDecl = + getAssociatedDistributedInvocationDecoderDecodeNextArgumentFunction( + decl); + assert(decodeFuncDecl && "decodeNextArgument function not found!"); + + auto decodeRef = SILDeclRef(decodeFuncDecl); + auto *adHocFunc = getOrCreateDeclaration(decodeFuncDecl, decodeRef); + F->setReferencedAdHocRequirementWitnessFunction(adHocFunc); + } } SILFunction *SILFunctionBuilder::getOrCreateFunction( diff --git a/lib/SIL/IR/SILModule.cpp b/lib/SIL/IR/SILModule.cpp index 8bd442a03ddd8..7f4d95f57d099 100644 --- a/lib/SIL/IR/SILModule.cpp +++ b/lib/SIL/IR/SILModule.cpp @@ -138,6 +138,7 @@ SILModule::~SILModule() { for (SILFunction &F : *this) { F.dropAllReferences(); F.dropDynamicallyReplacedFunction(); + F.dropReferencedAdHocRequirementWitnessFunction(); F.clearSpecializeAttrs(); } @@ -467,6 +468,7 @@ void SILModule::eraseFunction(SILFunction *F) { // (References are not needed anymore.) F->clear(); F->dropDynamicallyReplacedFunction(); + F->dropReferencedAdHocRequirementWitnessFunction(); // Drop references for any _specialize(target:) functions. F->clearSpecializeAttrs(); } diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index bb7672342628d..06868d3fd0e9f 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2983,6 +2983,12 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { OS << "\"] "; } + if (auto *usedFunc = getReferencedAdHocRequirementWitnessFunction()) { + OS << "[ref_adhoc_requirement_witness \""; + OS << usedFunc->getName(); + OS << "\"] "; + } + if (hasObjCReplacement()) { OS << "[objc_replacement_for \""; OS << getObjCReplacement().str(); diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 3f8a75c19534f..0396343828c55 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -973,6 +973,7 @@ static bool parseDeclSILOptional(bool *isTransparent, IsDistributed_t *isDistributed, IsExactSelfClass_t *isExactSelfClass, SILFunction **dynamicallyReplacedFunction, + SILFunction **usedAdHocRequirementWitness, Identifier *objCReplacementFor, SILFunction::Purpose *specialPurpose, Inline_t *inlineStrategy, @@ -1069,7 +1070,7 @@ static bool parseDeclSILOptional(bool *isTransparent, *MRK = EffectsKind::ReadWrite; else if (MRK && SP.P.Tok.getText() == "releasenone") *MRK = EffectsKind::ReleaseNone; - else if (dynamicallyReplacedFunction && SP.P.Tok.getText() == "dynamic_replacement_for") { + else if (dynamicallyReplacedFunction && SP.P.Tok.getText() == "dynamic_replacement_for") { SP.P.consumeToken(tok::identifier); if (SP.P.Tok.getKind() != tok::string_literal) { SP.P.diagnose(SP.P.Tok, diag::expected_in_attribute_list); @@ -1087,6 +1088,26 @@ static bool parseDeclSILOptional(bool *isTransparent, *dynamicallyReplacedFunction = Func; SP.P.consumeToken(tok::string_literal); + SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); + continue; + } else if (usedAdHocRequirementWitness && SP.P.Tok.getText() == "ref_adhoc_requirement_witness") { + 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; + } + // Drop the double quotes. + StringRef witnessFunc = SP.P.Tok.getText().drop_front().drop_back(); + SILFunction *Func = M.lookUpFunction(witnessFunc.str()); + if (!Func) { + Identifier Id = SP.P.Context.getIdentifier(witnessFunc); + SP.P.diagnose(SP.P.Tok, diag::sil_adhoc_requirement_witness_func_not_found, + Id); + return true; + } + *usedAdHocRequirementWitness = Func; + SP.P.consumeToken(tok::string_literal); + SP.P.parseToken(tok::r_square, diag::expected_in_attribute_list); continue; } else if (objCReplacementFor && @@ -6335,12 +6356,13 @@ bool SILParserState::parseDeclSIL(Parser &P) { EffectsKind MRK = EffectsKind::Unspecified; llvm::SmallVector argEffectLocs; SILFunction *DynamicallyReplacedFunction = nullptr; + SILFunction *AdHocWitnessFunction = nullptr; Identifier objCReplacementFor; if (parseSILLinkage(FnLinkage, P) || parseDeclSILOptional( &isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA, &isThunk, &isDynamic, &isDistributed, &isExactSelfClass, - &DynamicallyReplacedFunction, &objCReplacementFor, &specialPurpose, + &DynamicallyReplacedFunction, &AdHocWitnessFunction, &objCReplacementFor, &specialPurpose, &inlineStrategy, &optimizationMode, &perfConstr, nullptr, &isWeakImported, &availability, &isWithoutActuallyEscapingThunk, &Semantics, @@ -6378,6 +6400,8 @@ bool SILParserState::parseDeclSIL(Parser &P) { FunctionState.F->setIsExactSelfClass(isExactSelfClass); FunctionState.F->setDynamicallyReplacedFunction( DynamicallyReplacedFunction); + FunctionState.F->setReferencedAdHocRequirementWitnessFunction( + AdHocWitnessFunction); if (!objCReplacementFor.empty()) FunctionState.F->setObjCReplacement(objCReplacementFor); FunctionState.F->setSpecialPurpose(specialPurpose); @@ -6571,7 +6595,7 @@ bool SILParserState::parseSILGlobal(Parser &P) { if (parseSILLinkage(GlobalLinkage, P) || parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, State, M) || P.parseToken(tok::at_sign, diag::expected_sil_value_name) || @@ -6624,7 +6648,7 @@ bool SILParserState::parseSILProperty(Parser &P) { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - SP, M)) + nullptr, SP, M)) return true; ValueDecl *VD; @@ -6694,7 +6718,7 @@ bool SILParserState::parseSILVTable(Parser &P) { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, VTableState, M)) + nullptr, nullptr, VTableState, M)) return true; // Parse the class name. @@ -7211,7 +7235,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, WitnessState, M)) + nullptr, nullptr, WitnessState, M)) return true; // Parse the protocol conformance. diff --git a/lib/SILOptimizer/Analysis/CallerAnalysis.cpp b/lib/SILOptimizer/Analysis/CallerAnalysis.cpp index 738d08ab79226..28ffc297ece5c 100644 --- a/lib/SILOptimizer/Analysis/CallerAnalysis.cpp +++ b/lib/SILOptimizer/Analysis/CallerAnalysis.cpp @@ -33,8 +33,10 @@ CallerAnalysis::FunctionInfo::FunctionInfo(SILFunction *f) : callerStates(), // TODO: Make this more aggressive by considering // final/visibility/etc. - mayHaveIndirectCallers(f->getDynamicallyReplacedFunction() || - canBeCalledIndirectly(f->getRepresentation())), + mayHaveIndirectCallers( + f->getDynamicallyReplacedFunction() || + f->getReferencedAdHocRequirementWitnessFunction() || + canBeCalledIndirectly(f->getRepresentation())), mayHaveExternalCallers(f->isPossiblyUsedExternally() || f->isAvailableExternally()) {} diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 8857f2d8aac7c..695596b117d55 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -646,6 +646,7 @@ bool FunctionSignatureTransform::run(bool hasCaller) { hasCaller |= FSOOptimizeIfNotCalled; if (!hasCaller && (F->getDynamicallyReplacedFunction() || + F->getReferencedAdHocRequirementWitnessFunction() || canBeCalledIndirectly(F->getRepresentation()))) { LLVM_DEBUG(llvm::dbgs() << " function has no caller -> abort\n"); return false; diff --git a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp index 3004339b6002e..9d9c642f2b95a 100644 --- a/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp +++ b/lib/SILOptimizer/IPO/DeadFunctionElimination.cpp @@ -101,6 +101,9 @@ class DeadFunctionAndGlobalElimination { if (F->isDynamicallyReplaceable()) return true; + if (F->getReferencedAdHocRequirementWitnessFunction()) + return true; + // Don't remove pre-specialized functions. We need to preserver the // pre-specialization specifications from other modules. if (F->hasPrespecialization()) @@ -325,6 +328,9 @@ class DeadFunctionAndGlobalElimination { LLVM_DEBUG(llvm::dbgs() << " scan function " << F->getName() << '\n'); + if (auto *adHocWitness = F->getReferencedAdHocRequirementWitnessFunction()) + ensureAlive(adHocWitness); + // First scan all instructions of the function. for (SILBasicBlock &BB : *F) { for (SILInstruction &I : BB) { diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 47010bce0d5d4..833bec1f14c17 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -521,9 +521,10 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, DeclID clangNodeOwnerID; TypeID funcTyID; IdentifierID replacedFunctionID; + IdentifierID usedAdHocWitnessFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), @@ -531,11 +532,12 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, specialPurpose, inlineStrategy, + isWithoutActuallyEscapingThunk, specialPurpose, inlineStrategy, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, isDistributed, funcTyID, replacedFunctionID, + isDynamic, isExactSelfClass, isDistributed, funcTyID, + replacedFunctionID, usedAdHocWitnessFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); if (funcTyID == 0) { @@ -566,6 +568,13 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, replacedObjectiveCFunc = MF->getIdentifier(replacedFunctionID); } + SILFunction *usedAdHocWitnessFunction = nullptr; + if (usedAdHocWitnessFunctionID) { + auto usedAdHocWitnessFunctionStr = + MF->getIdentifier(usedAdHocWitnessFunctionID).str(); + usedAdHocWitnessFunction = getFuncForReference(usedAdHocWitnessFunctionStr); + } + auto linkageOpt = fromStableSILLinkage(rawLinkage); if (!linkageOpt) { LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage @@ -646,7 +655,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setTransparent(IsTransparent_t(isTransparent == 1)); fn->setSerialized(IsSerialized_t(isSerialized)); fn->setThunk(IsThunk_t(isThunk)); - fn->setWithoutActuallyEscapingThunk(bool(isWithoutactuallyEscapingThunk)); + fn->setWithoutActuallyEscapingThunk(bool(isWithoutActuallyEscapingThunk)); fn->setInlineStrategy(Inline_t(inlineStrategy)); fn->setSpecialPurpose(SILFunction::Purpose(specialPurpose)); fn->setEffectsKind(EffectsKind(effect)); @@ -670,6 +679,8 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setDynamicallyReplacedFunction(replacedFunction); if (!replacedObjectiveCFunc.empty()) fn->setObjCReplacement(replacedObjectiveCFunc); + if (usedAdHocWitnessFunction) + fn->setReferencedAdHocRequirementWitnessFunction(usedAdHocWitnessFunction); if (clangNodeOwner) fn->setClangNodeOwner(clangNodeOwner); for (auto ID : SemanticsIDs) { @@ -2954,9 +2965,10 @@ bool SILDeserializer::hasSILFunction(StringRef Name, DeclID clangOwnerID; TypeID funcTyID; IdentifierID replacedFunctionID; + IdentifierID usedAdHocWitnessFunctionID; GenericSignatureID genericSigID; unsigned rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), @@ -2964,11 +2976,12 @@ bool SILDeserializer::hasSILFunction(StringRef Name, ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, - isWithoutactuallyEscapingThunk, isGlobal, inlineStrategy, + isWithoutActuallyEscapingThunk, isGlobal, inlineStrategy, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, isDistributed, funcTyID, replacedFunctionID, + isDynamic, isExactSelfClass, isDistributed, funcTyID, + replacedFunctionID, usedAdHocWitnessFunctionID, genericSigID, clangOwnerID, SemanticsIDs); auto linkage = fromStableSILLinkage(rawLinkage); if (!linkage) { diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 7275456bea892..a974011c7be4c 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -56,7 +56,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 685; // Primary associated types +const uint16_t SWIFTMODULE_VERSION_MINOR = 687; // RefAdHocRequirementFunction info in SILFunctionLayout /// A standard hash seed used for all string hashes in a serialized module. /// diff --git a/lib/Serialization/SILFormat.h b/lib/Serialization/SILFormat.h index c09024e80c982..2af2716d589d6 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -284,6 +284,7 @@ namespace sil_block { BCFixed<1>, // is distributed TypeIDField, // SILFunctionType DeclIDField, // SILFunction name or 0 (replaced function) + DeclIDField, // SILFunction name or 0 (used ad-hoc requirement witness function) GenericSignatureIDField, DeclIDField, // ClangNode owner BCArray // Semantics Attribute diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index e816999337443..07d26c8e88d85 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -462,12 +462,17 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { if (auto *fun = F.getDynamicallyReplacedFunction()) { addReferencedSILFunction(fun, true); replacedFunctionID = S.addUniquedStringRef(fun->getName()); - } - else if (F.hasObjCReplacement()) { + } else if (F.hasObjCReplacement()) { replacedFunctionID = S.addUniquedStringRef(F.getObjCReplacement().str()); } + IdentifierID usedAdHocWitnessFunctionID = 0; + if (auto *fun = F.getReferencedAdHocRequirementWitnessFunction()) { + addReferencedSILFunction(fun, true); + usedAdHocWitnessFunctionID = S.addUniquedStringRef(fun->getName()); + } + unsigned numAttrs = NoBody ? 0 : F.getSpecializeAttrs().size(); auto resilience = F.getModule().getSwiftModule()->getResilienceStrategy(); @@ -495,9 +500,11 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { (unsigned)F.hasCReferences(), (unsigned)F.getEffectsKind(), (unsigned)numAttrs, (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), - (unsigned)F.isDynamicallyReplaceable(), (unsigned)F.isExactSelfClass(), - (unsigned)F.isDistributed(), FnID, replacedFunctionID, genericSigID, - clangNodeOwnerID, SemanticsIDs); + (unsigned)F.isDynamicallyReplaceable(), + (unsigned)F.isExactSelfClass(), + (unsigned)F.isDistributed(), + FnID, replacedFunctionID, usedAdHocWitnessFunctionID, + genericSigID, clangNodeOwnerID, SemanticsIDs); F.visitArgEffects( [&](int effectIdx, bool isDerived, SILFunction::ArgEffectKind) { diff --git a/stdlib/public/Distributed/DistributedActorSystem.swift b/stdlib/public/Distributed/DistributedActorSystem.swift index 65fcf9c302a77..422a2f76144d3 100644 --- a/stdlib/public/Distributed/DistributedActorSystem.swift +++ b/stdlib/public/Distributed/DistributedActorSystem.swift @@ -27,10 +27,11 @@ public protocol DistributedActorSystem: Sendable { associatedtype ResultHandler: DistributedTargetInvocationResultHandler /// The serialization requirement that will be applied to all distributed targets used with this system. + // TODO: constrain SerializationRequirement in typesystem to only be ok with protocol or class here associatedtype SerializationRequirement where SerializationRequirement == InvocationEncoder.SerializationRequirement, - SerializationRequirement == InvocationDecoder.SerializationRequirement, - SerializationRequirement == ResultHandler.SerializationRequirement + SerializationRequirement == InvocationDecoder.SerializationRequirement, + SerializationRequirement == ResultHandler.SerializationRequirement // ==== --------------------------------------------------------------------- // - MARK: Resolving actors by identity diff --git a/stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift b/stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift index 094a9e06f1807..90c108c1f38f5 100644 --- a/stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift +++ b/stdlib/public/Distributed/LocalTestingDistributedActorSystem.swift @@ -170,7 +170,7 @@ public struct LocalTestingInvocationEncoder: DistributedTargetInvocationEncoder } @available(SwiftStdlib 5.7, *) -public class LocalTestingInvocationDecoder : DistributedTargetInvocationDecoder { +public final class LocalTestingInvocationDecoder: DistributedTargetInvocationDecoder { public typealias SerializationRequirement = Codable public func decodeGenericSubstitutions() throws -> [Any.Type] { diff --git a/test/Distributed/Inputs/FakeDistributedActorSystems.swift b/test/Distributed/Inputs/FakeDistributedActorSystems.swift index f864ac3929f84..8ee09b9a1bae9 100644 --- a/test/Distributed/Inputs/FakeDistributedActorSystems.swift +++ b/test/Distributed/Inputs/FakeDistributedActorSystems.swift @@ -36,6 +36,7 @@ public struct ActorAddress: Hashable, Sendable, Codable { // ==== Noop Transport --------------------------------------------------------- +@available(SwiftStdlib 5.7, *) public struct FakeActorSystem: DistributedActorSystem, CustomStringConvertible { public typealias ActorID = ActorAddress public typealias InvocationDecoder = FakeInvocationDecoder @@ -111,6 +112,7 @@ public struct FakeActorSystem: DistributedActorSystem, CustomStringConvertible { // ==== Fake Roundtrip Transport ----------------------------------------------- // TODO(distributed): not thread safe... +@available(SwiftStdlib 5.7, *) public final class FakeRoundtripActorSystem: DistributedActorSystem, @unchecked Sendable { public typealias ActorID = ActorAddress public typealias InvocationEncoder = FakeInvocationEncoder @@ -256,6 +258,7 @@ public final class FakeRoundtripActorSystem: DistributedActorSystem, @unchecked } +@available(SwiftStdlib 5.7, *) public struct FakeInvocationEncoder : DistributedTargetInvocationEncoder { public typealias SerializationRequirement = Codable @@ -300,7 +303,12 @@ public struct FakeInvocationEncoder : DistributedTargetInvocationEncoder { } // === decoding -------------------------------------------------------------- -public class FakeInvocationDecoder : DistributedTargetInvocationDecoder { + +// !!! WARNING !!! +// This is a 'final class' on purpose, to see that we retain the ad-hoc witness +// for 'decodeNextArgument'; Do not change it to just a class! +@available(SwiftStdlib 5.7, *) +public final class FakeInvocationDecoder: DistributedTargetInvocationDecoder { public typealias SerializationRequirement = Codable var genericSubs: [Any.Type] = [] @@ -353,7 +361,7 @@ public class FakeInvocationDecoder : DistributedTargetInvocationDecoder { } } -@available(SwiftStdlib 5.5, *) +@available(SwiftStdlib 5.7, *) public struct FakeRoundtripResultHandler: DistributedTargetInvocationResultHandler { public typealias SerializationRequirement = Codable @@ -382,9 +390,11 @@ public struct FakeRoundtripResultHandler: DistributedTargetInvocationResultHandl // ==== Helpers ---------------------------------------------------------------- +@available(SwiftStdlib 5.7, *) @_silgen_name("swift_distributed_actor_is_remote") func __isRemoteActor(_ actor: AnyObject) -> Bool +@available(SwiftStdlib 5.7, *) func __isLocalActor(_ actor: AnyObject) -> Bool { return !__isRemoteActor(actor) } diff --git a/test/Distributed/Runtime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift b/test/Distributed/Runtime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift new file mode 100644 index 0000000000000..03767a199b30d --- /dev/null +++ b/test/Distributed/Runtime/distributed_actor_cross_module_final_class_adhoc_requirement_not_optimized_away.swift @@ -0,0 +1,51 @@ +// RUN: %empty-directory(%t) +// RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 -parse-as-library -emit-library -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems %S/../Inputs/FakeDistributedActorSystems.swift -o %t/%target-library-name(FakeDistributedActorSystems) +// RUN: %target-build-swift -target %target-cpu-apple-macosx10.15 -parse-as-library -lFakeDistributedActorSystems -module-name main -I %t -L %t %s -o %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s --color + +// REQUIRES: OS=macosx && (CPU=x86_64 || CPU=arm64) +// REQUIRES: executable_test +// REQUIRES: concurrency +// REQUIRES: distributed + +// rdar://76038845 +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime + +// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574 +// UNSUPPORTED: windows + +import Distributed +import FakeDistributedActorSystems + +@available(SwiftStdlib 5.7, *) +typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem + +@available(SwiftStdlib 5.7, *) +distributed actor Greeter { + distributed func hello() -> String { + return "Hello, World!" + } +} + +@available(SwiftStdlib 5.7, *) +func test() async throws { + let system = DefaultDistributedActorSystem() + + let local = Greeter(actorSystem: system) + let ref = try Greeter.resolve(id: local.id, using: system) + + let response = try await ref.hello() + // CHECK: >> remoteCall: on:main.Greeter, target:main.Greeter.hello(), invocation:FakeInvocationEncoder(genericSubs: [], arguments: [], returnType: Optional(Swift.String), errorType: nil), throwing:Swift.Never, returning:Swift.String + + print("response: \(response)") + // CHECK: response: Hello, World! + +} + +@available(SwiftStdlib 5.7, *) +@main struct Main { + static func main() async { + try! await test() + } +} diff --git a/test/Distributed/distributed_actor_accessor_thunks_32bit.swift b/test/Distributed/distributed_actor_accessor_thunks_32bit.swift index b5c353f68670c..257a92d442d19 100644 --- a/test/Distributed/distributed_actor_accessor_thunks_32bit.swift +++ b/test/Distributed/distributed_actor_accessor_thunks_32bit.swift @@ -100,16 +100,9 @@ public distributed actor MyOtherActor { // CHECK: [[DECODER_PTR:%*]] = bitcast %swift.opaque* %1 to %T27FakeDistributedActorSystems0A17InvocationDecoderC** // CHECK-NEXT: [[DECODER:%.*]] = load %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %T27FakeDistributedActorSystems0A17InvocationDecoderC** [[DECODER_PTR]] -// CHECK-NEXT: [[DECODER_METADATA:%.*]] = bitcast %swift.type* [[DECODER_TYPE]] to void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)** -// CHECK-NEXT: [[DECODE_NEXT_ARG_REF:%.*]] = getelementptr inbounds void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)*, void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)** [[DECODER_METADATA]], i32 35 -// CHECK-NEXT: [[DECODE_NEXT_ARG:%.*]] = load void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)*, void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)** [[DECODE_NEXT_ARG_REF]] +// CHECK-NEXT: [[DECODER_METADATA:%.*]] = bitcast i8* %2 to %swift.type* +// CHECK-NEXT: [[DECODE_NEXT_ARG_REF:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[DECODER_METADATA]], i32 - -// CHECK: [[ARG_TYPES:%.*]] = bitcast i8* %2 to %swift.type** - -// CHECK: [[ARG_0_TYPE_LOC:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ARG_TYPES]], i32 0 -// CHECK-NEXT: %arg_type = load %swift.type*, %swift.type** [[ARG_0_TYPE_LOC]] -// CHECK: %size = load i32, i32* {{.*}} // CHECK: [[ARG_0_SIZE_ADJ:%.*]] = add i32 %size, 15 // CHECK-NEXT: [[ARG_0_SIZE:%.*]] = and i32 [[ARG_0_SIZE_ADJ]], -16 // CHECK-NEXT: [[ARG_0_VALUE_BUF:%.*]] = call swiftcc i8* @swift_task_alloc(i32 [[ARG_0_SIZE]]) @@ -126,7 +119,7 @@ public distributed actor MyOtherActor { // CHECK: missing-witness1: // CHECK-NEXT: call void @llvm.trap() // CHECK-NEXT: unreachable -// CHECK: call swiftcc void [[DECODE_NEXT_ARG]](%swift.opaque* noalias nocapture sret(%swift.opaque) [[ARG_0_RES_SLOT]], %swift.type* %arg_type, i8** [[ENCODABLE_WITNESS]], i8** [[DECODABLE_WITNESS]], %T27FakeDistributedActorSystems0A17InvocationDecoderC* swiftself [[DECODER]], %swift.error** noalias nocapture dereferenceable(4) %swifterror) +// CHECK: call swiftcc void @"$s27FakeDistributedActorSystems0A17InvocationDecoderC18decodeNextArgumentxyKSeRzSERzlF"(%swift.opaque* noalias nocapture sret(%swift.opaque) [[ARG_0_RES_SLOT]], %swift.type* %arg_type, i8** [[ENCODABLE_WITNESS]], i8** [[DECODABLE_WITNESS]], %T27FakeDistributedActorSystems0A17InvocationDecoderC* swiftself [[DECODER]], %swift.error** noalias nocapture dereferenceable(4) %swifterror) // CHECK: store %swift.error* null, %swift.error** %swifterror // CHECK-NEXT: [[ARG_0_VAL_ADDR:%.*]] = bitcast i8* [[ARG_0_VALUE_BUF]] to %TSi* diff --git a/test/Distributed/distributed_actor_accessor_thunks_64bit.swift b/test/Distributed/distributed_actor_accessor_thunks_64bit.swift index 0902003307832..39a07847651c9 100644 --- a/test/Distributed/distributed_actor_accessor_thunks_64bit.swift +++ b/test/Distributed/distributed_actor_accessor_thunks_64bit.swift @@ -100,15 +100,9 @@ public distributed actor MyOtherActor { // CHECK: [[DECODER_PTR:%*]] = bitcast %swift.opaque* %1 to %T27FakeDistributedActorSystems0A17InvocationDecoderC** // CHECK-NEXT: [[DECODER:%.*]] = load %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %T27FakeDistributedActorSystems0A17InvocationDecoderC** [[DECODER_PTR]] -// CHECK-NEXT: [[DECODER_METADATA:%.*]] = bitcast %swift.type* [[DECODER_TYPE]] to void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)** -// CHECK-NEXT: [[DECODE_NEXT_ARG_REF:%.*]] = getelementptr inbounds void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)*, void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)** [[DECODER_METADATA]], i64 {{29|32}} -// CHECK-NEXT: [[DECODE_NEXT_ARG:%.*]] = load void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)*, void (%swift.opaque*, %swift.type*, i8**, i8**, %T27FakeDistributedActorSystems0A17InvocationDecoderC*, %swift.error**)** [[DECODE_NEXT_ARG_REF]] +// CHECK-NEXT: [[DECODER_METADATA:%.*]] = bitcast i8* %2 to %swift.type* +// CHECK-NEXT: [[DECODE_NEXT_ARG_REF:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[DECODER_METADATA]], i64 -// CHECK-NEXT: [[ARG_TYPES:%.*]] = bitcast i8* %2 to %swift.type** - -// CHECK: [[ARG_0_TYPE_LOC:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ARG_TYPES]], i64 0 -// CHECK-NEXT: %arg_type = load %swift.type*, %swift.type** [[ARG_0_TYPE_LOC]] -// CHECK: %size = load i64, i64* {{.*}} // CHECK: [[ARG_0_SIZE_ADJ:%.*]] = add i64 %size, 15 // CHECK-NEXT: [[ARG_0_SIZE:%.*]] = and i64 [[ARG_0_SIZE_ADJ]], -16 // CHECK-NEXT: [[ARG_0_VALUE_BUF:%.*]] = call swiftcc i8* @swift_task_alloc(i64 [[ARG_0_SIZE]]) @@ -125,7 +119,7 @@ public distributed actor MyOtherActor { // CHECK: missing-witness1: // CHECK-NEXT: call void @llvm.trap() // CHECK-NEXT: unreachable -// CHECK: call swiftcc void [[DECODE_NEXT_ARG]](%swift.opaque* noalias nocapture sret(%swift.opaque) [[ARG_0_RES_SLOT]], %swift.type* %arg_type, i8** [[ENCODABLE_WITNESS]], i8** [[DECODABLE_WITNESS]], %T27FakeDistributedActorSystems0A17InvocationDecoderC* swiftself [[DECODER]], %swift.error** noalias nocapture swifterror dereferenceable(8) %swifterror) +// CHECK: call swiftcc void @"$s27FakeDistributedActorSystems0A17InvocationDecoderC18decodeNextArgumentxyKSeRzSERzlF"(%swift.opaque* noalias nocapture sret(%swift.opaque) [[ARG_0_RES_SLOT]], %swift.type* %arg_type, i8** [[ENCODABLE_WITNESS]], i8** [[DECODABLE_WITNESS]], %T27FakeDistributedActorSystems0A17InvocationDecoderC* swiftself [[DECODER]], %swift.error** noalias nocapture swifterror dereferenceable(8) %swifterror) // CHECK: store %swift.error* null, %swift.error** %swifterror // CHECK-NEXT: [[ARG_0_VAL_ADDR:%.*]] = bitcast i8* [[ARG_0_VALUE_BUF]] to %TSi* diff --git a/test/SILGen/distributed_thunk.swift b/test/SILGen/distributed_thunk.swift index 74185c37817e9..e0b0dd8f26e5f 100644 --- a/test/SILGen/distributed_thunk.swift +++ b/test/SILGen/distributed_thunk.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-silgen %s -enable-experimental-distributed -disable-availability-checking | %FileCheck %s --dump-input=fail +// RUN: %target-swift-emit-silgen %s -enable-experimental-distributed -disable-availability-checking | %FileCheck %s // REQUIRES: concurrency // REQUIRES: distributed @@ -9,7 +9,7 @@ distributed actor DA { } extension DA { - // CHECK-LABEL: sil hidden [thunk] [distributed] [ossa] @$s17distributed_thunk2DAC1fyyYaKFTE : $@convention(method) @async (@guaranteed DA) -> @error Error + // CHECK-LABEL: sil hidden [thunk] [distributed] [ref_adhoc_requirement_witness "$s11Distributed29LocalTestingInvocationDecoderC18decodeNextArgumentxyKSeRzSERzlF"] [ossa] @$s17distributed_thunk2DAC1fyyYaKFTE : $@convention(method) @async (@guaranteed DA) -> @error Error { // CHECK: function_ref @swift_distributed_actor_is_remote // Call the actor function