From 4860f90fd705d3514a73ec7b6d5878fc7d3c6ec4 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 17 Nov 2021 10:57:33 -0800 Subject: [PATCH 01/38] [SIL] Add new flag to `SILFunction` - `IsDistributed` Determines whether given SILFunction represents a distributed method or its thunk. --- include/swift/SIL/SILFunction.h | 22 ++++++++++++++-- include/swift/SIL/SILFunctionBuilder.h | 5 +++- include/swift/SIL/TypeSubstCloner.h | 2 +- lib/SIL/IR/SILFunction.cpp | 15 +++++++---- lib/SIL/IR/SILFunctionBuilder.cpp | 26 ++++++++++++------- lib/SIL/IR/SILPrinter.cpp | 3 +++ lib/SIL/Parser/ParseSIL.cpp | 20 +++++++++----- lib/SIL/Parser/SILParserFunctionBuilder.h | 2 +- lib/SILGen/SILGen.cpp | 5 ++-- lib/SILGen/SILGenBridging.cpp | 3 ++- lib/SILGen/SILGenExpr.cpp | 8 +++--- lib/SILGen/SILGenFunction.cpp | 4 +-- lib/SILGen/SILGenPoly.cpp | 3 ++- lib/SILGen/SILGenThunk.cpp | 10 ++++--- lib/SILGen/SILGenType.cpp | 8 +++--- .../Differentiation/JVPCloner.cpp | 3 ++- lib/SILOptimizer/Differentiation/Thunk.cpp | 6 ++--- .../Differentiation/VJPCloner.cpp | 2 +- .../ExistentialTransform.cpp | 6 ++--- .../FunctionSignatureOpts.cpp | 4 +-- lib/SILOptimizer/IPO/CapturePropagation.cpp | 6 ++--- lib/SILOptimizer/IPO/ClosureSpecializer.cpp | 4 +-- .../Mandatory/CapturePromotion.cpp | 2 +- .../Mandatory/Differentiation.cpp | 11 +++++--- .../Transforms/AllocBoxToStack.cpp | 3 ++- lib/SILOptimizer/Transforms/Outliner.cpp | 4 +-- .../UtilityPasses/BugReducerTester.cpp | 2 +- lib/SILOptimizer/Utils/GenericCloner.cpp | 4 +-- lib/SILOptimizer/Utils/Generics.cpp | 3 ++- lib/Serialization/DeserializeSIL.cpp | 13 +++++----- lib/Serialization/ModuleFormat.h | 2 +- lib/Serialization/SILFormat.h | 1 + .../SILSerializationFunctionBuilder.h | 4 +-- lib/Serialization/SerializeSIL.cpp | 3 ++- test/SIL/Parser/basic.sil | 7 +++++ test/SILGen/distributed_thunk.swift | 2 +- 36 files changed, 146 insertions(+), 82 deletions(-) diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index c2888227c87d4..b735222eeaccc 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -59,6 +59,10 @@ enum IsExactSelfClass_t { IsNotExactSelfClass, IsExactSelfClass, }; +enum IsDistributed_t { + IsNotDistributed, + IsDistributed, +}; enum class PerformanceConstraints : uint8_t { None = 0, @@ -294,6 +298,9 @@ class SILFunction /// invoked with a `self` argument of the exact base class type. unsigned ExactSelfClass : 1; + /// Check whether this is a distributed method. + unsigned IsDistributed : 1; + /// True if this function is inlined at least once. This means that the /// debug info keeps a pointer to this function. unsigned Inlined : 1; @@ -373,7 +380,8 @@ class SILFunction SubclassScope classSubclassScope, Inline_t inlineStrategy, EffectsKind E, const SILDebugScope *debugScope, IsDynamicallyReplaceable_t isDynamic, - IsExactSelfClass_t isExactSelfClass); + IsExactSelfClass_t isExactSelfClass, + IsDistributed_t isDistributed); static SILFunction * create(SILModule &M, SILLinkage linkage, StringRef name, @@ -381,6 +389,7 @@ class SILFunction Optional loc, IsBare_t isBareSILFunction, IsTransparent_t isTrans, IsSerialized_t isSerialized, ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic, + IsDistributed_t isDistributed, IsExactSelfClass_t isExactSelfClass, IsThunk_t isThunk = IsNotThunk, SubclassScope classSubclassScope = SubclassScope::NotApplicable, @@ -399,7 +408,8 @@ class SILFunction Inline_t inlineStrategy, EffectsKind E, const SILDebugScope *DebugScope, IsDynamicallyReplaceable_t isDynamic, - IsExactSelfClass_t isExactSelfClass); + IsExactSelfClass_t isExactSelfClass, + IsDistributed_t isDistributed); /// Set has ownership to the given value. True means that the function has /// ownership, false means it does not. @@ -747,6 +757,14 @@ class SILFunction ExactSelfClass = t; } + IsDistributed_t isDistributed() const { + return IsDistributed_t(IsDistributed); + } + void + setIsDistributed(IsDistributed_t value = IsDistributed_t::IsDistributed) { + IsDistributed = value; + } + /// Get the DeclContext of this function. DeclContext *getDeclContext() const { return DeclCtxt; } diff --git a/include/swift/SIL/SILFunctionBuilder.h b/include/swift/SIL/SILFunctionBuilder.h index b992fce2232c2..73d251ccd407d 100644 --- a/include/swift/SIL/SILFunctionBuilder.h +++ b/include/swift/SIL/SILFunctionBuilder.h @@ -67,7 +67,8 @@ class SILFunctionBuilder { IsSerialized_t isSerialized, ProfileCounter entryCount, IsThunk_t isThunk, - IsDynamicallyReplaceable_t isDynamic); + IsDynamicallyReplaceable_t isDynamic, + IsDistributed_t isDistributed); /// Return the declaration of a function, or create it if it doesn't exist. SILFunction *getOrCreateFunction( @@ -75,6 +76,7 @@ class SILFunctionBuilder { CanSILFunctionType type, IsBare_t isBareSILFunction, IsTransparent_t isTransparent, IsSerialized_t isSerialized, IsDynamicallyReplaceable_t isDynamic, + IsDistributed_t isDistributed, ProfileCounter entryCount = ProfileCounter(), IsThunk_t isThunk = IsNotThunk, SubclassScope subclassScope = SubclassScope::NotApplicable); @@ -102,6 +104,7 @@ class SILFunctionBuilder { Optional loc, IsBare_t isBareSILFunction, IsTransparent_t isTrans, IsSerialized_t isSerialized, IsDynamicallyReplaceable_t isDynamic, + IsDistributed_t isDistributed, ProfileCounter entryCount = ProfileCounter(), IsThunk_t isThunk = IsNotThunk, SubclassScope subclassScope = SubclassScope::NotApplicable, diff --git a/include/swift/SIL/TypeSubstCloner.h b/include/swift/SIL/TypeSubstCloner.h index 90c31bec1621f..b06104a1a283c 100644 --- a/include/swift/SIL/TypeSubstCloner.h +++ b/include/swift/SIL/TypeSubstCloner.h @@ -446,7 +446,7 @@ class TypeSubstCloner : public SILClonerWithScopes { ParentFunction->getLocation(), MangledName, SILLinkage::Shared, ParentFunction->getLoweredFunctionType(), ParentFunction->isBare(), ParentFunction->isTransparent(), ParentFunction->isSerialized(), - IsNotDynamic, 0, ParentFunction->isThunk(), + IsNotDynamic, IsNotDistributed, 0, ParentFunction->isThunk(), ParentFunction->getClassSubclassScope()); // Increment the ref count for the inlined function, so it doesn't // get deleted before we can emit abstract debug info for it. diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index fe90ca4fec84e..e4032b3548771 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -86,6 +86,7 @@ SILFunction::create(SILModule &M, SILLinkage linkage, StringRef name, IsBare_t isBareSILFunction, IsTransparent_t isTrans, IsSerialized_t isSerialized, ProfileCounter entryCount, IsDynamicallyReplaceable_t isDynamic, + IsDistributed_t isDistributed, IsExactSelfClass_t isExactSelfClass, IsThunk_t isThunk, SubclassScope classSubclassScope, Inline_t inlineStrategy, @@ -108,14 +109,15 @@ SILFunction::create(SILModule &M, SILLinkage linkage, StringRef name, // deleted. And afterwards the same specialization is created again. fn->init(linkage, name, loweredType, genericEnv, loc, isBareSILFunction, isTrans, isSerialized, entryCount, isThunk, classSubclassScope, - inlineStrategy, E, debugScope, isDynamic, isExactSelfClass); + inlineStrategy, E, debugScope, isDynamic, isExactSelfClass, + isDistributed); assert(fn->empty()); } else { fn = new (M) SILFunction(M, linkage, name, loweredType, genericEnv, loc, isBareSILFunction, isTrans, isSerialized, entryCount, isThunk, classSubclassScope, inlineStrategy, E, debugScope, - isDynamic, isExactSelfClass); + isDynamic, isExactSelfClass, isDistributed); } if (entry) entry->setValue(fn); @@ -139,12 +141,13 @@ SILFunction::SILFunction(SILModule &Module, SILLinkage Linkage, StringRef Name, Inline_t inlineStrategy, EffectsKind E, const SILDebugScope *DebugScope, IsDynamicallyReplaceable_t isDynamic, - IsExactSelfClass_t isExactSelfClass) + IsExactSelfClass_t isExactSelfClass, + IsDistributed_t isDistributed) : SwiftObjectHeader(registeredMetatype), Module(Module), Availability(AvailabilityContext::alwaysAvailable()) { init(Linkage, Name, LoweredType, genericEnv, Loc, isBareSILFunction, isTrans, isSerialized, entryCount, isThunk, classSubclassScope, inlineStrategy, - E, DebugScope, isDynamic, isExactSelfClass); + E, DebugScope, isDynamic, isExactSelfClass, isDistributed); // Set our BB list to have this function as its parent. This enables us to // splice efficiently basic blocks in between functions. @@ -161,7 +164,8 @@ void SILFunction::init(SILLinkage Linkage, StringRef Name, Inline_t inlineStrategy, EffectsKind E, const SILDebugScope *DebugScope, IsDynamicallyReplaceable_t isDynamic, - IsExactSelfClass_t isExactSelfClass) { + IsExactSelfClass_t isExactSelfClass, + IsDistributed_t isDistributed) { this->Name = Name; this->LoweredType = LoweredType; this->GenericEnv = genericEnv; @@ -180,6 +184,7 @@ void SILFunction::init(SILLinkage Linkage, StringRef Name, this->IsWeakImported = false; this->IsDynamicReplaceable = isDynamic; this->ExactSelfClass = isExactSelfClass; + this->IsDistributed = isDistributed; this->Inlined = false; this->Zombie = false; this->HasOwnership = true, diff --git a/lib/SIL/IR/SILFunctionBuilder.cpp b/lib/SIL/IR/SILFunctionBuilder.cpp index 65171d0aeb71a..1499e0d0f6914 100644 --- a/lib/SIL/IR/SILFunctionBuilder.cpp +++ b/lib/SIL/IR/SILFunctionBuilder.cpp @@ -21,7 +21,8 @@ using namespace swift; SILFunction *SILFunctionBuilder::getOrCreateFunction( SILLocation loc, StringRef name, SILLinkage linkage, CanSILFunctionType type, IsBare_t isBareSILFunction, IsTransparent_t isTransparent, IsSerialized_t isSerialized, - IsDynamicallyReplaceable_t isDynamic, ProfileCounter entryCount, + IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed, + ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope subclassScope) { assert(!type->isNoEscape() && "Function decls always have escaping types."); if (auto fn = mod.lookUpFunction(name)) { @@ -33,8 +34,8 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( auto fn = SILFunction::create(mod, linkage, name, type, nullptr, loc, isBareSILFunction, isTransparent, isSerialized, - entryCount, isDynamic, IsNotExactSelfClass, - isThunk, subclassScope); + entryCount, isDynamic, isDistributed, + IsNotExactSelfClass, isThunk, subclassScope); fn->setDebugScope(new (mod) SILDebugScope(loc, fn)); return fn; } @@ -229,9 +230,15 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction( IsTrans = IsNotTransparent; } + IsDistributed_t IsDistributed = IsDistributed_t::IsNotDistributed; + // Mark both distributed thunks and methods as distributed. + if (constant.hasFuncDecl() && constant.getFuncDecl()->isDistributed()) { + IsDistributed = IsDistributed_t::IsDistributed; + } + auto *F = SILFunction::create(mod, linkage, name, constantType, nullptr, None, IsNotBare, IsTrans, IsSer, entryCount, IsDyn, - IsNotExactSelfClass, + IsDistributed, IsNotExactSelfClass, IsNotThunk, constant.getSubclassScope(), inlineStrategy, EK); F->setDebugScope(new (mod) SILDebugScope(loc, F)); @@ -280,10 +287,10 @@ SILFunction *SILFunctionBuilder::getOrCreateSharedFunction( SILLocation loc, StringRef name, CanSILFunctionType type, IsBare_t isBareSILFunction, IsTransparent_t isTransparent, IsSerialized_t isSerialized, ProfileCounter entryCount, IsThunk_t isThunk, - IsDynamicallyReplaceable_t isDynamic) { + IsDynamicallyReplaceable_t isDynamic, IsDistributed_t isDistributed) { return getOrCreateFunction(loc, name, SILLinkage::Shared, type, isBareSILFunction, isTransparent, isSerialized, - isDynamic, entryCount, isThunk, + isDynamic, isDistributed, entryCount, isThunk, SubclassScope::NotApplicable); } @@ -292,12 +299,13 @@ SILFunction *SILFunctionBuilder::createFunction( GenericEnvironment *genericEnv, Optional loc, IsBare_t isBareSILFunction, IsTransparent_t isTrans, IsSerialized_t isSerialized, IsDynamicallyReplaceable_t isDynamic, - ProfileCounter entryCount, IsThunk_t isThunk, SubclassScope subclassScope, + IsDistributed_t isDistributed, ProfileCounter entryCount, + IsThunk_t isThunk, SubclassScope subclassScope, Inline_t inlineStrategy, EffectsKind EK, SILFunction *InsertBefore, const SILDebugScope *DebugScope) { return SILFunction::create(mod, linkage, name, loweredType, genericEnv, loc, isBareSILFunction, isTrans, isSerialized, - entryCount, isDynamic, IsNotExactSelfClass, - isThunk, subclassScope, + entryCount, isDynamic, isDistributed, + IsNotExactSelfClass, isThunk, subclassScope, inlineStrategy, EK, InsertBefore, DebugScope); } diff --git a/lib/SIL/IR/SILPrinter.cpp b/lib/SIL/IR/SILPrinter.cpp index f944283617e0a..f84715bac7798 100644 --- a/lib/SIL/IR/SILPrinter.cpp +++ b/lib/SIL/IR/SILPrinter.cpp @@ -2884,6 +2884,9 @@ void SILFunction::print(SILPrintContext &PrintCtx) const { if (isDynamicallyReplaceable()) { OS << "[dynamically_replacable] "; } + if (isDistributed()) { + OS << "[distributed] "; + } if (isExactSelfClass()) { OS << "[exact_self_class] "; } diff --git a/lib/SIL/Parser/ParseSIL.cpp b/lib/SIL/Parser/ParseSIL.cpp index 4b6d4bef91339..f7d5b7539ae2e 100644 --- a/lib/SIL/Parser/ParseSIL.cpp +++ b/lib/SIL/Parser/ParseSIL.cpp @@ -955,6 +955,7 @@ static bool parseDeclSILOptional(bool *isTransparent, bool *hasOwnershipSSA, IsThunk_t *isThunk, IsDynamicallyReplaceable_t *isDynamic, + IsDistributed_t *isDistributed, IsExactSelfClass_t *isExactSelfClass, SILFunction **dynamicallyReplacedFunction, Identifier *objCReplacementFor, @@ -987,6 +988,8 @@ static bool parseDeclSILOptional(bool *isTransparent, *isSerialized = IsSerialized; else if (isDynamic && SP.P.Tok.getText() == "dynamically_replacable") *isDynamic = IsDynamic; + else if (isDistributed && SP.P.Tok.getText() == "distributed") + *isDistributed = IsDistributed; else if (isExactSelfClass && SP.P.Tok.getText() == "exact_self_class") *isExactSelfClass = IsExactSelfClass; else if (isSerialized && SP.P.Tok.getText() == "serializable") @@ -6265,6 +6268,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { IsSerialized_t isSerialized = IsNotSerialized; bool isCanonical = false; IsDynamicallyReplaceable_t isDynamic = IsNotDynamic; + IsDistributed_t isDistributed = IsNotDistributed; IsExactSelfClass_t isExactSelfClass = IsNotExactSelfClass; bool hasOwnershipSSA = false; IsThunk_t isThunk = IsNotThunk; @@ -6284,9 +6288,10 @@ bool SILParserState::parseDeclSIL(Parser &P) { if (parseSILLinkage(FnLinkage, P) || parseDeclSILOptional( &isTransparent, &isSerialized, &isCanonical, &hasOwnershipSSA, - &isThunk, &isDynamic, &isExactSelfClass, &DynamicallyReplacedFunction, - &objCReplacementFor, &specialPurpose, &inlineStrategy, - &optimizationMode, &perfConstr, nullptr, &isWeakImported, &availability, + &isThunk, &isDynamic, &isDistributed, &isExactSelfClass, + &DynamicallyReplacedFunction, &objCReplacementFor, &specialPurpose, + &inlineStrategy, &optimizationMode, &perfConstr, nullptr, + &isWeakImported, &availability, &isWithoutActuallyEscapingThunk, &Semantics, &SpecAttrs, &ClangDecl, &MRK, FunctionState, M) || P.parseToken(tok::at_sign, diag::expected_sil_function_name) || @@ -6318,6 +6323,7 @@ bool SILParserState::parseDeclSIL(Parser &P) { FunctionState.F->setOwnershipEliminated(); FunctionState.F->setThunk(IsThunk_t(isThunk)); FunctionState.F->setIsDynamic(isDynamic); + FunctionState.F->setIsDistributed(isDistributed); FunctionState.F->setIsExactSelfClass(isExactSelfClass); FunctionState.F->setDynamicallyReplacedFunction( DynamicallyReplacedFunction); @@ -6495,7 +6501,7 @@ bool SILParserState::parseSILGlobal(Parser &P) { SILParser State(P); if (parseSILLinkage(GlobalLinkage, P) || parseDeclSILOptional(nullptr, &isSerialized, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &isLet, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, State, M) || @@ -6548,7 +6554,7 @@ bool SILParserState::parseSILProperty(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, 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, nullptr, SP, M)) return true; ValueDecl *VD; @@ -6617,7 +6623,7 @@ bool SILParserState::parseSILVTable(Parser &P) { if (parseDeclSILOptional(nullptr, &Serialized, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, VTableState, M)) return true; @@ -7134,7 +7140,7 @@ bool SILParserState::parseSILWitnessTable(Parser &P) { 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, nullptr, WitnessState, M)) return true; diff --git a/lib/SIL/Parser/SILParserFunctionBuilder.h b/lib/SIL/Parser/SILParserFunctionBuilder.h index 1714056902008..45667d023b26a 100644 --- a/lib/SIL/Parser/SILParserFunctionBuilder.h +++ b/lib/SIL/Parser/SILParserFunctionBuilder.h @@ -28,7 +28,7 @@ class LLVM_LIBRARY_VISIBILITY SILParserFunctionBuilder { SILLocation loc) { auto *result = builder.createFunction( SILLinkage::Private, name, ty, nullptr, loc, IsNotBare, - IsNotTransparent, IsNotSerialized, IsNotDynamic); + IsNotTransparent, IsNotSerialized, IsNotDynamic, IsNotDistributed); result->setDebugScope(new (builder.mod) SILDebugScope(loc, result)); return result; } diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 475585ee756cf..f3febf7c8ed8f 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -603,7 +603,8 @@ SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess, IsNotBare, IsNotTransparent, IsNotSerialized, - IsNotDynamic); + IsNotDynamic, + IsNotDistributed); return fn; } @@ -1622,7 +1623,7 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName, SILGenFunctionBuilder builder(*this); auto *f = builder.createFunction( SILLinkage::Private, funcName, initSILType, nullptr, SILLocation(binding), - IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic); + IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic, IsNotDistributed); f->setSpecialPurpose(SILFunction::Purpose::GlobalInitOnceFunction); f->setDebugScope(new (M) SILDebugScope(RegularLocation(binding), f)); auto dc = binding->getDeclContext(); diff --git a/lib/SILGen/SILGenBridging.cpp b/lib/SILGen/SILGenBridging.cpp index a2818560bb300..1d9b726e7ec3c 100644 --- a/lib/SILGen/SILGenBridging.cpp +++ b/lib/SILGen/SILGenBridging.cpp @@ -1523,7 +1523,8 @@ SILFunction *SILGenFunction::emitNativeAsyncToForeignThunk(SILDeclRef thunk) { F.isSerialized(), ProfileCounter(), IsThunk, - IsNotDynamic); + IsNotDynamic, + IsNotDistributed); auto closureRef = B.createFunctionRef(loc, closure); diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 9c8e71884cf25..a5efd1a041344 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2779,7 +2779,7 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM, (expansion == ResilienceExpansion::Minimal ? IsSerializable : IsNotSerialized), - ProfileCounter(), IsThunk, IsNotDynamic); + ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed); if (!thunk->empty()) return thunk; @@ -2927,7 +2927,7 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM, (expansion == ResilienceExpansion::Minimal ? IsSerializable : IsNotSerialized), - ProfileCounter(), IsThunk, IsNotDynamic); + ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed); if (!thunk->empty()) return thunk; @@ -3105,7 +3105,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, (expansion == ResilienceExpansion::Minimal ? IsSerializable : IsNotSerialized), - ProfileCounter(), IsThunk, IsNotDynamic); + ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed); if (!equals->empty()) { return; } @@ -3282,7 +3282,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM, (expansion == ResilienceExpansion::Minimal ? IsSerializable : IsNotSerialized), - ProfileCounter(), IsThunk, IsNotDynamic); + ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed); if (!hash->empty()) { return; } diff --git a/lib/SILGen/SILGenFunction.cpp b/lib/SILGen/SILGenFunction.cpp index 080e2582c56cd..e9fc159ef09d7 100644 --- a/lib/SILGen/SILGenFunction.cpp +++ b/lib/SILGen/SILGenFunction.cpp @@ -657,7 +657,7 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { auto NSStringFromClassFn = builder.getOrCreateFunction( mainClass, "NSStringFromClass", SILLinkage::PublicExternal, NSStringFromClassType, IsBare, IsTransparent, IsNotSerialized, - IsNotDynamic); + IsNotDynamic, IsNotDistributed); auto NSStringFromClass = B.createFunctionRef(mainClass, NSStringFromClassFn); SILValue metaTy = B.createMetatype(mainClass, SILType::getPrimitiveObjectType(mainClassMetaty)); @@ -747,7 +747,7 @@ void SILGenFunction::emitArtificialTopLevel(Decl *mainDecl) { auto NSApplicationMainFn = builder.getOrCreateFunction( mainClass, "NSApplicationMain", SILLinkage::PublicExternal, NSApplicationMainType, IsBare, IsTransparent, IsNotSerialized, - IsNotDynamic); + IsNotDynamic, IsNotDistributed); auto NSApplicationMain = B.createFunctionRef(mainClass, NSApplicationMainFn); SILValue args[] = { argc, argv }; diff --git a/lib/SILGen/SILGenPoly.cpp b/lib/SILGen/SILGenPoly.cpp index 5b55968d725a6..62c47e04629a8 100644 --- a/lib/SILGen/SILGenPoly.cpp +++ b/lib/SILGen/SILGenPoly.cpp @@ -3692,7 +3692,7 @@ ManagedValue SILGenFunction::getThunkedAutoDiffLinearMap( SILGenFunctionBuilder fb(SGM); auto *thunk = fb.getOrCreateSharedFunction( loc, name, thunkDeclType, IsBare, IsTransparent, IsSerialized, - ProfileCounter(), IsReabstractionThunk, IsNotDynamic); + ProfileCounter(), IsReabstractionThunk, IsNotDynamic, IsNotDistributed); // Partially-apply the thunk to `linearMap` and return the thunked value. auto getThunkedResult = [&]() { @@ -3961,6 +3961,7 @@ SILFunction *SILGenModule::getOrCreateCustomDerivativeThunk( loc, name, linkage, thunkFnTy, IsBare, IsNotTransparent, customDerivativeFn->isSerialized(), customDerivativeFn->isDynamicallyReplaceable(), + customDerivativeFn->isDistributed(), customDerivativeFn->getEntryCount(), IsThunk, customDerivativeFn->getClassSubclassScope()); // This thunk may be publicly exposed and cannot be transparent. diff --git a/lib/SILGen/SILGenThunk.cpp b/lib/SILGen/SILGenThunk.cpp index df5ad2a51506f..ff968bc6314dc 100644 --- a/lib/SILGen/SILGenThunk.cpp +++ b/lib/SILGen/SILGenThunk.cpp @@ -60,7 +60,8 @@ SILFunction *SILGenModule::getDynamicThunk(SILDeclRef constant, SILGenFunctionBuilder builder(*this); auto F = builder.getOrCreateFunction( constant.getDecl(), name, SILLinkage::Shared, constantTy, IsBare, - IsTransparent, IsSerializable, IsNotDynamic, ProfileCounter(), IsThunk); + IsTransparent, IsSerializable, IsNotDynamic, IsNotDistributed, + ProfileCounter(), IsThunk); if (F->empty()) { // Emit the thunk if we haven't yet. @@ -257,7 +258,8 @@ SILFunction *SILGenModule::getOrCreateForeignAsyncCompletionHandlerImplFunction( IsBare, IsTransparent, IsSerializable, ProfileCounter(), IsThunk, - IsNotDynamic); + IsNotDynamic, + IsNotDistributed); if (F->empty()) { // Emit the implementation. @@ -516,7 +518,7 @@ getOrCreateReabstractionThunk(CanSILFunctionType thunkType, SILGenFunctionBuilder builder(*this); return builder.getOrCreateSharedFunction( loc, name, thunkDeclType, IsBare, IsTransparent, serializable, - ProfileCounter(), IsReabstractionThunk, IsNotDynamic); + ProfileCounter(), IsReabstractionThunk, IsNotDynamic, IsNotDistributed); } SILFunction *SILGenModule::getOrCreateDerivativeVTableThunk( @@ -538,7 +540,7 @@ SILFunction *SILGenModule::getOrCreateDerivativeVTableThunk( auto *thunk = builder.getOrCreateFunction( derivativeFnDecl, name, SILLinkage::Private, constantTy, IsBare, IsTransparent, derivativeFnDeclRef.isSerialized(), IsNotDynamic, - ProfileCounter(), IsThunk); + IsNotDistributed, ProfileCounter(), IsThunk); if (!thunk->empty()) return thunk; diff --git a/lib/SILGen/SILGenType.cpp b/lib/SILGen/SILGenType.cpp index 114819a1d3241..1f095a281ba16 100644 --- a/lib/SILGen/SILGenType.cpp +++ b/lib/SILGen/SILGenType.cpp @@ -193,7 +193,7 @@ SILGenModule::emitVTableMethod(ClassDecl *theClass, SILLinkage::Private, name, overrideInfo.SILFnType, genericEnv, loc, IsBare, IsNotTransparent, IsNotSerialized, IsNotDynamic, - ProfileCounter(), IsThunk); + IsNotDistributed, ProfileCounter(), IsThunk); thunk->setDebugScope(new (M) SILDebugScope(loc, thunk)); PrettyStackTraceSILFunction trace("generating vtable thunk", thunk); @@ -784,8 +784,8 @@ SILFunction *SILGenModule::emitProtocolWitness( auto *f = builder.createFunction( linkage, nameBuffer, witnessSILFnType, genericEnv, SILLocation(witnessRef.getDecl()), IsNotBare, IsTransparent, isSerialized, - IsNotDynamic, ProfileCounter(), IsThunk, SubclassScope::NotApplicable, - InlineStrategy); + IsNotDynamic, IsNotDistributed, ProfileCounter(), IsThunk, + SubclassScope::NotApplicable, InlineStrategy); f->setDebugScope(new (M) SILDebugScope(RegularLocation(witnessRef.getDecl()), f)); @@ -856,7 +856,7 @@ static SILFunction *emitSelfConformanceWitness(SILGenModule &SGM, auto *f = builder.createFunction( linkage, name, witnessSILFnType, genericEnv, SILLocation(requirement.getDecl()), IsNotBare, IsTransparent, - IsSerialized, IsNotDynamic, ProfileCounter(), IsThunk, + IsSerialized, IsNotDynamic, IsNotDistributed, ProfileCounter(), IsThunk, SubclassScope::NotApplicable, InlineDefault); f->setDebugScope(new (SGM.M) diff --git a/lib/SILOptimizer/Differentiation/JVPCloner.cpp b/lib/SILOptimizer/Differentiation/JVPCloner.cpp index 13511db45d2e4..926ef1d900e50 100644 --- a/lib/SILOptimizer/Differentiation/JVPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/JVPCloner.cpp @@ -1704,7 +1704,8 @@ void JVPCloner::Implementation::prepareForDifferentialGeneration() { linkage, context.getASTContext().getIdentifier(diffName).str(), diffType, diffGenericEnv, original->getLocation(), original->isBare(), IsNotTransparent, jvp->isSerialized(), - original->isDynamicallyReplaceable()); + original->isDynamicallyReplaceable(), + original->isDistributed()); differential->setDebugScope( new (module) SILDebugScope(original->getLocation(), differential)); diff --git a/lib/SILOptimizer/Differentiation/Thunk.cpp b/lib/SILOptimizer/Differentiation/Thunk.cpp index 95932e9c7c2df..e9f5a88cafc7d 100644 --- a/lib/SILOptimizer/Differentiation/Thunk.cpp +++ b/lib/SILOptimizer/Differentiation/Thunk.cpp @@ -324,7 +324,7 @@ SILFunction *getOrCreateReabstractionThunk(SILOptFunctionBuilder &fb, auto *thunk = fb.getOrCreateSharedFunction( loc, name, thunkDeclType, IsBare, IsTransparent, IsSerialized, - ProfileCounter(), IsReabstractionThunk, IsNotDynamic); + ProfileCounter(), IsReabstractionThunk, IsNotDynamic, IsNotDistributed); if (!thunk->empty()) return thunk; @@ -582,7 +582,7 @@ getOrCreateSubsetParametersThunkForLinearMap( auto loc = parentThunk->getLocation(); auto *thunk = fb.getOrCreateSharedFunction( loc, thunkName, thunkType, IsBare, IsTransparent, IsSerialized, - ProfileCounter(), IsThunk, IsNotDynamic); + ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed); if (!thunk->empty()) return {thunk, interfaceSubs}; @@ -863,7 +863,7 @@ getOrCreateSubsetParametersThunkForDerivativeFunction( auto loc = origFnOperand.getLoc(); auto *thunk = fb.getOrCreateSharedFunction( loc, thunkName, thunkType, IsBare, IsTransparent, caller->isSerialized(), - ProfileCounter(), IsThunk, IsNotDynamic); + ProfileCounter(), IsThunk, IsNotDynamic, IsNotDistributed); if (!thunk->empty()) return {thunk, interfaceSubs}; diff --git a/lib/SILOptimizer/Differentiation/VJPCloner.cpp b/lib/SILOptimizer/Differentiation/VJPCloner.cpp index 840330d7230fb..2e07f82ef1767 100644 --- a/lib/SILOptimizer/Differentiation/VJPCloner.cpp +++ b/lib/SILOptimizer/Differentiation/VJPCloner.cpp @@ -996,7 +996,7 @@ SILFunction *VJPCloner::Implementation::createEmptyPullback() { linkage, context.getASTContext().getIdentifier(pbName).str(), pbType, pbGenericEnv, original->getLocation(), original->isBare(), IsNotTransparent, vjp->isSerialized(), - original->isDynamicallyReplaceable()); + original->isDynamicallyReplaceable(), original->isDistributed()); pullback->setDebugScope(new (module) SILDebugScope(original->getLocation(), pullback)); return pullback; diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp index 03ed4864d3306..47173c70b4aac 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/ExistentialTransform.cpp @@ -631,9 +631,9 @@ void ExistentialTransform::createExistentialSpecializedFunction() { NewF = FunctionBuilder.createFunction( linkage, Name, NewFTy, NewFGenericEnv, F->getLocation(), F->isBare(), - F->isTransparent(), F->isSerialized(), IsNotDynamic, F->getEntryCount(), - F->isThunk(), F->getClassSubclassScope(), F->getInlineStrategy(), - F->getEffectsKind(), nullptr, F->getDebugScope()); + F->isTransparent(), F->isSerialized(), IsNotDynamic, IsNotDistributed, + F->getEntryCount(), F->isThunk(), F->getClassSubclassScope(), + F->getInlineStrategy(), F->getEffectsKind(), nullptr, F->getDebugScope()); /// Set the semantics attributes for the new function. for (auto &Attr : F->getSemanticsAttrs()) diff --git a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp index 7f8754d6ed07a..5e7c98db5d7e8 100644 --- a/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp +++ b/lib/SILOptimizer/FunctionSignatureTransforms/FunctionSignatureOpts.cpp @@ -521,8 +521,8 @@ void FunctionSignatureTransform::createFunctionSignatureOptimizedFunction() { // classSubclassScope. TransformDescriptor.OptimizedFunction = FunctionBuilder.createFunction( linkage, Name, NewFTy, NewFGenericEnv, F->getLocation(), F->isBare(), - F->isTransparent(), F->isSerialized(), IsNotDynamic, F->getEntryCount(), - F->isThunk(), + F->isTransparent(), F->isSerialized(), IsNotDynamic, IsNotDistributed, + F->getEntryCount(), F->isThunk(), /*classSubclassScope=*/SubclassScope::NotApplicable, F->getInlineStrategy(), F->getEffectsKind(), nullptr, F->getDebugScope()); SILFunction *NewF = TransformDescriptor.OptimizedFunction.get(); diff --git a/lib/SILOptimizer/IPO/CapturePropagation.cpp b/lib/SILOptimizer/IPO/CapturePropagation.cpp index 2a9f2e9a9b477..8aff807cc96f6 100644 --- a/lib/SILOptimizer/IPO/CapturePropagation.cpp +++ b/lib/SILOptimizer/IPO/CapturePropagation.cpp @@ -262,9 +262,9 @@ SILFunction *CapturePropagation::specializeConstClosure(PartialApplyInst *PAI, SILFunction *NewF = FuncBuilder.createFunction( SILLinkage::Shared, Name, NewFTy, GenericEnv, OrigF->getLocation(), OrigF->isBare(), OrigF->isTransparent(), Serialized, IsNotDynamic, - OrigF->getEntryCount(), OrigF->isThunk(), OrigF->getClassSubclassScope(), - OrigF->getInlineStrategy(), OrigF->getEffectsKind(), - /*InsertBefore*/ OrigF, OrigF->getDebugScope()); + IsNotDistributed, OrigF->getEntryCount(), OrigF->isThunk(), + OrigF->getClassSubclassScope(), OrigF->getInlineStrategy(), + OrigF->getEffectsKind(), /*InsertBefore*/ OrigF, OrigF->getDebugScope()); if (!OrigF->hasOwnership()) { NewF->setOwnershipEliminated(); } diff --git a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp index f270b84c4aaa5..74d767c907893 100644 --- a/lib/SILOptimizer/IPO/ClosureSpecializer.cpp +++ b/lib/SILOptimizer/IPO/ClosureSpecializer.cpp @@ -693,8 +693,8 @@ ClosureSpecCloner::initCloned(SILOptFunctionBuilder &FunctionBuilder, getSpecializedLinkage(ClosureUser, ClosureUser->getLinkage()), ClonedName, ClonedTy, ClosureUser->getGenericEnvironment(), ClosureUser->getLocation(), IsBare, ClosureUser->isTransparent(), - CallSiteDesc.isSerialized(), IsNotDynamic, ClosureUser->getEntryCount(), - ClosureUser->isThunk(), + CallSiteDesc.isSerialized(), IsNotDynamic, IsNotDistributed, + ClosureUser->getEntryCount(), ClosureUser->isThunk(), /*classSubclassScope=*/SubclassScope::NotApplicable, ClosureUser->getInlineStrategy(), ClosureUser->getEffectsKind(), ClosureUser, ClosureUser->getDebugScope()); diff --git a/lib/SILOptimizer/Mandatory/CapturePromotion.cpp b/lib/SILOptimizer/Mandatory/CapturePromotion.cpp index 6ee1af50d6131..5dc665216f172 100644 --- a/lib/SILOptimizer/Mandatory/CapturePromotion.cpp +++ b/lib/SILOptimizer/Mandatory/CapturePromotion.cpp @@ -465,7 +465,7 @@ ClosureCloner::initCloned(SILOptFunctionBuilder &functionBuilder, auto *fn = functionBuilder.createFunction( orig->getLinkage(), clonedName, clonedTy, orig->getGenericEnvironment(), orig->getLocation(), orig->isBare(), IsNotTransparent, serialized, - IsNotDynamic, orig->getEntryCount(), orig->isThunk(), + IsNotDynamic, IsNotDistributed, orig->getEntryCount(), orig->isThunk(), orig->getClassSubclassScope(), orig->getInlineStrategy(), orig->getEffectsKind(), orig, orig->getDebugScope()); for (auto &attr : orig->getSemanticsAttrs()) diff --git a/lib/SILOptimizer/Mandatory/Differentiation.cpp b/lib/SILOptimizer/Mandatory/Differentiation.cpp index 23a57616a87d0..f7f6579f9404a 100644 --- a/lib/SILOptimizer/Mandatory/Differentiation.cpp +++ b/lib/SILOptimizer/Mandatory/Differentiation.cpp @@ -795,7 +795,8 @@ static SILFunction *createEmptyVJP(ADContext &context, witness->getLinkage(), context.getASTContext().getIdentifier(vjpName).str(), vjpType, vjpGenericEnv, original->getLocation(), original->isBare(), - IsNotTransparent, isSerialized, original->isDynamicallyReplaceable()); + IsNotTransparent, isSerialized, original->isDynamicallyReplaceable(), + original->isDistributed()); vjp->setDebugScope(new (module) SILDebugScope(original->getLocation(), vjp)); LLVM_DEBUG(llvm::dbgs() << "VJP type: " << vjp->getLoweredFunctionType() @@ -836,7 +837,8 @@ static SILFunction *createEmptyJVP(ADContext &context, witness->getLinkage(), context.getASTContext().getIdentifier(jvpName).str(), jvpType, jvpGenericEnv, original->getLocation(), original->isBare(), - IsNotTransparent, isSerialized, original->isDynamicallyReplaceable()); + IsNotTransparent, isSerialized, original->isDynamicallyReplaceable(), + original->isDistributed()); jvp->setDebugScope(new (module) SILDebugScope(original->getLocation(), jvp)); LLVM_DEBUG(llvm::dbgs() << "JVP type: " << jvp->getLoweredFunctionType() @@ -870,7 +872,7 @@ static void emitFatalError(ADContext &context, SILFunction *f, auto *fatalErrorFn = fnBuilder.getOrCreateFunction( loc, fatalErrorFuncName, SILLinkage::PublicExternal, fatalErrorFnType, IsNotBare, IsNotTransparent, IsNotSerialized, IsNotDynamic, - ProfileCounter(), IsNotThunk); + IsNotDistributed, ProfileCounter(), IsNotThunk); auto *fatalErrorFnRef = builder.createFunctionRef(loc, fatalErrorFn); builder.createApply(loc, fatalErrorFnRef, SubstitutionMap(), {}); builder.createUnreachable(loc); @@ -1029,7 +1031,8 @@ static SILValue promoteCurryThunkApplicationToDifferentiableFunction( auto *newThunk = fb.getOrCreateFunction( loc, newThunkName, getSpecializedLinkage(thunk, thunk->getLinkage()), thunkType, thunk->isBare(), thunk->isTransparent(), thunk->isSerialized(), - thunk->isDynamicallyReplaceable(), ProfileCounter(), thunk->isThunk()); + thunk->isDynamicallyReplaceable(), thunk->isDistributed(), + ProfileCounter(), thunk->isThunk()); // If new thunk is newly created: clone the old thunk body, wrap the // returned function value with an `differentiable_function` // instruction, and process the `differentiable_function` instruction. diff --git a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp index 0a0cff60a4b5e..caf1498c00013 100644 --- a/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp +++ b/lib/SILOptimizer/Transforms/AllocBoxToStack.cpp @@ -718,7 +718,8 @@ SILFunction *PromotedParamCloner::initCloned(SILOptFunctionBuilder &FuncBuilder, swift::getSpecializedLinkage(Orig, Orig->getLinkage()), ClonedName, ClonedTy, Orig->getGenericEnvironment(), Orig->getLocation(), Orig->isBare(), Orig->isTransparent(), Serialized, IsNotDynamic, - Orig->getEntryCount(), Orig->isThunk(), Orig->getClassSubclassScope(), + IsNotDistributed, Orig->getEntryCount(), Orig->isThunk(), + Orig->getClassSubclassScope(), Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig, Orig->getDebugScope()); for (auto &Attr : Orig->getSemanticsAttrs()) { diff --git a/lib/SILOptimizer/Transforms/Outliner.cpp b/lib/SILOptimizer/Transforms/Outliner.cpp index 70106b2997745..daa8aa407f787 100644 --- a/lib/SILOptimizer/Transforms/Outliner.cpp +++ b/lib/SILOptimizer/Transforms/Outliner.cpp @@ -334,7 +334,7 @@ BridgedProperty::outline(SILModule &M) { auto *Fun = FuncBuilder.getOrCreateFunction( ObjCMethod->getLoc(), name, SILLinkage::Shared, FunctionType, IsNotBare, - IsNotTransparent, IsSerializable, IsNotDynamic); + IsNotTransparent, IsSerializable, IsNotDynamic, IsNotDistributed); bool NeedsDefinition = Fun->empty(); if (Release) { @@ -1046,7 +1046,7 @@ ObjCMethodCall::outline(SILModule &M) { auto *Fun = FuncBuilder.getOrCreateFunction( ObjCMethod->getLoc(), name, SILLinkage::Shared, FunctionType, IsNotBare, - IsNotTransparent, IsSerializable, IsNotDynamic); + IsNotTransparent, IsSerializable, IsNotDynamic, IsNotDistributed); bool NeedsDefinition = Fun->empty(); // Call the outlined function. diff --git a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp index e616d6c9b75fc..fdda8c1ec1fbf 100644 --- a/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp +++ b/lib/SILOptimizer/UtilityPasses/BugReducerTester.cpp @@ -92,7 +92,7 @@ class BugReducerTester : public SILFunctionTransform { SILFunction *F = FunctionBuilder.getOrCreateSharedFunction( RegularLocation::getAutoGeneratedLocation(), RuntimeCrasherFunctionName, FuncType, IsBare, IsNotTransparent, IsSerialized, ProfileCounter(), - IsNotThunk, IsNotDynamic); + IsNotThunk, IsNotDynamic, IsNotDistributed); if (F->isDefinition()) return F; diff --git a/lib/SILOptimizer/Utils/GenericCloner.cpp b/lib/SILOptimizer/Utils/GenericCloner.cpp index 8513525c8e11c..7a0c8385de5b4 100644 --- a/lib/SILOptimizer/Utils/GenericCloner.cpp +++ b/lib/SILOptimizer/Utils/GenericCloner.cpp @@ -42,8 +42,8 @@ SILFunction *GenericCloner::createDeclaration( getSpecializedLinkage(Orig, Orig->getLinkage()), NewName, ReInfo.getSpecializedType(), ReInfo.getSpecializedGenericEnvironment(), Orig->getLocation(), Orig->isBare(), Orig->isTransparent(), - ReInfo.isSerialized(), IsNotDynamic, Orig->getEntryCount(), - Orig->isThunk(), Orig->getClassSubclassScope(), + ReInfo.isSerialized(), IsNotDynamic, IsNotDistributed, + Orig->getEntryCount(), Orig->isThunk(), Orig->getClassSubclassScope(), Orig->getInlineStrategy(), Orig->getEffectsKind(), Orig, Orig->getDebugScope()); for (auto &Attr : Orig->getSemanticsAttrs()) { diff --git a/lib/SILOptimizer/Utils/Generics.cpp b/lib/SILOptimizer/Utils/Generics.cpp index d22e37fabd2c2..44e0481c1df22 100644 --- a/lib/SILOptimizer/Utils/Generics.cpp +++ b/lib/SILOptimizer/Utils/Generics.cpp @@ -2201,7 +2201,8 @@ class ReabstractionThunkGenerator { SILFunction *ReabstractionThunkGenerator::createThunk() { SILFunction *Thunk = FunctionBuilder.getOrCreateSharedFunction( Loc, ThunkName, ReInfo.getSubstitutedType(), IsBare, IsTransparent, - ReInfo.isSerialized(), ProfileCounter(), IsThunk, IsNotDynamic); + ReInfo.isSerialized(), ProfileCounter(), IsThunk, IsNotDynamic, + IsNotDistributed); // Re-use an existing thunk. if (!Thunk->empty()) return Thunk; diff --git a/lib/Serialization/DeserializeSIL.cpp b/lib/Serialization/DeserializeSIL.cpp index 184b79646f09c..7c61557de8af9 100644 --- a/lib/Serialization/DeserializeSIL.cpp +++ b/lib/Serialization/DeserializeSIL.cpp @@ -529,7 +529,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass; + isDynamic, isExactSelfClass, isDistributed; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, @@ -537,8 +537,8 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, - clangNodeOwnerID, SemanticsIDs); + isDynamic, isExactSelfClass, isDistributed, funcTyID, replacedFunctionID, + genericSigID, clangNodeOwnerID, SemanticsIDs); if (funcTyID == 0) { LLVM_DEBUG(llvm::dbgs() << "SILFunction typeID is 0.\n"); @@ -672,6 +672,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn, fn->setIsDynamic(IsDynamicallyReplaceable_t(isDynamic)); fn->setIsExactSelfClass(IsExactSelfClass_t(isExactSelfClass)); + fn->setIsDistributed(IsDistributed_t(isDistributed)); if (replacedFunction) fn->setDynamicallyReplacedFunction(replacedFunction); if (!replacedObjectiveCFunc.empty()) @@ -2961,7 +2962,7 @@ bool SILDeserializer::hasSILFunction(StringRef Name, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass; + isDynamic, isExactSelfClass, isDistributed; ArrayRef SemanticsIDs; SILFunctionLayout::readRecord( scratch, rawLinkage, isTransparent, isSerialized, isThunk, @@ -2969,8 +2970,8 @@ bool SILDeserializer::hasSILFunction(StringRef Name, optimizationMode, perfConstr, subclassScope, hasCReferences, effect, numSpecAttrs, hasQualifiedOwnership, isWeakImported, LIST_VER_TUPLE_PIECES(available), - isDynamic, isExactSelfClass, funcTyID, replacedFunctionID, genericSigID, - clangOwnerID, SemanticsIDs); + isDynamic, isExactSelfClass, isDistributed, funcTyID, replacedFunctionID, + genericSigID, clangOwnerID, SemanticsIDs); auto linkage = fromStableSILLinkage(rawLinkage); if (!linkage) { LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 7ebb3a73c43ad..8742dd2f73d67 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 = 652; // @main cleanup +const uint16_t SWIFTMODULE_VERSION_MINOR = 653; // `IsDistributed` bit on SILFunction /// 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 b446fd91544dc..570843d139518 100644 --- a/lib/Serialization/SILFormat.h +++ b/lib/Serialization/SILFormat.h @@ -293,6 +293,7 @@ namespace sil_block { BC_AVAIL_TUPLE, // availability for weak linking BCFixed<1>, // is dynamically replacable BCFixed<1>, // exact self class + BCFixed<1>, // is distributed TypeIDField, // SILFunctionType DeclIDField, // SILFunction name or 0 (replaced function) GenericSignatureIDField, diff --git a/lib/Serialization/SILSerializationFunctionBuilder.h b/lib/Serialization/SILSerializationFunctionBuilder.h index 8bb8aab4be8e6..1e9e9c351c1f7 100644 --- a/lib/Serialization/SILSerializationFunctionBuilder.h +++ b/lib/Serialization/SILSerializationFunctionBuilder.h @@ -30,8 +30,8 @@ class LLVM_LIBRARY_VISIBILITY SILSerializationFunctionBuilder { return builder.createFunction( SILLinkage::Private, name, type.getAs(), nullptr, loc, IsNotBare, IsNotTransparent, - IsNotSerialized, IsNotDynamic, ProfileCounter(), IsNotThunk, - SubclassScope::NotApplicable); + IsNotSerialized, IsNotDynamic, IsNotDistributed, ProfileCounter(), + IsNotThunk, SubclassScope::NotApplicable); } void setHasOwnership(SILFunction *f, bool newValue) { diff --git a/lib/Serialization/SerializeSIL.cpp b/lib/Serialization/SerializeSIL.cpp index 9197739df346a..efedb34d3cd41 100644 --- a/lib/Serialization/SerializeSIL.cpp +++ b/lib/Serialization/SerializeSIL.cpp @@ -490,7 +490,8 @@ void SILSerializer::writeSILFunction(const SILFunction &F, bool DeclOnly) { (unsigned)numSpecAttrs, (unsigned)F.hasOwnership(), F.isAlwaysWeakImported(), LIST_VER_TUPLE_PIECES(available), (unsigned)F.isDynamicallyReplaceable(), (unsigned)F.isExactSelfClass(), - FnID, replacedFunctionID, genericSigID, clangNodeOwnerID, SemanticsIDs); + (unsigned)F.isDistributed(), FnID, replacedFunctionID, genericSigID, + clangNodeOwnerID, SemanticsIDs); if (NoBody) return; diff --git a/test/SIL/Parser/basic.sil b/test/SIL/Parser/basic.sil index fe64079ecb632..801a1baa1f719 100644 --- a/test/SIL/Parser/basic.sil +++ b/test/SIL/Parser/basic.sil @@ -1725,6 +1725,13 @@ bb0: return %0 : $() } +// CHECK-LABEL: sil hidden [distributed] @test_distributed_method +sil hidden [distributed] @test_distributed_method : $@convention(thin) () -> () { +bb0: + %0 = tuple () + return %0 : $() +} + struct EmptyStruct {} sil @test_empty_destructure : $@convention(thin) () -> () { diff --git a/test/SILGen/distributed_thunk.swift b/test/SILGen/distributed_thunk.swift index 396d032de4ac9..7f58eac6f23c9 100644 --- a/test/SILGen/distributed_thunk.swift +++ b/test/SILGen/distributed_thunk.swift @@ -9,7 +9,7 @@ distributed actor DA { } extension DA { - // CHECK-LABEL: sil hidden [thunk] [ossa] @$s17distributed_thunk2DAC1fyyFTE : $@convention(method) @async (@guaranteed DA) -> @error Error + // CHECK-LABEL: sil hidden [thunk] [distributed] [ossa] @$s17distributed_thunk2DAC1fyyFTE : $@convention(method) @async (@guaranteed DA) -> @error Error // CHECK: function_ref @swift_distributed_actor_is_remote // Call the actor function From b8358b26fe55914799ea2bf7722cb5ec8bfd5f0f Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 18 Nov 2021 16:05:54 -0800 Subject: [PATCH 02/38] [Mangling] Add mangling for distributed method accessors `Distributed Method Accessor` is a global helper function to get access to particular `distributed method` on an actor from outside the process. --- docs/ABI/Mangling.rst | 1 + include/swift/AST/ASTMangler.h | 1 + include/swift/Demangling/DemangleNodes.def | 1 + lib/AST/ASTMangler.cpp | 1 + lib/Demangling/Demangler.cpp | 2 ++ lib/Demangling/NodePrinter.cpp | 6 ++++++ lib/Demangling/OldRemangler.cpp | 6 ++++++ lib/Demangling/Remangler.cpp | 7 +++++++ test/Demangle/Inputs/manglings.txt | 1 + 9 files changed, 26 insertions(+) diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 3b08b3266fdd6..ec48374e23c2c 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -218,6 +218,7 @@ types where the metadata itself has unknown layout.) global ::= global 'TD' // dynamic dispatch thunk global ::= global 'Td' // direct method reference thunk global ::= global 'TE' // distributed actor thunk + global ::= global 'TF' // distributed method accessor global ::= global 'TI' // implementation of a dynamic_replaceable function global ::= global 'Tu' // async function pointer of a function global ::= global 'TX' // function pointer of a dynamic_replaceable function diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 134085c1f7789..268239efe6b75 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -104,6 +104,7 @@ class ASTMangler : public Mangler { SwiftAsObjCThunk, ObjCAsSwiftThunk, DistributedThunk, + DistributedMethodAccessor }; ASTMangler(bool DWARFMangling = false) diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index d357c5c42c535..2cb3e50b5722b 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -71,6 +71,7 @@ CONTEXT_NODE(Destructor) CONTEXT_NODE(DidSet) NODE(Directness) NODE(DistributedThunk) +NODE(DistributedMethodAccessor) NODE(DynamicAttribute) NODE(DirectMethodReferenceAttribute) NODE(DynamicSelf) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 3bdbdc7af9e19..38553756a7f25 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -849,6 +849,7 @@ void ASTMangler::appendSymbolKind(SymbolKind SKind) { case SymbolKind::SwiftAsObjCThunk: return appendOperator("To"); case SymbolKind::ObjCAsSwiftThunk: return appendOperator("TO"); case SymbolKind::DistributedThunk: return appendOperator("TE"); + case SymbolKind::DistributedMethodAccessor: return appendOperator("TF"); } } diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index 90953faf46d36..c58fb863f9b15 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -133,6 +133,7 @@ bool swift::Demangle::isFunctionAttr(Node::Kind kind) { case Node::Kind::OutlinedBridgedMethod: case Node::Kind::MergedFunction: case Node::Kind::DistributedThunk: + case Node::Kind::DistributedMethodAccessor: case Node::Kind::DynamicallyReplaceableFunctionImpl: case Node::Kind::DynamicallyReplaceableFunctionKey: case Node::Kind::DynamicallyReplaceableFunctionVar: @@ -2363,6 +2364,7 @@ NodePointer Demangler::demangleThunkOrSpecialization() { case 'D': return createNode(Node::Kind::DynamicAttribute); case 'd': return createNode(Node::Kind::DirectMethodReferenceAttribute); case 'E': return createNode(Node::Kind::DistributedThunk); + case 'F': return createNode(Node::Kind::DistributedMethodAccessor); case 'a': return createNode(Node::Kind::PartialApplyObjCForwarder); case 'A': return createNode(Node::Kind::PartialApplyForwarder); case 'm': return createNode(Node::Kind::MergedFunction); diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 216fd2d5d456f..17be1d6b6cbef 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -559,6 +559,7 @@ class NodePrinter { case Node::Kind::ProtocolConformanceRefInProtocolModule: case Node::Kind::ProtocolConformanceRefInOtherModule: case Node::Kind::DistributedThunk: + case Node::Kind::DistributedMethodAccessor: case Node::Kind::DynamicallyReplaceableFunctionKey: case Node::Kind::DynamicallyReplaceableFunctionImpl: case Node::Kind::DynamicallyReplaceableFunctionVar: @@ -1997,6 +1998,11 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, Printer << "distributed thunk for "; } return nullptr; + case Node::Kind::DistributedMethodAccessor: + if (!Options.ShortenThunk) { + Printer << "distributed method accessor for "; + } + return nullptr; case Node::Kind::DynamicallyReplaceableFunctionKey: if (!Options.ShortenThunk) { Printer << "dynamically replaceable key for "; diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index 7240aa4e198b1..18f317fb3a94d 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -735,6 +735,12 @@ Remangler::mangleDistributedThunk(Node *node, unsigned depth) { return ManglingError::Success; } +ManglingError +Remangler::mangleDistributedMethodAccessor(Node *node, unsigned depth) { + Buffer << "TF"; + return ManglingError::Success; +} + ManglingError Remangler::mangleDynamicallyReplaceableFunctionImpl(Node *node, unsigned depth) { diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 1dc2ee9a6186d..ab99098dfbd02 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -1611,6 +1611,7 @@ ManglingError Remangler::mangleGlobal(Node *node, unsigned depth) { case Node::Kind::DirectMethodReferenceAttribute: case Node::Kind::MergedFunction: case Node::Kind::DistributedThunk: + case Node::Kind::DistributedMethodAccessor: case Node::Kind::DynamicallyReplaceableFunctionKey: case Node::Kind::DynamicallyReplaceableFunctionImpl: case Node::Kind::DynamicallyReplaceableFunctionVar: @@ -2248,6 +2249,12 @@ Remangler::mangleDistributedThunk(Node *node, unsigned depth) { return ManglingError::Success; } +ManglingError +Remangler::mangleDistributedMethodAccessor(Node *node, unsigned depth) { + Buffer << "TF"; + return ManglingError::Success; +} + ManglingError Remangler::mangleDynamicallyReplaceableFunctionImpl(Node *node, unsigned depth) { diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index 17001295459e5..a7ef9b27740d8 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -421,3 +421,4 @@ $s13__lldb_expr_110$10016c2d8yXZ1B10$10016c2e0LLC ---> __lldb_expr_1.(unknown co $s__TJO ---> $s__TJO $s6Foobar7Vector2VAASdRszlE10simdMatrix5scale6rotate9translateSo0C10_double3x3aACySdG_SdAJtFZ0D4TypeL_aySd__GD ---> MatrixType #1 in static (extension in Foobar):Foobar.Vector2.simdMatrix(scale: Foobar.Vector2, rotate: Swift.Double, translate: Foobar.Vector2) -> __C.simd_double3x3 $s17distributed_thunk2DAC1fyyFTE ---> distributed thunk for distributed_thunk.DA.f() -> () +$s16distributed_test1XC7computeyS2iFTF ---> distributed method accessor for distributed_test.X.compute(Swift.Int) -> Swift.Int From 9ebdf36ca67598c46defc1b4af5241935aaf183b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 19 Nov 2021 12:23:17 -0800 Subject: [PATCH 03/38] [IRGen] Add skeleton implementation of distributed method accessor --- include/swift/IRGen/Linking.h | 15 ++++++- lib/IRGen/GenDistributed.cpp | 82 ++++++++++++++++++++++++++++++++++- lib/IRGen/IRGenModule.h | 6 +++ lib/IRGen/IRGenSIL.cpp | 5 +++ lib/IRGen/Linking.cpp | 19 +++++++- 5 files changed, 123 insertions(+), 4 deletions(-) diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 1191f1024a706..ef1b87d79eed4 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -481,6 +481,9 @@ class LinkEntity { /// name is known. /// The pointer is a const char* of the name. KnownAsyncFunctionPointer, + + /// The pointer is SILFunction* + DistributedMethodAccessor, }; friend struct llvm::DenseMapInfo; @@ -1263,6 +1266,15 @@ class LinkEntity { return entity; } + static LinkEntity forDistributedMethodAccessor(SILFunction *method) { + LinkEntity entity; + entity.Pointer = method; + entity.SecondaryPointer = nullptr; + entity.Data = + LINKENTITY_SET_FIELD(Kind, unsigned(Kind::DistributedMethodAccessor)); + return entity; + } + LinkEntity getUnderlyingEntityForAsyncFunctionPointer() const { LinkEntity entity; entity.Pointer = Pointer; @@ -1341,7 +1353,8 @@ class LinkEntity { return getKind() == Kind::AsyncFunctionPointer || getKind() == Kind::DynamicallyReplaceableFunctionVariable || getKind() == Kind::DynamicallyReplaceableFunctionKey || - getKind() == Kind::SILFunction; + getKind() == Kind::SILFunction || + getKind() == Kind::DistributedMethodAccessor; } SILFunction *getSILFunction() const { diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 135d6966864c4..6e562887bbf3d 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -19,6 +19,7 @@ #include "BitPatternBuilder.h" #include "ClassTypeInfo.h" #include "ExtraInhabitants.h" +#include "GenDecl.h" #include "GenProto.h" #include "GenType.h" #include "IRGenDebugInfo.h" @@ -26,8 +27,11 @@ #include "IRGenModule.h" #include "LoadableTypeInfo.h" #include "ScalarPairTypeInfo.h" -#include "swift/AST/ProtocolConformanceRef.h" #include "swift/ABI/MetadataValues.h" +#include "swift/AST/ExtInfo.h" +#include "swift/AST/ProtocolConformanceRef.h" +#include "swift/IRGen/Linking.h" +#include "swift/SIL/SILFunction.h" using namespace swift; using namespace irgen; @@ -53,3 +57,79 @@ llvm::Value *irgen::emitDistributedActorInitializeRemote( return result; } + +namespace { + +class DistributedAccessor { + IRGenFunction &IGF; + + /// Underlying distributed method for this accessor. + SILFunction *Method; + +public: + DistributedAccessor(IRGenFunction &IGF, SILFunction *method); + + void emit(); +}; + +} // end namespace + +llvm::Function * +IRGenModule::getAddrOfDistributedMethodAccessor(SILFunction *F, + ForDefinition_t forDefinition) { + auto entity = LinkEntity::forDistributedMethodAccessor(F); + + llvm::Function *&entry = GlobalFuncs[entity]; + if (entry) { + if (forDefinition) + updateLinkageForDefinition(*this, entry, entity); + return entry; + } + + auto getParamForArguments = [&]() { + auto ptrType = Context.getUnsafeRawPointerType(); + return SILParameterInfo(ptrType->getCanonicalType(), + ParameterConvention::Direct_Guaranteed); + }; + + + // `self` of the distributed actor is going to be passed as an argument + // to this accessor function. + auto extInfo = SILExtInfoBuilder() + .withRepresentation(SILFunctionTypeRepresentation::Thick) + .build(); + + // Accessor gets argument value buffer and a reference to `self` of + // the actor and produces a call to the distributed thunk. + auto accessorType = SILFunctionType::get( + /*genericSignature=*/nullptr, extInfo, SILCoroutineKind::None, + ParameterConvention::Direct_Guaranteed, + {getParamForArguments()}, + /*Yields=*/{}, + /*Results=*/{}, + /*ErrorResult=*/None, + /*patternSubs=*/SubstitutionMap(), + /*invocationSubs=*/SubstitutionMap(), Context); + + Signature signature = getSignature(accessorType); + LinkInfo link = LinkInfo::get(*this, entity, forDefinition); + + return createFunction(*this, link, signature); +} + +void IRGenModule::emitDistributedMethodAccessor(SILFunction *method) { + assert(method->isDistributed()); + + auto *f = getAddrOfDistributedMethodAccessor(method, ForDefinition); + if (!f->isDeclaration()) + return; + + IRGenFunction IGF(*this, f); + DistributedAccessor(IGF, method).emit(); +} + +DistributedAccessor::DistributedAccessor(IRGenFunction &IGF, + SILFunction *method) + : IGF(IGF), Method(method) {} + +void DistributedAccessor::emit() { IGF.Builder.CreateRetVoid(); } diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index f83e353331088..1fc722a85a764 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -1631,6 +1631,12 @@ private: \ Address getAddrOfObjCISAMask(); + llvm::Function * + getAddrOfDistributedMethodAccessor(SILFunction *F, + ForDefinition_t forDefinition); + + void emitDistributedMethodAccessor(SILFunction *method); + /// Retrieve the generic signature for the current generic context, or null if no /// generic environment is active. CanGenericSignature getCurGenericContext(); diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index a55c4258127f8..9216f9d975c39 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2199,6 +2199,11 @@ void IRGenSILFunction::emitSILFunction() { IGM.noteSwiftAsyncFunctionDef(); } + // Generate accessor thunk for the `distributed` method. + if (CurSILFn->isDistributed() && !CurSILFn->isThunk()) { + IGM.emitDistributedMethodAccessor(CurSILFn); + } + // Configure the dominance resolver. // TODO: consider re-using a dom analysis from the PassManager // TODO: consider using a cheaper analysis at -O0 diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index c58a3627f2e2d..0f75db3d6dd8c 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -492,11 +492,18 @@ std::string LinkEntity::mangleAsString() const { Result.append("Tu"); return Result; } - case Kind::PartialApplyForwarder: + case Kind::PartialApplyForwarder: { std::string Result; Result = std::string(static_cast(Pointer)->getName()); return Result; } + + case Kind::DistributedMethodAccessor: { + std::string Result(getSILFunction()->getName()); + Result.append("TF"); + return Result; + } + } llvm_unreachable("bad entity kind!"); } @@ -795,6 +802,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const { case Kind::KnownAsyncFunctionPointer: return SILLinkage::PublicExternal; case Kind::PartialApplyForwarder: + case Kind::DistributedMethodAccessor: return SILLinkage::Private; } llvm_unreachable("bad link entity kind"); @@ -885,6 +893,7 @@ bool LinkEntity::isContextDescriptor() const { case Kind::CanonicalPrespecializedGenericTypeCachingOnceToken: case Kind::PartialApplyForwarder: case Kind::KnownAsyncFunctionPointer: + case Kind::DistributedMethodAccessor: return false; } llvm_unreachable("invalid descriptor"); @@ -1092,7 +1101,8 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const { return false; case Kind::DynamicallyReplaceableFunctionKey: case Kind::DynamicallyReplaceableFunctionVariable: - case Kind::SILFunction: { + case Kind::SILFunction: + case Kind::DistributedMethodAccessor: { return getSILFunction()->isWeakImported(); } @@ -1330,6 +1340,11 @@ DeclContext *LinkEntity::getDeclContextForEmission() const { case Kind::PartialApplyForwarderAsyncFunctionPointer: return getUnderlyingEntityForAsyncFunctionPointer() .getDeclContextForEmission(); + + case Kind::DistributedMethodAccessor: { + auto *methodDC = getSILFunction()->getDeclContext(); + return methodDC->getParentModule(); + } } llvm_unreachable("invalid decl kind"); } From 19bf160ed0eb783c96a86bc00e16de1e202cdaa4 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 22 Nov 2021 11:44:34 -0800 Subject: [PATCH 04/38] [Distributed] IRGen: Add argument loading from `UnsafeRawPointer` into an explosion `DistributedAccessor::computeArguments` handles loading of the argument values from the provided `UnsafeRawPointer` (managed by the caller), coercing retrieved arguments to appropriate platform-native representation, and exploding object to form correct argument sequence for distributed method call. --- lib/IRGen/GenDistributed.cpp | 99 +++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 6e562887bbf3d..d926e8a51b423 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -61,6 +61,7 @@ llvm::Value *irgen::emitDistributedActorInitializeRemote( namespace { class DistributedAccessor { + IRGenModule &IGM; IRGenFunction &IGF; /// Underlying distributed method for this accessor. @@ -70,6 +71,9 @@ class DistributedAccessor { DistributedAccessor(IRGenFunction &IGF, SILFunction *method); void emit(); + +private: + Explosion computeArguments(llvm::Value *argumentBuffer); }; } // end namespace @@ -130,6 +134,97 @@ void IRGenModule::emitDistributedMethodAccessor(SILFunction *method) { DistributedAccessor::DistributedAccessor(IRGenFunction &IGF, SILFunction *method) - : IGF(IGF), Method(method) {} + : IGM(IGF.IGM), IGF(IGF), Method(method) {} + +Explosion DistributedAccessor::computeArguments(llvm::Value *argumentBuffer) { + auto fnType = Method->getLoweredFunctionType(); + + Explosion arguments; + + auto offset = + IGF.createAlloca(IGM.Int8PtrTy, IGM.getPointerAlignment(), "offset"); + IGF.Builder.CreateLifetimeStart(offset, IGM.getPointerSize()); + + // Initialize "offset" with the address of the base of the argument buffer. + IGF.Builder.CreateStore(argumentBuffer, offset); + + // Cover all of the arguments except to `self` of the actor. + for (auto ¶m : fnType->getParameters().drop_back()) { + auto paramTy = param.getSILStorageInterfaceType(); + const TypeInfo &typeInfo = IGF.getTypeInfo(paramTy); + + // 1. Load current offset. + llvm::Value *currentOffset = IGF.Builder.CreateLoad(offset, "elt_offset"); + + // 2. Cast the pointer to the type of the element. + Address eltPtr = IGF.Builder.CreateBitCast( + Address(currentOffset, IGM.getPointerAlignment()), + IGM.getStoragePointerType(paramTy)); + + // 3. Adjust typed pointer to the alignement of the type. + auto alignedOffset = typeInfo.roundUpToTypeAlignment(IGF, eltPtr, paramTy); + + // 4. Load argument value from the element pointer. + auto *argValue = IGF.Builder.CreateLoad(alignedOffset, "argval"); + + // 5. Create an exploded version of the type to pass as an + // argument to distributed method. + + if (paramTy.isObject()) { + auto &nativeSchema = typeInfo.nativeParameterValueSchema(IGM); + auto expandedTy = nativeSchema.getExpandedType(IGM); + + if (nativeSchema.requiresIndirect()) { + llvm_unreachable("indirect parameters are not supported"); + } + + Explosion nonNativeParam; + nonNativeParam.add(argValue); -void DistributedAccessor::emit() { IGF.Builder.CreateRetVoid(); } + // Convert SIL type into a native representation. + auto nativeParam = nativeSchema.mapIntoNative( + IGM, IGF, nonNativeParam, paramTy, /*isOutlined=*/false); + + // If expanded type is a struct we need to explode it to match + // expected argument schema. + if (auto *ST = dyn_cast(expandedTy)) { + IGF.emitAllExtractValues(nativeParam.claimNext(), ST, arguments); + } else { + arguments.add(nativeParam.claimNext()); + } + } else { + arguments.add(argValue); + } + + // 6. Move the offset to the beginning of the next element. + { + llvm::Value *typeSize = typeInfo.getSize(IGF, paramTy); + + llvm::Value *addr = alignedOffset.getAddress(); + addr = IGF.Builder.CreatePtrToInt(addr, IGM.IntPtrTy); + llvm::Value *nextOffset = IGF.Builder.CreateIntToPtr( + IGF.Builder.CreateAdd(addr, typeSize), IGM.Int8PtrTy); + + IGF.Builder.CreateStore(nextOffset, offset); + } + } + + IGF.Builder.CreateLifetimeEnd(offset, IGM.getPointerSize()); + + return arguments; +} + +void DistributedAccessor::emit() { + auto params = IGF.collectParameters(); + + // UnsafeRawPointer that holds all of the argument values + auto *argBuffer = params.claimNext(); + // Reference to a `self` of the actor to be called. + auto *actorSelf = params.claimNext(); + + // Step one is to load all of the data from argument buffer, + // so it could be forwarded to the distributed method. + auto arguments = computeArguments(argBuffer); + + IGF.Builder.CreateRetVoid(); +} From ac2973d21152a9b68ca686189663488e81540d7c Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 22 Nov 2021 20:03:16 -0800 Subject: [PATCH 05/38] [Distributed] IRGen: Form a callee for a distributed method --- lib/IRGen/GenDistributed.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index d926e8a51b423..8405a0d746b35 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -17,6 +17,7 @@ #include "GenDistributed.h" #include "BitPatternBuilder.h" +#include "Callee.h" #include "ClassTypeInfo.h" #include "ExtraInhabitants.h" #include "GenDecl.h" @@ -74,6 +75,10 @@ class DistributedAccessor { private: Explosion computeArguments(llvm::Value *argumentBuffer); + + FunctionPointer getPointerToMethod() const; + + Callee getCalleeForDistributedMethod(llvm::Value *self) const; }; } // end namespace @@ -228,3 +233,24 @@ void DistributedAccessor::emit() { IGF.Builder.CreateRetVoid(); } + +FunctionPointer DistributedAccessor::getPointerToMethod() const { + auto fnType = Method->getLoweredFunctionType(); + auto fpKind = classifyFunctionPointerKind(Method); + auto signature = IGM.getSignature(fnType, fpKind.useSpecialConvention()); + + auto *fnPtr = + IGM.getAddrOfSILFunction(Method, NotForDefinition, + /*isDynamicallyReplaceable=*/false, + /*shouldCallPreviousImplementation=*/false); + + return FunctionPointer::forDirect(fpKind, fnPtr, /*secondary=*/nullptr, + signature); +} + +Callee +DistributedAccessor::getCalleeForDistributedMethod(llvm::Value *self) const { + auto fnType = Method->getLoweredFunctionType(); + CalleeInfo info{fnType, fnType, SubstitutionMap()}; + return {std::move(info), getPointerToMethod(), self}; +} From a866a7a53e5bc4e09a89bac1694a65d7f8366d60 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 22 Nov 2021 22:07:30 -0800 Subject: [PATCH 06/38] [Distributed] IRGen: Emit a call to a distributed method Note that results are not handled yet. --- lib/IRGen/GenDistributed.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 8405a0d746b35..cdd03e52ecd04 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -18,6 +18,7 @@ #include "BitPatternBuilder.h" #include "Callee.h" +#include "CallEmission.h" #include "ClassTypeInfo.h" #include "ExtraInhabitants.h" #include "GenDecl.h" @@ -231,7 +232,31 @@ void DistributedAccessor::emit() { // so it could be forwarded to the distributed method. auto arguments = computeArguments(argBuffer); - IGF.Builder.CreateRetVoid(); + // Step two, let's form and emit a call to the distributed method + // using computed argument explosion. + { + auto fnType = Method->getLoweredFunctionType(); + GenericContextScope scope(IGM, fnType->getInvocationGenericSignature()); + + Explosion result; + + auto callee = getCalleeForDistributedMethod(actorSelf); + auto emission = + getCallEmission(IGF, callee.getSwiftContext(), std::move(callee)); + + emission->begin(); + emission->setArgs(arguments, /*isOutlined=*/false, + /*witnessMetadata=*/nullptr); + emission->emitToExplosion(result, /*isOutlined=*/false); + emission->end(); + + if (result.empty()) { + IGF.Builder.CreateRetVoid(); + return; + } + + // TODO: Emit result if method has one or more. + } } FunctionPointer DistributedAccessor::getPointerToMethod() const { From 185a6630f1bcc2e477de94fb6eabd8e67aaa5b4d Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 23 Nov 2021 01:06:39 -0800 Subject: [PATCH 07/38] [Distributed] IRGen: Forward distributed method results through accessor Accessor infers result(s) from the underlying distributed method its going to call, and forwards all of the results produced by such call up to the caller. --- lib/IRGen/GenDistributed.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index cdd03e52ecd04..774245f8a8f4b 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -109,14 +109,16 @@ IRGenModule::getAddrOfDistributedMethodAccessor(SILFunction *F, .withRepresentation(SILFunctionTypeRepresentation::Thick) .build(); + auto methodTy = F->getLoweredFunctionType(); // Accessor gets argument value buffer and a reference to `self` of - // the actor and produces a call to the distributed thunk. + // the actor and produces a call to the distributed thunk forwarding + // its result(s) out. auto accessorType = SILFunctionType::get( /*genericSignature=*/nullptr, extInfo, SILCoroutineKind::None, ParameterConvention::Direct_Guaranteed, {getParamForArguments()}, /*Yields=*/{}, - /*Results=*/{}, + /*Results=*/methodTy->getResults(), /*ErrorResult=*/None, /*patternSubs=*/SubstitutionMap(), /*invocationSubs=*/SubstitutionMap(), Context); @@ -221,6 +223,10 @@ Explosion DistributedAccessor::computeArguments(llvm::Value *argumentBuffer) { } void DistributedAccessor::emit() { + auto methodTy = Method->getLoweredFunctionType(); + SILFunctionConventions conv(methodTy, IGF.getSILModule()); + TypeExpansionContext expansionContext = IGM.getMaximalTypeExpansionContext(); + auto params = IGF.collectParameters(); // UnsafeRawPointer that holds all of the argument values @@ -235,8 +241,7 @@ void DistributedAccessor::emit() { // Step two, let's form and emit a call to the distributed method // using computed argument explosion. { - auto fnType = Method->getLoweredFunctionType(); - GenericContextScope scope(IGM, fnType->getInvocationGenericSignature()); + GenericContextScope scope(IGM, methodTy->getInvocationGenericSignature()); Explosion result; @@ -255,7 +260,10 @@ void DistributedAccessor::emit() { return; } - // TODO: Emit result if method has one or more. + auto resultTy = conv.getSILResultType(expansionContext); + IGF.emitScalarReturn(resultTy, resultTy, result, + /*swiftCCReturn=*/false, + /*isOutlined=*/false); } } From 2179db3607ef82d11cabb42fe420348e333bc698 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 23 Nov 2021 22:43:13 -0800 Subject: [PATCH 08/38] [IRGen] Linking: Make it possible to form async pointers to distributed method accessors --- include/swift/IRGen/Linking.h | 15 +++++++++++++++ lib/IRGen/Linking.cpp | 9 ++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index ef1b87d79eed4..633ee4fc60e0e 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -484,6 +484,9 @@ class LinkEntity { /// The pointer is SILFunction* DistributedMethodAccessor, + /// An async function pointer for a distributed method accessor. + /// The pointer is a SILFunction*. + DistributedMethodAccessorAsyncPointer, }; friend struct llvm::DenseMapInfo; @@ -1239,6 +1242,13 @@ class LinkEntity { Kind, unsigned(LinkEntity::Kind::PartialApplyForwarderAsyncFunctionPointer)); break; + case LinkEntity::Kind::DistributedMethodAccessor: { + entity.Data = LINKENTITY_SET_FIELD( + Kind, + unsigned(LinkEntity::Kind::DistributedMethodAccessorAsyncPointer)); + break; + } + default: llvm_unreachable("Link entity kind cannot have an async function pointer"); } @@ -1306,6 +1316,11 @@ class LinkEntity { Kind, unsigned(LinkEntity::Kind::PartialApplyForwarder)); break; + case LinkEntity::Kind::DistributedMethodAccessorAsyncPointer: + entity.Data = LINKENTITY_SET_FIELD( + Kind, unsigned(LinkEntity::Kind::DistributedMethodAccessor)); + break; + default: llvm_unreachable("Link entity is not an async function pointer"); } diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index 0f75db3d6dd8c..da10d1da3c5a5 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -469,7 +469,8 @@ std::string LinkEntity::mangleAsString() const { case Kind::DispatchThunkAsyncFunctionPointer: case Kind::DispatchThunkInitializerAsyncFunctionPointer: case Kind::DispatchThunkAllocatorAsyncFunctionPointer: - case Kind::PartialApplyForwarderAsyncFunctionPointer: { + case Kind::PartialApplyForwarderAsyncFunctionPointer: + case Kind::DistributedMethodAccessorAsyncPointer: { std::string Result(getUnderlyingEntityForAsyncFunctionPointer() .mangleAsString()); Result.append("Tu"); @@ -797,6 +798,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const { case Kind::DispatchThunkInitializerAsyncFunctionPointer: case Kind::DispatchThunkAllocatorAsyncFunctionPointer: case Kind::PartialApplyForwarderAsyncFunctionPointer: + case Kind::DistributedMethodAccessorAsyncPointer: return getUnderlyingEntityForAsyncFunctionPointer() .getLinkage(forDefinition); case Kind::KnownAsyncFunctionPointer: @@ -829,6 +831,7 @@ bool LinkEntity::isContextDescriptor() const { case Kind::DispatchThunkInitializerAsyncFunctionPointer: case Kind::DispatchThunkAllocatorAsyncFunctionPointer: case Kind::PartialApplyForwarderAsyncFunctionPointer: + case Kind::DistributedMethodAccessorAsyncPointer: case Kind::MethodDescriptor: case Kind::MethodDescriptorDerivative: case Kind::MethodDescriptorInitializer: @@ -1014,6 +1017,7 @@ llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const { case Kind::DispatchThunkAllocatorAsyncFunctionPointer: case Kind::DistributedThunkAsyncFunctionPointer: case Kind::PartialApplyForwarderAsyncFunctionPointer: + case Kind::DistributedMethodAccessorAsyncPointer: case Kind::AsyncFunctionPointerAST: case Kind::KnownAsyncFunctionPointer: return IGM.AsyncFunctionPointerTy; @@ -1055,6 +1059,7 @@ Alignment LinkEntity::getAlignment(IRGenModule &IGM) const { case Kind::DispatchThunkInitializerAsyncFunctionPointer: case Kind::DispatchThunkAllocatorAsyncFunctionPointer: case Kind::PartialApplyForwarderAsyncFunctionPointer: + case Kind::DistributedMethodAccessorAsyncPointer: case Kind::KnownAsyncFunctionPointer: case Kind::ObjCClassRef: case Kind::ObjCClass: @@ -1210,6 +1215,7 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const { case Kind::DispatchThunkInitializerAsyncFunctionPointer: case Kind::DispatchThunkAllocatorAsyncFunctionPointer: case Kind::PartialApplyForwarderAsyncFunctionPointer: + case Kind::DistributedMethodAccessorAsyncPointer: return getUnderlyingEntityForAsyncFunctionPointer() .isWeakImported(module); case Kind::KnownAsyncFunctionPointer: @@ -1338,6 +1344,7 @@ DeclContext *LinkEntity::getDeclContextForEmission() const { case Kind::DispatchThunkInitializerAsyncFunctionPointer: case Kind::DispatchThunkAllocatorAsyncFunctionPointer: case Kind::PartialApplyForwarderAsyncFunctionPointer: + case Kind::DistributedMethodAccessorAsyncPointer: return getUnderlyingEntityForAsyncFunctionPointer() .getDeclContextForEmission(); From 9d1c103f5ec5d71f428aa851405835edb0df7c1b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 24 Nov 2021 11:08:25 -0800 Subject: [PATCH 09/38] [Distributed] IRGen: Turn distributed method accessor into async function --- lib/IRGen/GenDistributed.cpp | 99 +++++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 34 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 774245f8a8f4b..d4a59b08b79ac 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -17,11 +17,13 @@ #include "GenDistributed.h" #include "BitPatternBuilder.h" -#include "Callee.h" #include "CallEmission.h" +#include "Callee.h" #include "ClassTypeInfo.h" #include "ExtraInhabitants.h" +#include "GenCall.h" #include "GenDecl.h" +#include "GenMeta.h" #include "GenProto.h" #include "GenType.h" #include "IRGenDebugInfo.h" @@ -69,8 +71,14 @@ class DistributedAccessor { /// Underlying distributed method for this accessor. SILFunction *Method; + /// The interface type of this accessor function. + CanSILFunctionType AccessorType; + /// The asynchronous context associated with this accessor. + AsyncContextLayout AsyncLayout; + public: - DistributedAccessor(IRGenFunction &IGF, SILFunction *method); + DistributedAccessor(IRGenFunction &IGF, SILFunction *method, + CanSILFunctionType accessorTy); void emit(); @@ -84,17 +92,11 @@ class DistributedAccessor { } // end namespace -llvm::Function * -IRGenModule::getAddrOfDistributedMethodAccessor(SILFunction *F, - ForDefinition_t forDefinition) { - auto entity = LinkEntity::forDistributedMethodAccessor(F); - - llvm::Function *&entry = GlobalFuncs[entity]; - if (entry) { - if (forDefinition) - updateLinkageForDefinition(*this, entry, entity); - return entry; - } +/// Compute a type of a distributed method accessor function based +/// on the provided distributed method. +static CanSILFunctionType getAccessorType(IRGenModule &IGM, + SILFunction *DistMethod) { + auto &Context = IGM.Context; auto getParamForArguments = [&]() { auto ptrType = Context.getUnsafeRawPointerType(); @@ -102,28 +104,40 @@ IRGenModule::getAddrOfDistributedMethodAccessor(SILFunction *F, ParameterConvention::Direct_Guaranteed); }; - // `self` of the distributed actor is going to be passed as an argument // to this accessor function. auto extInfo = SILExtInfoBuilder() - .withRepresentation(SILFunctionTypeRepresentation::Thick) - .build(); + .withRepresentation(SILFunctionTypeRepresentation::Thick) + .withAsync() + .build(); - auto methodTy = F->getLoweredFunctionType(); + auto methodTy = DistMethod->getLoweredFunctionType(); // Accessor gets argument value buffer and a reference to `self` of // the actor and produces a call to the distributed thunk forwarding // its result(s) out. - auto accessorType = SILFunctionType::get( + return SILFunctionType::get( /*genericSignature=*/nullptr, extInfo, SILCoroutineKind::None, - ParameterConvention::Direct_Guaranteed, - {getParamForArguments()}, + ParameterConvention::Direct_Guaranteed, {getParamForArguments()}, /*Yields=*/{}, /*Results=*/methodTy->getResults(), /*ErrorResult=*/None, /*patternSubs=*/SubstitutionMap(), /*invocationSubs=*/SubstitutionMap(), Context); +} + +llvm::Function * +IRGenModule::getAddrOfDistributedMethodAccessor(SILFunction *F, + ForDefinition_t forDefinition) { + auto entity = LinkEntity::forDistributedMethodAccessor(F); + + llvm::Function *&entry = GlobalFuncs[entity]; + if (entry) { + if (forDefinition) + updateLinkageForDefinition(*this, entry, entity); + return entry; + } - Signature signature = getSignature(accessorType); + Signature signature = getSignature(getAccessorType(*this, F)); LinkInfo link = LinkInfo::get(*this, entity, forDefinition); return createFunction(*this, link, signature); @@ -137,12 +151,18 @@ void IRGenModule::emitDistributedMethodAccessor(SILFunction *method) { return; IRGenFunction IGF(*this, f); - DistributedAccessor(IGF, method).emit(); + DistributedAccessor(IGF, method, getAccessorType(*this, method)).emit(); } DistributedAccessor::DistributedAccessor(IRGenFunction &IGF, - SILFunction *method) - : IGM(IGF.IGM), IGF(IGF), Method(method) {} + SILFunction *method, + CanSILFunctionType accessorTy) + : IGM(IGF.IGM), IGF(IGF), Method(method), AccessorType(accessorTy), + AsyncLayout(getAsyncContextLayout( + IGM, AccessorType, AccessorType, SubstitutionMap(), + /*suppress generics*/ true, + FunctionPointer::Kind( + FunctionPointer::BasicKind::AsyncFunctionPointer))) {} Explosion DistributedAccessor::computeArguments(llvm::Value *argumentBuffer) { auto fnType = Method->getLoweredFunctionType(); @@ -229,11 +249,30 @@ void DistributedAccessor::emit() { auto params = IGF.collectParameters(); + // FIXME: Once we remove async task and executor this should be one not three. + unsigned numAsyncContextParams = + (unsigned)AsyncFunctionArgumentIndex::Context + 1; + (void)params.claim(numAsyncContextParams); + // UnsafeRawPointer that holds all of the argument values auto *argBuffer = params.claimNext(); // Reference to a `self` of the actor to be called. auto *actorSelf = params.claimNext(); + GenericContextScope scope(IGM, methodTy->getInvocationGenericSignature()); + + // Preliminary: Setup async context for this accessor. + { + auto asyncContextIdx = + Signature::forAsyncEntry(IGM, AccessorType, + /*useSpecialConvention*/ false) + .getAsyncContextIndex(); + + auto entity = LinkEntity::forDistributedMethodAccessor(Method); + emitAsyncFunctionEntry(IGF, AsyncLayout, entity, asyncContextIdx); + emitAsyncFunctionPointer(IGM, IGF.CurFn, entity, AsyncLayout.getSize()); + } + // Step one is to load all of the data from argument buffer, // so it could be forwarded to the distributed method. auto arguments = computeArguments(argBuffer); @@ -241,8 +280,6 @@ void DistributedAccessor::emit() { // Step two, let's form and emit a call to the distributed method // using computed argument explosion. { - GenericContextScope scope(IGM, methodTy->getInvocationGenericSignature()); - Explosion result; auto callee = getCalleeForDistributedMethod(actorSelf); @@ -255,15 +292,9 @@ void DistributedAccessor::emit() { emission->emitToExplosion(result, /*isOutlined=*/false); emission->end(); - if (result.empty()) { - IGF.Builder.CreateRetVoid(); - return; - } - + Explosion error; auto resultTy = conv.getSILResultType(expansionContext); - IGF.emitScalarReturn(resultTy, resultTy, result, - /*swiftCCReturn=*/false, - /*isOutlined=*/false); + emitAsyncReturn(IGF, AsyncLayout, resultTy, AccessorType, result, error); } } From 8980922a531ab5c354bd7e6beb1dcdbc57d922f9 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 25 Nov 2021 00:57:18 -0800 Subject: [PATCH 10/38] [Distributed] IRGen: Mark accessor as `throws` and forward error values from distributed method Distributed method is always `async throws` outside of its isolation context, so accessor has to be `async throws` as well, and be able to forward error value from the call to the outside. --- lib/IRGen/GenDistributed.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index d4a59b08b79ac..8e609126284fe 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -112,6 +112,10 @@ static CanSILFunctionType getAccessorType(IRGenModule &IGM, .build(); auto methodTy = DistMethod->getLoweredFunctionType(); + + assert(methodTy->isAsync()); + assert(methodTy->hasErrorResult()); + // Accessor gets argument value buffer and a reference to `self` of // the actor and produces a call to the distributed thunk forwarding // its result(s) out. @@ -120,7 +124,7 @@ static CanSILFunctionType getAccessorType(IRGenModule &IGM, ParameterConvention::Direct_Guaranteed, {getParamForArguments()}, /*Yields=*/{}, /*Results=*/methodTy->getResults(), - /*ErrorResult=*/None, + /*ErrorResult=*/methodTy->getErrorResult(), /*patternSubs=*/SubstitutionMap(), /*invocationSubs=*/SubstitutionMap(), Context); } @@ -281,6 +285,7 @@ void DistributedAccessor::emit() { // using computed argument explosion. { Explosion result; + Explosion error; auto callee = getCalleeForDistributedMethod(actorSelf); auto emission = @@ -290,9 +295,20 @@ void DistributedAccessor::emit() { emission->setArgs(arguments, /*isOutlined=*/false, /*witnessMetadata=*/nullptr); emission->emitToExplosion(result, /*isOutlined=*/false); + + // Both accessor and distributed method are always `async throws` + // so we need to load error value (if any) from the slot. + { + assert(methodTy->hasErrorResult()); + + SILType errorType = conv.getSILErrorType(expansionContext); + Address calleeErrorSlot = + emission->getCalleeErrorSlot(errorType, /*isCalleeAsync=*/true); + error.add(IGF.Builder.CreateLoad(calleeErrorSlot)); + } + emission->end(); - Explosion error; auto resultTy = conv.getSILResultType(expansionContext); emitAsyncReturn(IGF, AsyncLayout, resultTy, AccessorType, result, error); } From 3ec9986a8335eef744ae609d7df807f27221b4c9 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 26 Nov 2021 19:10:08 -0800 Subject: [PATCH 11/38] [Distributed] IRGen: Support returning results indirectly from accessor --- lib/IRGen/GenDistributed.cpp | 40 ++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 8e609126284fe..7cf363e8a2e90 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -83,7 +83,7 @@ class DistributedAccessor { void emit(); private: - Explosion computeArguments(llvm::Value *argumentBuffer); + void computeArguments(llvm::Value *argumentBuffer, Explosion &arguments); FunctionPointer getPointerToMethod() const; @@ -168,11 +168,10 @@ DistributedAccessor::DistributedAccessor(IRGenFunction &IGF, FunctionPointer::Kind( FunctionPointer::BasicKind::AsyncFunctionPointer))) {} -Explosion DistributedAccessor::computeArguments(llvm::Value *argumentBuffer) { +void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, + Explosion &arguments) { auto fnType = Method->getLoweredFunctionType(); - Explosion arguments; - auto offset = IGF.createAlloca(IGM.Int8PtrTy, IGM.getPointerAlignment(), "offset"); IGF.Builder.CreateLifetimeStart(offset, IGM.getPointerSize()); @@ -242,8 +241,6 @@ Explosion DistributedAccessor::computeArguments(llvm::Value *argumentBuffer) { } IGF.Builder.CreateLifetimeEnd(offset, IGM.getPointerSize()); - - return arguments; } void DistributedAccessor::emit() { @@ -253,12 +250,25 @@ void DistributedAccessor::emit() { auto params = IGF.collectParameters(); + auto directResultTy = conv.getSILResultType(expansionContext); + const auto &directResultTI = IGM.getTypeInfo(directResultTy); + auto &resultSchema = directResultTI.nativeReturnValueSchema(IGM); + llvm::Value *indirectResultSlot = nullptr; + + if (resultSchema.requiresIndirect()) + indirectResultSlot = params.claimNext(); + + Explosion arguments; + // Claim indirect results first, they are going to be passed + // through to the distributed method. + params.transferInto(arguments, conv.getNumIndirectSILResults()); + // FIXME: Once we remove async task and executor this should be one not three. unsigned numAsyncContextParams = (unsigned)AsyncFunctionArgumentIndex::Context + 1; (void)params.claim(numAsyncContextParams); - // UnsafeRawPointer that holds all of the argument values + // UnsafeRawPointer that holds all of the argument values. auto *argBuffer = params.claimNext(); // Reference to a `self` of the actor to be called. auto *actorSelf = params.claimNext(); @@ -279,7 +289,7 @@ void DistributedAccessor::emit() { // Step one is to load all of the data from argument buffer, // so it could be forwarded to the distributed method. - auto arguments = computeArguments(argBuffer); + computeArguments(argBuffer, arguments); // Step two, let's form and emit a call to the distributed method // using computed argument explosion. @@ -294,7 +304,15 @@ void DistributedAccessor::emit() { emission->begin(); emission->setArgs(arguments, /*isOutlined=*/false, /*witnessMetadata=*/nullptr); - emission->emitToExplosion(result, /*isOutlined=*/false); + + if (resultSchema.requiresIndirect()) { + Address resultAddr(indirectResultSlot, + directResultTI.getBestKnownAlignment()); + emission->emitToMemory(resultAddr, cast(directResultTI), + /*isOutlined=*/false); + } else { + emission->emitToExplosion(result, /*isOutlined=*/false); + } // Both accessor and distributed method are always `async throws` // so we need to load error value (if any) from the slot. @@ -309,8 +327,8 @@ void DistributedAccessor::emit() { emission->end(); - auto resultTy = conv.getSILResultType(expansionContext); - emitAsyncReturn(IGF, AsyncLayout, resultTy, AccessorType, result, error); + emitAsyncReturn(IGF, AsyncLayout, directResultTy, AccessorType, result, + error); } } From 7190e9ed9f20f45025de32e4f3387a41adc6537e Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 29 Nov 2021 11:59:23 -0800 Subject: [PATCH 12/38] [SIL] IR: Make sure that distributed thunk is always emitted Even if there are no uses of the thunk in the code it's still could be accessed from remotely via distributed accessor mechanism, so distributed thunks are always used. --- lib/SIL/IR/SILFunction.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index e4032b3548771..c3c9cf017808c 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -683,6 +683,9 @@ SILFunction::isPossiblyUsedExternally() const { if (ReplacedFunction) return true; + if (isDistributed() && isThunk()) + return true; + return swift::isPossiblyUsedExternally(linkage, getModule().isWholeModule()); } From 176b54574d784edd8c9b920295591c318b970e09 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 29 Nov 2021 12:01:16 -0800 Subject: [PATCH 13/38] [Distributed] IRGen: Switch accessor over to distributed thunk Instead of using the distributed method directly, let's always call distributed thunk instead which is safe option because actor could not be local (e.g. issue with routing) but only distributed thunk would know that and take appropriate action. --- lib/IRGen/IRGenSIL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index 9216f9d975c39..a32763d87b9f4 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2200,7 +2200,7 @@ void IRGenSILFunction::emitSILFunction() { } // Generate accessor thunk for the `distributed` method. - if (CurSILFn->isDistributed() && !CurSILFn->isThunk()) { + if (CurSILFn->isDistributed() && CurSILFn->isThunk()) { IGM.emitDistributedMethodAccessor(CurSILFn); } From 56fdf34f0a4b1bfe82edb7e8dac9fed09aad0978 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 30 Nov 2021 12:43:32 -0800 Subject: [PATCH 14/38] [Distributed] NFC: Remove outdated FIXME about async task/executor parameters --- lib/IRGen/GenDistributed.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 7cf363e8a2e90..79192c3eb322b 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -263,7 +263,6 @@ void DistributedAccessor::emit() { // through to the distributed method. params.transferInto(arguments, conv.getNumIndirectSILResults()); - // FIXME: Once we remove async task and executor this should be one not three. unsigned numAsyncContextParams = (unsigned)AsyncFunctionArgumentIndex::Context + 1; (void)params.claim(numAsyncContextParams); From 71e7355e8c0cb4eaf34330dd6e942f68bb212a40 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 1 Dec 2021 10:33:20 -0800 Subject: [PATCH 15/38] [Distributed] IRGen: Don't load arguments they turn into `void` in native schema If parameter type's size is `0` then we don't want to perform a load at the current position in the buffer and have to move to the next non-empty element. --- lib/IRGen/GenDistributed.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 79192c3eb322b..3eb8172b025ff 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -195,10 +195,7 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, // 3. Adjust typed pointer to the alignement of the type. auto alignedOffset = typeInfo.roundUpToTypeAlignment(IGF, eltPtr, paramTy); - // 4. Load argument value from the element pointer. - auto *argValue = IGF.Builder.CreateLoad(alignedOffset, "argval"); - - // 5. Create an exploded version of the type to pass as an + // 4. Create an exploded version of the type to pass as an // argument to distributed method. if (paramTy.isObject()) { @@ -209,6 +206,13 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, llvm_unreachable("indirect parameters are not supported"); } + // If schema is empty, skip to the next argument. + if (nativeSchema.empty()) + continue; + + // 5. Load argument value from the element pointer. + auto *argValue = IGF.Builder.CreateLoad(alignedOffset, "argval"); + Explosion nonNativeParam; nonNativeParam.add(argValue); @@ -224,7 +228,8 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, arguments.add(nativeParam.claimNext()); } } else { - arguments.add(argValue); + // 5. Load argument value from the element pointer. + arguments.add(IGF.Builder.CreateLoad(alignedOffset, "argval")); } // 6. Move the offset to the beginning of the next element. From 2156fb04e44bed01b57c71fc2bfe2d94a24b24f1 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 1 Dec 2021 15:14:01 -0800 Subject: [PATCH 16/38] [Distributed/Accessor] IRGen: Don't move argument buffer pointer past the last element --- lib/IRGen/GenDistributed.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 3eb8172b025ff..bfb25b85d1648 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -180,7 +180,8 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, IGF.Builder.CreateStore(argumentBuffer, offset); // Cover all of the arguments except to `self` of the actor. - for (auto ¶m : fnType->getParameters().drop_back()) { + auto parameters = fnType->getParameters().drop_back(); + for (const auto ¶m : parameters) { auto paramTy = param.getSILStorageInterfaceType(); const TypeInfo &typeInfo = IGF.getTypeInfo(paramTy); @@ -232,8 +233,9 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, arguments.add(IGF.Builder.CreateLoad(alignedOffset, "argval")); } - // 6. Move the offset to the beginning of the next element. - { + // 6. Move the offset to the beginning of the next element, unless + // this is the last element. + if (param != parameters.back()) { llvm::Value *typeSize = typeInfo.getSize(IGF, paramTy); llvm::Value *addr = alignedOffset.getAddress(); From 38a0e66903c8fdee862b55fb778bd33e9dc2b4c0 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 1 Dec 2021 16:40:46 -0800 Subject: [PATCH 17/38] [Distributed/IRGen] NFC: Add various test-cases for distributed accessors Test multiple scenarios - value types, reference types, optionals, arrays, direct and indirect returns. --- test/IRGen/distributed_actor_accessors.swift | 280 +++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 test/IRGen/distributed_actor_accessors.swift diff --git a/test/IRGen/distributed_actor_accessors.swift b/test/IRGen/distributed_actor_accessors.swift new file mode 100644 index 0000000000000..e651af0c562c2 --- /dev/null +++ b/test/IRGen/distributed_actor_accessors.swift @@ -0,0 +1,280 @@ +// RUN: %target-swift-frontend -emit-irgen %s -swift-version 5 -enable-experimental-distributed | %IRGenFileCheck %s + +// UNSUPPORTED: back_deploy_concurrency +// REQUIRES: concurrency +// REQUIRES: distributed + +import _Distributed + +enum SimpleE : Codable { +case a +} + +enum E : Codable { +case a, b, c +} + +enum IndirectE : Codable { + case empty + indirect case test(_: Int) +} + +final class Obj : Codable, Sendable { + let x: Int + + init(x: Int) { + self.x = x + } +} + +struct LargeStruct : Codable { + var a: Int + var b: Int + var c: String + var d: Double +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyActor { + public typealias Transport = AnyActorTransport + + distributed func simple1(_: Int) { + } + + // `String` would be a direct result as a struct type + distributed func simple2(_: Int) -> String { + return "" + } + + // `String` is an object that gets exploded into two parameters + distributed func simple3(_: String) -> Int { + return 42 + } + + // Enum with a single case are special because they have an empty + // native schema so they are dropped from parameters/result. + distributed func single_case_enum(_ e: SimpleE) -> SimpleE { + return e + } + + distributed func with_indirect_enums(_: IndirectE, _: Int) -> IndirectE { + return .empty + } + + // Combination of multiple arguments, reference type and indirect result + // + // Note: Tuple types cannot be used here is either position because they + // cannot conform to protocols. + distributed func complex(_: [Int], _: Obj, _: String?, _: LargeStruct) -> LargeStruct { + fatalError() + } +} + +/// ---> Thunk and distributed method accessor for `simple1` + +/// Let's make sure that accessor loads the data from the buffer and calls expected accessor + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTE" + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETF"(%swift.context* swiftasync %0, i8* %1, %swift.refcounted* swiftself %2) + +/// Read the current offset and cast an element to `Int` + +// CHECK: store i8* %1, i8** %offset, align 8 +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[ELT_PTR:%.*]] = bitcast i8* %elt_offset to %TSi* +// CHECK-NEXT: %argval = load %TSi, %TSi* [[ELT_PTR]], align 8 + +// CHECK: [[NATIVE_VAL_LOC:%.*]] = bitcast %TSi* %argval.coercion.coerced to i64* +// CHECK-NEXT: [[ARG_VAL:%.*]] = load i64, i64* [[NATIVE_VAL_LOC]], align 8 + +/// Retrieve an async pointer to the distributed thunk for `simple1` + +// CHECK: [[THUNK_LOC:%.*]] = add i64 ptrtoint (void (%swift.context*, i64, %T27distributed_actor_accessors7MyActorC*)* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTE" to i64), {{.*}} +// CHECK-NEXT: [[OPAQUE_THUNK_PTR:%.*]] = inttoptr i64 [[THUNK_LOC]] to i8* +// CHECK-NEXT: [[THUNK_PTR:%.*]] = bitcast i8* [[OPAQUE_THUNK_PTR]] to void (%swift.context*, i64, %T27distributed_actor_accessors7MyActorC*)* + +/// Call distributed thunk for `simple1` and `end` async context without results + +// CHECK: [[THUNK_PTR_REF:%.*]] = bitcast void (%swift.context*, i64, %T27distributed_actor_accessors7MyActorC*)* [[THUNK_PTR]] to i8* +// CHECK-NEXT: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, i8* [[THUNK_PTR_REF]], %swift.context* {{.*}}, i64 [[ARG_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, %swift.error* } [[THUNK_RESULT]], 0 +// CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// ---> Thunk and distributed method accessor for `simple2` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTE" + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETF" + +/// !!! - We are not going to double-check argument extraction here since it's the same as `simple1`. +// CHECK: [[NATIVE_ARG_VAL:%.*]] = load i64, i64* {{.*}}, align 8 + +/// Load async pointer to distributed thunk for `simple2` + +// CHECK: [[THUNK_LOC:%.*]] = add i64 ptrtoint (void (%swift.context*, i64, %T27distributed_actor_accessors7MyActorC*)* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTE" to i64), {{.*}} +// CHECK-NEXT: [[OPAQUE_THUNK_PTR:%.*]] = inttoptr i64 [[THUNK_LOC]] to i8* +// CHECK-NEXT: [[THUNK_PTR:%.*]] = bitcast i8* [[OPAQUE_THUNK_PTR]] to void (%swift.context*, i64, %T27distributed_actor_accessors7MyActorC*)* + +/// Call the thunk with extracted argument value + +// CHECK: [[THUNK_PTR_REF:%.*]] = bitcast void (%swift.context*, i64, %T27distributed_actor_accessors7MyActorC*)* [[THUNK_PTR]] to i8* +// CHECK-NEXT: [[THUNK_RESULT:%.*]] = call { i8*, i64, %swift.bridge*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8i64p0s_swift.bridgesp0s_swift.errorss({{.*}}, i8* [[THUNK_PTR_REF]], %swift.context* {{.*}}, i64 [[NATIVE_ARG_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, i64, %swift.bridge*, %swift.error* } [[THUNK_RESULT]], 0 +// CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) + +/// Extract information about `String` from result and call `end` + +// CHECK: [[STR_STRUCT:%.*]] = insertvalue { i64, %swift.bridge* } {{.*}}, %swift.bridge* {{.*}}, 1 +// CHECK: [[STR_SIZE:%.*]] = extractvalue { i64, %swift.bridge* } [[STR_STRUCT]], 0 +// CHECK-NEXT: [[STR_VAL:%.*]] = extractvalue { i64, %swift.bridge* } [[STR_STRUCT]], 1 +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, i64 [[STR_SIZE]], %swift.bridge* [[STR_VAL]], %swift.error* {{.*}}) + +/// ---> Thunk and distributed method accessor for `simple3` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTE" + +/// !!! in `simple3` interesting bits are: argument value extraction (because string is exploded into N arguments) and call to distributed thunk +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETF" + +// CHECK: %argval = load %TSS, %TSS* {{.*}}, align 8 +// CHECK: [[NATIVE_STR_PTR:%.*]] = bitcast %TSS* %argval.coercion.coerced to { i64, %swift.bridge* }* +// CHECK-NEXT: [[NATIVE_STR:%.*]] = load { i64, %swift.bridge* }, { i64, %swift.bridge* }* [[NATIVE_STR_PTR]], align 8 +// CHECK: [[STR_SIZE:%.*]] = extractvalue { i64, %swift.bridge* } [[NATIVE_STR]], 0 +// CHECK-NEXT: [[STR_VAL:%.*]] = extractvalue { i64, %swift.bridge* } [[NATIVE_STR]], 1 + +/// Load pointer to a distributed thunk for `simple3` + +// CHECK: [[THUNK_LOC:%.*]] = add i64 ptrtoint (void (%swift.context*, i64, %swift.bridge*, %T27distributed_actor_accessors7MyActorC*)* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTE" to i64), {{.*}} +// CHECK-NEXT: [[OPAQUE_THUNK_PTR:%.*]] = inttoptr i64 [[THUNK_LOC]] to i8* +// CHECK-NEXT: [[THUNK_PTR:%.*]] = bitcast i8* [[OPAQUE_THUNK_PTR]] to void (%swift.context*, i64, %swift.bridge*, %T27distributed_actor_accessors7MyActorC*)* + +/// Call distributed thunk with exploaded string value + +// CHECK: [[OPAQUE_THUNK_PTR:%.*]] = bitcast void (%swift.context*, i64, %swift.bridge*, %T27distributed_actor_accessors7MyActorC*)* [[THUNK_PTR]] to i8* +// CHECK-NEXT: [[THUNK_RESULT:%.*]] = call { i8*, i64, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8i64p0s_swift.errorss({{.*}}, i8* [[OPAQUE_THUNK_PTR]], %swift.context* {{.*}}, i64 [[STR_SIZE]], %swift.bridge* [[STR_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 0 +// CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) +// CHECK: [[INT_RES:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 1 +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, i64 [[INT_RES]], %swift.error* {{.*}}) + +/// --> Thunk and distributed method accessor for `single_case_enum` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTE" + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETF"(%swift.context* swiftasync %0, i8* [[BUFFER:%.*]], %swift.refcounted* swiftself %2) + +/// First, let's check that there were no loads from the argument buffer and no stores to "current offset". + +// CHECK: [[OFFSET:%.*]] = bitcast i8** %offset to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[OFFSET]]) +// CHECK-NEXT: store i8* [[BUFFER]], i8** %offset, align 8 +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[ELT_PTR:.*]] = bitcast i8* %elt_offset to %T27distributed_actor_accessors7SimpleEO* +// CHECK-NEXT: [[OFFSET:%.*]] = bitcast i8** %offset to i8* +// CHECK-NEXT call void @llvm.lifetime.end.p0i8(i64 8, i8* [[OFFSET]]) + +/// Now, let's check that the call doesn't have any arguments and returns nothing. + +// CHECK: [[THUNK_REF:%.*]] = bitcast void (%swift.context*, %T27distributed_actor_accessors7MyActorC*)* {{.*}} to i8* +// CHECK: {{.*}} = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, i8* [[THUNK_REF]], %swift.context* {{.*}}, %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, i8* {{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// --> Thunk and distributed method accessor for `with_indirect_enums` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTE" +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETF" + +/// First, Load both arguments from the buffer. + +// CHECK: store i8* %1, i8** %offset, align 8 +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[ENUM_PTR:%.*]] = bitcast i8* %elt_offset to %T27distributed_actor_accessors9IndirectEO* +// CHECK-NEXT: %argval = load %T27distributed_actor_accessors9IndirectEO, %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]], align 8 +// CHECK-NEXT: [[OPAQUE_ENUM_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* %argval.coercion.coerced to i8* +// CHECK: store %T27distributed_actor_accessors9IndirectEO %argval, %T27distributed_actor_accessors9IndirectEO* %argval.coercion.coerced, align 8 +// CHECK-NEXT: [[COERCED_ENUM_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* %argval.coercion.coerced to i64* +// CHECK-NEXT: [[NATIVE_ENUM_VAL:%.*]] = load i64, i64* [[COERCED_ENUM_PTR]], align 8 +// CHECK: [[ENUM_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]] to i64 +// CHECK-NEXT: [[NEXT_ELT_LOC:%.*]] = add i64 [[ENUM_PTR_INT]], 8 +// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 %13 to i8* +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 +// CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[INT_PTR:%.*]] = bitcast i8* %elt_offset1 to %TSi* +// CHECK-NEXT: %argval2 = load %TSi, %TSi* [[INT_PTR]], align 8 +// CHECK-NEXT: [[OPAQUE_INT_PTR:%.*]] = bitcast %TSi* %argval2.coercion.coerced to i8* +// CHECK: store %TSi %argval2, %TSi* %argval2.coercion.coerced, align 8 +// CHECK-NEXT: [[COERCED_INT_PTR:%.*]] = bitcast %TSi* %argval2.coercion.coerced to i64* +// CHECK-NEXT: [[NATIVE_INT_VAL:%.*]] = load i64, i64* [[COERCED_INT_PTR]], align 8 + +/// Call distributed thunk with extracted arguments. + +// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, i64, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8i64p0s_swift.errorss({{.*}}, %swift.context* {{.*}}, i64 [[NATIVE_ENUM_VAL]], i64 [[NATIVE_INT_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 0 +// CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) +// CHECK: [[ENUM_RESULT:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 1 +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, i64 [[ENUM_RESULT]], %swift.error* {{.*}}) + +/// ---> Thunk and distributed method for `complex` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTE" + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETF"(%T27distributed_actor_accessors11LargeStructV* noalias nocapture [[INDIRECT_RES:%.*]], %swift.context* swiftasync %1, i8* %2, %swift.refcounted* swiftself %3) + +/// First, let's check that all of the different argument types here are loaded correctly. + +/// -> [Int] + +// CHECK: %elt_offset = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[ARR_PTR:%.*]] = bitcast i8* %elt_offset to %TSa* +// CHECK-NEXT: %argval = load %TSa, %TSa* [[ARR_PTR]], align 8 +// CHECK: store %TSa %argval, %TSa* %argval.coercion.coerced, align 8 +// CHECK-NEXT: [[PTR_TO_NATIVE_ARR:%.*]] = bitcast %TSa* %argval.coercion.coerced to %swift.bridge** +// CHECK-NEXT: [[NATIVE_ARR_VAL:%.*]] = load %swift.bridge*, %swift.bridge** [[PTR_TO_NATIVE_ARR]], align 8 +// CHECK: [[ARR_PTR_INT:%.*]] = ptrtoint %TSa* [[ARR_PTR]] to i64 +// CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[ARR_PTR_INT]], 8 +// CHECK-NEXT: [[OPAQUE_NEXT_ELT:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* +// CHECK-NEXT: store i8* [[OPAQUE_NEXT_ELT]], i8** %offset, align 8 + +/// -> Obj + +// CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[OBJ_PTR:%.*]] = bitcast i8* %elt_offset1 to %T27distributed_actor_accessors3ObjC** +// CHECK-NEXT: [[NATIVE_OBJ_VAL:%.*]] = load %T27distributed_actor_accessors3ObjC*, %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]], align 8 +// CHECK-NEXT: [[OBJ_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]] to i64 +// CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[OBJ_PTR_INT]], 8 +// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 %18 to i8* +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 + +/// -> String? + +// CHECK-NEXT: %elt_offset3 = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[OPT_PTR:%.*]] = bitcast i8* %elt_offset3 to %TSSSg* +// CHECK-NEXT: %argval4 = load %TSSSg, %TSSSg* [[OPT_PTR]], align 8 +// CHECK: store %TSSSg %argval4, %TSSSg* %argval4.coercion.coerced, align 8 +// CHECK-NEXT: [[NATIVE_OPT_PTR:%.*]] = bitcast %TSSSg* %argval4.coercion.coerced to { i64, i64 }* +// CHECK-NEXT: [[NATIVE_OPT_VAL:%.*]] = load { i64, i64 }, { i64, i64 }* [[NATIVE_OPT_PTR]], align 8 +// CHECK: [[NATIVE_OPT_VAL_0:%.*]] = extractvalue { i64, i64 } [[NATIVE_OPT_VAL]], 0 +// CHECK-NEXT: [[NATIVE_OPT_VAL_1:%.*]] = extractvalue { i64, i64 } [[NATIVE_OPT_VAL]], 1 +// CHECK-NEXT: [[OPT_PTR_INT:%.*]] = ptrtoint %TSSSg* [[OPT_PTR]] to i64 +// CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[OPT_PTR_INT]], 16 +// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 + +/// -> LargeStruct (passed indirectly) + +// CHECK-NEXT: %elt_offset5 = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[STRUCT_PTR:%.*]] = bitcast i8* %elt_offset5 to %T27distributed_actor_accessors11LargeStructV* +// CHECK-NEXT: [[STRUCT_VAL:%.*]] = load %T27distributed_actor_accessors11LargeStructV, %T27distributed_actor_accessors11LargeStructV* [[STRUCT_PTR]], align 8 +// CHECK: store %T27distributed_actor_accessors11LargeStructV [[STRUCT_VAL]], %T27distributed_actor_accessors11LargeStructV* %argval6.coercion.coerced, align 8 +// CHECK-NEXT: [[PTR_TO_STRUCT:%.*]] = bitcast %T27distributed_actor_accessors11LargeStructV* %argval6.coercion.coerced to %T27distributed_actor_accessors11LargeStructV** +// CHECK-NEXT: [[NATIVE_STRUCT_VAL:%.*]] = load %T27distributed_actor_accessors11LargeStructV*, %T27distributed_actor_accessors11LargeStructV** [[PTR_TO_STRUCT]], align 8 + +/// Now let's make sure that distributed thunk call uses the arguments correctly + +// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, %T27distributed_actor_accessors11LargeStructV* [[INDIRECT_RES]], %swift.context* {{.*}}, %swift.bridge* [[NATIVE_ARR_VAL]], %T27distributed_actor_accessors3ObjC* [[NATIVE_OBJ_VAL]], i64 [[NATIVE_OPT_VAL_0]], i64 [[NATIVE_OPT_VAL_1]], %T27distributed_actor_accessors11LargeStructV* [[NATIVE_STRUCT_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) + +/// RESULT is returned indirectly so there is nothing to pass to `end` + +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) From 8e1aa191883b63a8761be69c89848343d45500ef Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 2 Dec 2021 15:55:38 -0800 Subject: [PATCH 18/38] [Mangling] Define mangling for runtime accessible function records --- docs/ABI/Mangling.rst | 1 + include/swift/AST/ASTMangler.h | 3 ++- include/swift/Demangling/DemangleNodes.def | 3 +++ lib/AST/ASTMangler.cpp | 1 + lib/Demangling/Demangler.cpp | 5 ++++- lib/Demangling/NodePrinter.cpp | 6 ++++++ lib/Demangling/OldRemangler.cpp | 6 ++++++ lib/Demangling/Remangler.cpp | 7 +++++++ test/Demangle/Inputs/manglings.txt | 1 + 9 files changed, 31 insertions(+), 2 deletions(-) diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index ec48374e23c2c..f50f7d764acef 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -143,6 +143,7 @@ Globals global ::= opaque-type 'Ho' // opaque type descriptor runtime record #endif global ::= protocol-conformance 'Hc' // protocol conformance runtime record + global ::= global 'HF' // accessible function runtime record global ::= nominal-type 'Mo' // class metadata immediate member base offset diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 268239efe6b75..dc752268bad18 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -104,7 +104,8 @@ class ASTMangler : public Mangler { SwiftAsObjCThunk, ObjCAsSwiftThunk, DistributedThunk, - DistributedMethodAccessor + DistributedMethodAccessor, + AccessibleFunctionRecord }; ASTMangler(bool DWARFMangling = false) diff --git a/include/swift/Demangling/DemangleNodes.def b/include/swift/Demangling/DemangleNodes.def index 2cb3e50b5722b..f72304a6a27f5 100644 --- a/include/swift/Demangling/DemangleNodes.def +++ b/include/swift/Demangling/DemangleNodes.def @@ -326,5 +326,8 @@ NODE(IndexSubset) NODE(AsyncAwaitResumePartialFunction) NODE(AsyncSuspendResumePartialFunction) +// Added in Swift 5.6 +NODE(AccessibleFunctionRecord) + #undef CONTEXT_NODE #undef NODE diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 38553756a7f25..1d61aa7fc59ed 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -850,6 +850,7 @@ void ASTMangler::appendSymbolKind(SymbolKind SKind) { case SymbolKind::ObjCAsSwiftThunk: return appendOperator("TO"); case SymbolKind::DistributedThunk: return appendOperator("TE"); case SymbolKind::DistributedMethodAccessor: return appendOperator("TF"); + case SymbolKind::AccessibleFunctionRecord: return appendOperator("HF"); } } diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index c58fb863f9b15..1f07fcca398ae 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -140,6 +140,7 @@ bool swift::Demangle::isFunctionAttr(Node::Kind kind) { case Node::Kind::AsyncFunctionPointer: case Node::Kind::AsyncAwaitResumePartialFunction: case Node::Kind::AsyncSuspendResumePartialFunction: + case Node::Kind::AccessibleFunctionRecord: return true; default: return false; @@ -800,7 +801,7 @@ NodePointer Demangler::demangleOperator() { return createWithChild( Node::Kind::ProtocolConformanceRefInProtocolModule, popProtocol()); - // Runtime records (type/protocol/conformance) + // Runtime records (type/protocol/conformance/function) case 'c': return createWithChild(Node::Kind::ProtocolConformanceDescriptorRecord, popProtocolConformance()); @@ -810,6 +811,8 @@ NodePointer Demangler::demangleOperator() { return createWithChild(Node::Kind::OpaqueTypeDescriptorRecord, popNode()); case 'r': return createWithChild(Node::Kind::ProtocolDescriptorRecord, popProtocol()); + case 'F': + return createNode(Node::Kind::AccessibleFunctionRecord); default: pushBack(); diff --git a/lib/Demangling/NodePrinter.cpp b/lib/Demangling/NodePrinter.cpp index 17be1d6b6cbef..f9d3ab1456ea6 100644 --- a/lib/Demangling/NodePrinter.cpp +++ b/lib/Demangling/NodePrinter.cpp @@ -586,6 +586,7 @@ class NodePrinter { case Node::Kind::IndexSubset: case Node::Kind::AsyncAwaitResumePartialFunction: case Node::Kind::AsyncSuspendResumePartialFunction: + case Node::Kind::AccessibleFunctionRecord: return false; } printer_unreachable("bad node kind"); @@ -2003,6 +2004,11 @@ NodePointer NodePrinter::print(NodePointer Node, unsigned depth, Printer << "distributed method accessor for "; } return nullptr; + case Node::Kind::AccessibleFunctionRecord: + if (!Options.ShortenThunk) { + Printer << "accessible function runtime record for "; + } + return nullptr; case Node::Kind::DynamicallyReplaceableFunctionKey: if (!Options.ShortenThunk) { Printer << "dynamically replaceable key for "; diff --git a/lib/Demangling/OldRemangler.cpp b/lib/Demangling/OldRemangler.cpp index 18f317fb3a94d..028b514c55090 100644 --- a/lib/Demangling/OldRemangler.cpp +++ b/lib/Demangling/OldRemangler.cpp @@ -2784,3 +2784,9 @@ Demangle::mangleNodeAsObjcCString(NodePointer node, return remangler.getBufferStr().data(); } + +ManglingError Remangler::mangleAccessibleFunctionRecord(Node *node, + unsigned depth) { + Buffer << "HF"; + return ManglingError::Success; +} diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index ab99098dfbd02..6d0534d7b6e67 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -1618,6 +1618,7 @@ ManglingError Remangler::mangleGlobal(Node *node, unsigned depth) { case Node::Kind::AsyncFunctionPointer: case Node::Kind::AsyncAwaitResumePartialFunction: case Node::Kind::AsyncSuspendResumePartialFunction: + case Node::Kind::AccessibleFunctionRecord: mangleInReverseOrder = true; break; default: @@ -3381,6 +3382,12 @@ ManglingError Remangler::mangleGlobalVariableOnceDeclList(Node *node, return ManglingError::Success; } +ManglingError Remangler::mangleAccessibleFunctionRecord(Node *node, + unsigned depth) { + Buffer << "HF"; + return ManglingError::Success; +} + } // anonymous namespace /// The top-level interface to the remangler. diff --git a/test/Demangle/Inputs/manglings.txt b/test/Demangle/Inputs/manglings.txt index a7ef9b27740d8..8a6c306ef6653 100644 --- a/test/Demangle/Inputs/manglings.txt +++ b/test/Demangle/Inputs/manglings.txt @@ -422,3 +422,4 @@ $s__TJO ---> $s__TJO $s6Foobar7Vector2VAASdRszlE10simdMatrix5scale6rotate9translateSo0C10_double3x3aACySdG_SdAJtFZ0D4TypeL_aySd__GD ---> MatrixType #1 in static (extension in Foobar):Foobar.Vector2.simdMatrix(scale: Foobar.Vector2, rotate: Swift.Double, translate: Foobar.Vector2) -> __C.simd_double3x3 $s17distributed_thunk2DAC1fyyFTE ---> distributed thunk for distributed_thunk.DA.f() -> () $s16distributed_test1XC7computeyS2iFTF ---> distributed method accessor for distributed_test.X.compute(Swift.Int) -> Swift.Int +$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETFHF ---> accessible function runtime record for distributed method accessor for distributed thunk for distributed_actor_accessors.MyActor.simple2(Swift.Int) -> Swift.String From ef4e94ef239d7088b4b58cb6f99632da450fda68 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 2 Dec 2021 21:13:03 -0800 Subject: [PATCH 19/38] [Distributed] IRGen: Define a runtime record for accessible functions A "accessible" function that can be looked up based on a string key, and then called through a fully-abstracted entry point whose arguments can be constructed in code. --- include/swift/ABI/Metadata.h | 23 +++++++++++++++++++++++ include/swift/ABI/MetadataValues.h | 15 +++++++++++++++ include/swift/IRGen/Linking.h | 16 +++++++++++++++- lib/IRGen/IRGenModule.cpp | 4 ++++ lib/IRGen/IRGenModule.h | 2 ++ lib/IRGen/Linking.cpp | 19 ++++++++++++++++--- 6 files changed, 75 insertions(+), 4 deletions(-) diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index b32dc943ff5c8..2ee3e37cbdfe9 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -5036,6 +5036,29 @@ class DynamicReplacementScope uint32_t getFlags() { return flags; } }; +/// An "accessible" function that can be looked up based on a string key, +/// and then called through a fully-abstracted entry point whose arguments +/// can be constructed in code. +template +struct TargetAccessibleFunctionRecord final { +public: + /// The name of the function, which is a unique string assigned to the + /// function so it can be looked up later. + RelativeDirectPointer Name; + + /// The Swift function type, encoded as a mangled name. + RelativeDirectPointer FunctionType; + + /// The fully-abstracted function to call. + RelativeDirectPointer + Function; + + /// Flags providing more information about the function. + AccessibleFunctionFlags Flags; +}; + } // end namespace swift #pragma clang diagnostic pop diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index 1792101cf1ec4..b79884df29918 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -2312,6 +2312,21 @@ enum class ContinuationStatus : size_t { Resumed = 2 }; +/// Flags that go in a TargetAccessibleFunction structure. +class AccessibleFunctionFlags : public FlagSet { +public: + enum { + /// Whether this is a "distributed" actor function. + Distributed = 0, + }; + + explicit AccessibleFunctionFlags(uint32_t bits) : FlagSet(bits) {} + constexpr AccessibleFunctionFlags() {} + + /// Whether the this is a "distributed" actor function. + FLAGSET_DEFINE_FLAG_ACCESSORS(Distributed, isDistributed, setDistributed) +}; + } // end namespace swift #endif // SWIFT_ABI_METADATAVALUES_H diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 633ee4fc60e0e..fd23355ad72e7 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -487,6 +487,10 @@ class LinkEntity { /// An async function pointer for a distributed method accessor. /// The pointer is a SILFunction*. DistributedMethodAccessorAsyncPointer, + + /// Accessible function record, which describes a function that can be + /// looked up by name by the runtime. + AccessibleFunctionRecord, }; friend struct llvm::DenseMapInfo; @@ -1285,6 +1289,15 @@ class LinkEntity { return entity; } + static LinkEntity forAccessibleFunctionRecord(SILFunction *func) { + LinkEntity entity; + entity.Pointer = func; + entity.SecondaryPointer = nullptr; + entity.Data = + LINKENTITY_SET_FIELD(Kind, unsigned(Kind::AccessibleFunctionRecord)); + return entity; + } + LinkEntity getUnderlyingEntityForAsyncFunctionPointer() const { LinkEntity entity; entity.Pointer = Pointer; @@ -1369,7 +1382,8 @@ class LinkEntity { getKind() == Kind::DynamicallyReplaceableFunctionVariable || getKind() == Kind::DynamicallyReplaceableFunctionKey || getKind() == Kind::SILFunction || - getKind() == Kind::DistributedMethodAccessor; + getKind() == Kind::DistributedMethodAccessor || + getKind() == Kind::AccessibleFunctionRecord; } SILFunction *getSILFunction() const { diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 89c9cb80551b6..7f355a56b82ce 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -600,6 +600,10 @@ IRGenModule::IRGenModule(IRGenerator &irgen, DynamicReplacementKeyTy = createStructType(*this, "swift.dyn_repl_key", {RelativeAddressTy, Int32Ty}); + AccessibleFunctionRecordTy = createStructType( + *this, "swift.accessible_function", + {RelativeAddressTy, RelativeAddressTy, RelativeAddressTy, Int32Ty}); + AsyncFunctionPointerTy = createStructType(*this, "swift.async_func_pointer", {RelativeAddressTy, Int32Ty}, true); SwiftContextTy = llvm::StructType::create(getLLVMContext(), "swift.context"); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 1fc722a85a764..b9be8924c01ab 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -728,6 +728,8 @@ class IRGenModule { *DynamicReplacementLinkEntryPtrTy; // %link_entry* llvm::StructType *DynamicReplacementKeyTy; // { i32, i32} + llvm::StructType *AccessibleFunctionRecordTy; // { i32*, i32*, i32} + llvm::StructType *AsyncFunctionPointerTy; // { i32, i32 } llvm::StructType *SwiftContextTy; llvm::StructType *SwiftTaskTy; diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index da10d1da3c5a5..24a3b16a6718f 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -504,6 +504,12 @@ std::string LinkEntity::mangleAsString() const { Result.append("TF"); return Result; } + + case Kind::AccessibleFunctionRecord: { + std::string Result(getSILFunction()->getName()); + Result.append("HF"); + return Result; + } } llvm_unreachable("bad entity kind!"); } @@ -805,6 +811,7 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const { return SILLinkage::PublicExternal; case Kind::PartialApplyForwarder: case Kind::DistributedMethodAccessor: + case Kind::AccessibleFunctionRecord: return SILLinkage::Private; } llvm_unreachable("bad link entity kind"); @@ -897,6 +904,7 @@ bool LinkEntity::isContextDescriptor() const { case Kind::PartialApplyForwarder: case Kind::KnownAsyncFunctionPointer: case Kind::DistributedMethodAccessor: + case Kind::AccessibleFunctionRecord: return false; } llvm_unreachable("invalid descriptor"); @@ -1023,6 +1031,8 @@ llvm::Type *LinkEntity::getDefaultDeclarationType(IRGenModule &IGM) const { return IGM.AsyncFunctionPointerTy; case Kind::PartialApplyForwarder: return IGM.FunctionPtrTy; + case Kind::AccessibleFunctionRecord: + return IGM.AccessibleFunctionRecordTy; default: llvm_unreachable("declaration LLVM type not specified"); } @@ -1053,6 +1063,7 @@ Alignment LinkEntity::getAlignment(IRGenModule &IGM) const { case Kind::MethodDescriptorAllocator: case Kind::OpaqueTypeDescriptor: case Kind::OpaqueTypeDescriptorRecord: + case Kind::AccessibleFunctionRecord: return Alignment(4); case Kind::AsyncFunctionPointer: case Kind::DispatchThunkAsyncFunctionPointer: @@ -1208,6 +1219,7 @@ bool LinkEntity::isWeakImported(ModuleDecl *module) const { case Kind::ReflectionFieldDescriptor: case Kind::CoroutineContinuationPrototype: case Kind::DifferentiabilityWitness: + case Kind::AccessibleFunctionRecord: return false; case Kind::AsyncFunctionPointer: @@ -1348,9 +1360,10 @@ DeclContext *LinkEntity::getDeclContextForEmission() const { return getUnderlyingEntityForAsyncFunctionPointer() .getDeclContextForEmission(); - case Kind::DistributedMethodAccessor: { - auto *methodDC = getSILFunction()->getDeclContext(); - return methodDC->getParentModule(); + case Kind::DistributedMethodAccessor: + case Kind::AccessibleFunctionRecord: { + auto *funcDC = getSILFunction()->getDeclContext(); + return funcDC->getParentModule(); } } llvm_unreachable("invalid decl kind"); From a83101787d57a035351a0bbc49d0374005725b39 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 3 Dec 2021 13:32:31 -0800 Subject: [PATCH 20/38] [IRGen] Implement accessible function section/record emission Uses a dedicated section in the binary to emit records about functions that can be looked up by name at the runtime, and then called through a fully-abstracted entry point whose arguments can be constructed in code. --- lib/IRGen/GenDecl.cpp | 84 ++++++++++++++++++++ lib/IRGen/IRGen.cpp | 3 + lib/IRGen/IRGenModule.h | 14 +++- lib/IRGen/IRGenSIL.cpp | 5 +- test/IRGen/distributed_actor_accessors.swift | 63 +++++++++++++++ 5 files changed, 167 insertions(+), 2 deletions(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index dcbfa17a1134f..05bd976db7f70 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -1272,6 +1272,11 @@ void IRGenerator::emitTypeMetadataRecords() { } } +void IRGenerator::emitAccessibleFunctions() { + for (auto &m : *this) + m.second->emitAccessibleFunctions(); +} + static void deleteAndReenqueueForEmissionValuesDependentOnCanonicalPrespecializedMetadataRecords( IRGenModule &IGM, CanType typeWithCanonicalMetadataPrespecialization, @@ -3889,6 +3894,11 @@ void IRGenModule::addProtocolConformance(ConformanceDescription &&record) { ProtocolConformances.push_back(std::move(record)); } +void IRGenModule::addAccessibleFunction(SILFunction *func, + llvm::Function *thunk) { + AccessibleFunctions.push_back({func, thunk}); +} + /// Emit the protocol conformance list and return it (if asContiguousArray is /// true, otherwise the records are emitted as individual globals and /// nullptr is returned). @@ -4090,6 +4100,80 @@ llvm::Constant *IRGenModule::emitTypeMetadataRecords(bool asContiguousArray) { return nullptr; } +void IRGenModule::emitAccessibleFunctions() { + if (AccessibleFunctions.empty()) + return; + + StringRef sectionName; + switch (TargetInfo.OutputObjectFormat) { + case llvm::Triple::GOFF: + case llvm::Triple::UnknownObjectFormat: + llvm_unreachable("Don't know how to emit accessible functions for " + "the selected object format."); + case llvm::Triple::MachO: + sectionName = "__TEXT, __swift5_acfunc, regular"; + break; + case llvm::Triple::ELF: + case llvm::Triple::Wasm: + sectionName = "swift5_accessible_functions"; + break; + case llvm::Triple::XCOFF: + case llvm::Triple::COFF: + sectionName = ".sw5acfn$B"; + break; + } + + for (const auto &entry : AccessibleFunctions) { + SILFunction *func = entry.first; + llvm::Function *thunk = entry.second; + + auto mangledRecordName = + LinkEntity::forAccessibleFunctionRecord(func).mangleAsString(); + + auto var = new llvm::GlobalVariable( + Module, AccessibleFunctionRecordTy, /*isConstant*/ true, + llvm::GlobalValue::PrivateLinkage, /*initializer*/ nullptr, + mangledRecordName); + + std::string mangledFunctionName = + LinkEntity::forSILFunction(func).mangleAsString(); + llvm::Constant *name = getAddrOfGlobalString( + mangledFunctionName, /*willBeRelativelyAddressed*/ true); + llvm::Constant *relativeName = emitDirectRelativeReference(name, var, {}); + + GenericSignature signature; + if (auto *env = func->getGenericEnvironment()) { + signature = env->getGenericSignature(); + } + + llvm::Constant *type = getTypeRef(func->getLoweredFunctionType(), signature, + MangledTypeRefRole::Metadata) + .first; + llvm::Constant *relativeType = emitDirectRelativeReference(type, var, {1}); + + llvm::Function *funcAddr = + thunk ? thunk : getAddrOfSILFunction(func, NotForDefinition); + llvm::Constant *relativeFuncAddr = + emitDirectRelativeReference(funcAddr, var, {2}); + + AccessibleFunctionFlags flagsVal; + flagsVal.setDistributed(func->isDistributed()); + + llvm::Constant *flags = + llvm::ConstantInt::get(Int32Ty, flagsVal.getOpaqueValue()); + + llvm::Constant *recordFields[] = {relativeName, relativeType, + relativeFuncAddr, flags}; + auto record = + llvm::ConstantStruct::get(AccessibleFunctionRecordTy, recordFields); + var->setInitializer(record); + var->setSection(sectionName); + var->setAlignment(llvm::MaybeAlign(4)); + disableAddressSanitizer(*this, var); + addUsedGlobal(var); + } +} + /// Fetch a global reference to a reference to the given Objective-C class. /// The result is of type ObjCClassPtrTy->getPointerTo(). Address IRGenModule::getAddrOfObjCClassRef(ClassDecl *theClass) { diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 4a52cda0ab55e..7d86facb6975c 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -1118,6 +1118,7 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator, IGM.emitSwiftProtocols(/*asContiguousArray*/ false); IGM.emitProtocolConformances(/*asContiguousArray*/ false); IGM.emitTypeMetadataRecords(/*asContiguousArray*/ false); + IGM.emitAccessibleFunctions(); IGM.emitBuiltinReflectionMetadata(); IGM.emitReflectionMetadataVersion(); irgen.emitEagerClassInitialization(); @@ -1361,6 +1362,8 @@ static void performParallelIRGeneration(IRGenDescriptor desc) { irgen.emitTypeMetadataRecords(); + irgen.emitAccessibleFunctions(); + irgen.emitReflectionMetadataVersion(); irgen.emitEagerClassInitialization(); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index b9be8924c01ab..d6b2325b3e9f1 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -401,6 +401,10 @@ class IRGenerator { /// Emit type metadata records for types without explicit protocol conformance. void emitTypeMetadataRecords(); + /// Emit type metadata recrods for functions that can be looked up by name at + /// runtime. + void emitAccessibleFunctions(); + /// Emit reflection metadata records for builtin and imported types referenced /// from this module. void emitBuiltinReflectionMetadata(); @@ -1037,11 +1041,14 @@ class IRGenModule { void addObjCClass(llvm::Constant *addr, bool nonlazy); void addObjCClassStub(llvm::Constant *addr); void addProtocolConformance(ConformanceDescription &&conformance); + void addAccessibleFunction(SILFunction *func, + llvm::Function *thunk = nullptr); llvm::Constant *emitSwiftProtocols(bool asContiguousArray); llvm::Constant *emitProtocolConformances(bool asContiguousArray); llvm::Constant *emitTypeMetadataRecords(bool asContiguousArray); - llvm::Constant *emitFieldDescriptors(); + + void emitAccessibleFunctions(); llvm::Constant *getConstantSignedFunctionPointer(llvm::Constant *fn, CanSILFunctionType fnType); @@ -1170,6 +1177,11 @@ class IRGenModule { /// List of ExtensionDecls corresponding to the generated /// categories. SmallVector ObjCCategoryDecls; + /// List of all of the functions, which can be lookup by name + /// up at runtime. Second element is an optional "accessor" thunk + /// to call the given function through. + SmallVector, 4> + AccessibleFunctions; /// Map of Objective-C protocols and protocol references, bitcast to i8*. /// The interesting global variables relating to an ObjC protocol. diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index a32763d87b9f4..a9e75fe03e3ee 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2199,9 +2199,12 @@ void IRGenSILFunction::emitSILFunction() { IGM.noteSwiftAsyncFunctionDef(); } - // Generate accessor thunk for the `distributed` method. + // Emit distributed accessor, and mark the thunk as accessible + // by name at runtime through it. if (CurSILFn->isDistributed() && CurSILFn->isThunk()) { IGM.emitDistributedMethodAccessor(CurSILFn); + IGM.addAccessibleFunction(CurSILFn, IGM.getAddrOfDistributedMethodAccessor( + CurSILFn, NotForDefinition)); } // Configure the dominance resolver. diff --git a/test/IRGen/distributed_actor_accessors.swift b/test/IRGen/distributed_actor_accessors.swift index e651af0c562c2..5f822d6c744c6 100644 --- a/test/IRGen/distributed_actor_accessors.swift +++ b/test/IRGen/distributed_actor_accessors.swift @@ -70,6 +70,69 @@ public distributed actor MyActor { } } +@available(SwiftStdlib 5.6, *) +public distributed actor MyOtherActor { + public typealias Transport = AnyActorTransport + + distributed func empty() { + } +} + + +/// ---> Let's check that distributed accessors and thunks are emitted as accessible functions + +/// -> `MyActor.simple1` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" = private constant +// CHECK-SAME: @"symbolic Si___________pIetMHygzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETF" +// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" + +/// -> `MyActor.simple2` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" = private constant +// CHECK-SAME: @"symbolic Si_____SS______pIetMHygozo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETF" +// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" + +/// -> `MyActor.simple3` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" = private constant +// CHECK-SAME: @"symbolic SS_____Si______pIetMHggdzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETF" +// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" + +/// -> `MyActor.single_case_enum` +// CHECK: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" = private constant +// CHECK-SAME: @"symbolic __________AA______pIetMHygdzo_ 27distributed_actor_accessors7SimpleEO AA7MyActorC s5ErrorP" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETF" +// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" + +/// -> `MyActor.with_indirect_enums` +// CHECK: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" = private constant +// CHECK-SAME: @"symbolic _____Si_____AA______pIetMHgygozo_ 27distributed_actor_accessors9IndirectEO AA7MyActorC s5ErrorP" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETF" +// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" + +/// -> `MyActor.complex` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" = private constant +// CHECK-SAME: @"symbolic SaySiG_____SSSg__________AD______pIetMHgggngrzo_ 27distributed_actor_accessors3ObjC AA11LargeStructV AA7MyActorC s5ErrorP" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETF" +// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" + +/// -> `MyOtherActor.empty` +// CHECK: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" = private constant +// CHECK-SAME: @"symbolic ___________pIetMHgzo_ 27distributed_actor_accessors12MyOtherActorC s5ErrorP" +// CHECK-SAME: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETF" +// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" + +// CHECK: @llvm.used = appending global [{{.*}} x i8*] [ +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" +// CHECK-SAME: ], section "llvm.metadata" + /// ---> Thunk and distributed method accessor for `simple1` /// Let's make sure that accessor loads the data from the buffer and calls expected accessor From 0060859c181c0a5c80028d6857a45e41972c9c4b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 3 Dec 2021 13:50:45 -0800 Subject: [PATCH 21/38] [Distributed] IRGen: Don't allocate offset pointer if there is nothing to load If underlying function does not have any parameter, then let's exit early and avoid stack allocating the argument buffer cursor. --- lib/IRGen/GenDistributed.cpp | 9 +++++++-- test/IRGen/distributed_actor_accessors.swift | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index bfb25b85d1648..f259b54f88dd3 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -172,6 +172,13 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, Explosion &arguments) { auto fnType = Method->getLoweredFunctionType(); + // Cover all of the arguments except to `self` of the actor. + auto parameters = fnType->getParameters().drop_back(); + + // If there are no parameters to extract, we are done. + if (parameters.empty()) + return; + auto offset = IGF.createAlloca(IGM.Int8PtrTy, IGM.getPointerAlignment(), "offset"); IGF.Builder.CreateLifetimeStart(offset, IGM.getPointerSize()); @@ -179,8 +186,6 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, // Initialize "offset" with the address of the base of the argument buffer. IGF.Builder.CreateStore(argumentBuffer, offset); - // Cover all of the arguments except to `self` of the actor. - auto parameters = fnType->getParameters().drop_back(); for (const auto ¶m : parameters) { auto paramTy = param.getSILStorageInterfaceType(); const TypeInfo &typeInfo = IGF.getTypeInfo(paramTy); diff --git a/test/IRGen/distributed_actor_accessors.swift b/test/IRGen/distributed_actor_accessors.swift index 5f822d6c744c6..eda5ac0e50b30 100644 --- a/test/IRGen/distributed_actor_accessors.swift +++ b/test/IRGen/distributed_actor_accessors.swift @@ -341,3 +341,17 @@ public distributed actor MyOtherActor { /// RESULT is returned indirectly so there is nothing to pass to `end` // CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// ---> Thunk and distributed method for `MyOtherActor.empty` + +/// Let's check that there is no offset allocation here since parameter list is empty + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETF" +// CHECK-NEXT: entry: +// CHECK-NEXT: {{.*}} = alloca %swift.context*, align 8 +// CHECK-NEXT: %swifterror = alloca swifterror %swift.error*, align 8 +// CHECK-NEXT: {{.*}} = call token @llvm.coro.id.async(i32 20, i32 16, i32 0, i8* bitcast (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i8*)) +// CHECK-NEXT: {{.*}} = call i8* @llvm.coro.begin(token %4, i8* null) +// CHECK-NEXT: store %swift.context* {{.*}}, %swift.context** {{.*}}, align 8 +// CHECK-NEXT: store %swift.error* null, %swift.error** %swifterror, align 8 +// CHECK-NEXT: {{.*}} = load i32, i32* getelementptr inbounds (%swift.async_func_pointer, %swift.async_func_pointer* bitcast (void (%swift.context*, %T27distributed_actor_accessors12MyOtherActorC*)* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTE" to %swift.async_func_pointer*), i32 0, i32 0), align 8 From be08a8ba8c9a8fc1a5b33276184d4cf3a6fd4aa8 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 6 Dec 2021 10:09:26 -0800 Subject: [PATCH 22/38] [Distributed] IRGen: Pluralize the name of accessible functions section --- lib/IRGen/GenDecl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 05bd976db7f70..b5a3f1119253e 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -4111,7 +4111,7 @@ void IRGenModule::emitAccessibleFunctions() { llvm_unreachable("Don't know how to emit accessible functions for " "the selected object format."); case llvm::Triple::MachO: - sectionName = "__TEXT, __swift5_acfunc, regular"; + sectionName = "__TEXT, __swift5_acfuncs, regular"; break; case llvm::Triple::ELF: case llvm::Triple::Wasm: From 3f4c06eb1bad665bb5bb3041ca80d082a98d7302 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 6 Dec 2021 11:38:37 -0800 Subject: [PATCH 23/38] [Distributed] Runtime: Add skeleton support for accessible function sections --- include/swift/ABI/Metadata.h | 2 + stdlib/public/SwiftShims/MetadataSections.h | 1 + stdlib/public/runtime/AccessibleFunction.cpp | 80 +++++++++++++++++++ stdlib/public/runtime/CMakeLists.txt | 3 +- stdlib/public/runtime/ImageInspection.h | 7 ++ .../public/runtime/ImageInspectionCommon.cpp | 24 +++++- stdlib/public/runtime/ImageInspectionCommon.h | 3 + .../public/runtime/ImageInspectionMachO.cpp | 8 ++ .../public/runtime/ImageInspectionStatic.cpp | 9 +++ 9 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 stdlib/public/runtime/AccessibleFunction.cpp diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 2ee3e37cbdfe9..4cf322ebfa2eb 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -5059,6 +5059,8 @@ struct TargetAccessibleFunctionRecord final { AccessibleFunctionFlags Flags; }; +using AccessibleFunctionRecord = TargetAccessibleFunctionRecord; + } // end namespace swift #pragma clang diagnostic pop diff --git a/stdlib/public/SwiftShims/MetadataSections.h b/stdlib/public/SwiftShims/MetadataSections.h index 939b49d969d05..47de4f0ea70bc 100644 --- a/stdlib/public/SwiftShims/MetadataSections.h +++ b/stdlib/public/SwiftShims/MetadataSections.h @@ -64,6 +64,7 @@ struct MetadataSections { MetadataSectionRange swift5_replac2; MetadataSectionRange swift5_builtin; MetadataSectionRange swift5_capture; + MetadataSectionRange swift5_accessible_functions; }; #ifdef __cplusplus diff --git a/stdlib/public/runtime/AccessibleFunction.cpp b/stdlib/public/runtime/AccessibleFunction.cpp new file mode 100644 index 0000000000000..3f903c393fb18 --- /dev/null +++ b/stdlib/public/runtime/AccessibleFunction.cpp @@ -0,0 +1,80 @@ +//===---- AccessibleFunction.cpp - Swift protocol conformance checking ----===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// Checking and caching of Swift accessible functions. +// +//===----------------------------------------------------------------------===// + +#include "ImageInspection.h" +#include "Private.h" +#include "swift/Basic/Lazy.h" +#include "swift/Demangling/Demangler.h" +#include "swift/Runtime/Concurrent.h" +#include "swift/Runtime/Metadata.h" +#include "Private.h" + +#include + +using namespace swift; + +#pragma mark Accessible function cache +namespace { + +struct AccessibleFunctionsSection { + const AccessibleFunctionRecord *Begin, *End; + + AccessibleFunctionsSection(const AccessibleFunctionRecord *begin, + const AccessibleFunctionRecord *end) + : Begin(begin), End(end) {} + + AccessibleFunctionsSection(const void *ptr, uintptr_t size) { + auto bytes = reinterpret_cast(ptr); + Begin = reinterpret_cast(ptr); + End = reinterpret_cast(bytes + size); + } + + const AccessibleFunctionRecord *begin() const { return Begin; } + const AccessibleFunctionRecord *end() const { return End; } +}; + +struct AccessibleFunctionsState { + ConcurrentReadableArray SectionsToScan; + + AccessibleFunctionsState() { + initializeAccessibleFunctionsLookup(); + } +}; + +static Lazy Functions; + +} // end anonymous namespace + +static void _registerAccessibleFunctions(AccessibleFunctionsState &C, + AccessibleFunctionsSection section) { + C.SectionsToScan.push_back(section); +} + +void swift::addImageAccessibleFunctionsBlockCallbackUnsafe(const void *functions, + uintptr_t size) { + assert( + size % sizeof(AccessibleFunctionRecord) == 0 && + "accessible function section not a multiple of AccessibleFunctionRecord"); + + auto &C = Functions.unsafeGetAlreadyInitialized(); + _registerAccessibleFunctions(C, AccessibleFunctionsSection{functions, size}); +} + +void swift::addImageAccessibleFunctionsBlockCallback(const void *functions, + uintptr_t size) { + Functions.get(); + addImageAccessibleFunctionsBlockCallbackUnsafe(functions, size); +} diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 77ca35cac3431..5a5216f3135dc 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -68,7 +68,8 @@ set(swift_runtime_sources ReflectionMirror.cpp RuntimeInvocationsTracking.cpp SwiftDtoa.cpp - SwiftTLSContext.cpp) + SwiftTLSContext.cpp + AccessibleFunction.cpp) # Acknowledge that the following sources are known. set(LLVM_OPTIONAL_SOURCES diff --git a/stdlib/public/runtime/ImageInspection.h b/stdlib/public/runtime/ImageInspection.h index b205b7c211dc8..159405246ef1b 100644 --- a/stdlib/public/runtime/ImageInspection.h +++ b/stdlib/public/runtime/ImageInspection.h @@ -73,6 +73,9 @@ void initializeTypeMetadataRecordLookup(); /// Load the metadata from the image necessary to perform dynamic replacements. void initializeDynamicReplacementLookup(); +/// Load the metadata from the image necessary to find functions by name. +void initializeAccessibleFunctionsLookup(); + // Callbacks to register metadata from an image to the runtime. void addImageProtocolsBlockCallback(const void *start, uintptr_t size); void addImageProtocolsBlockCallbackUnsafe(const void *start, uintptr_t size); @@ -87,6 +90,10 @@ void addImageTypeMetadataRecordBlockCallbackUnsafe(const void *start, void addImageDynamicReplacementBlockCallback(const void *start, uintptr_t size, const void *start2, uintptr_t size2); +void addImageAccessibleFunctionsBlockCallback(const void *start, + uintptr_t size); +void addImageAccessibleFunctionsBlockCallbackUnsafe(const void *start, + uintptr_t size); int lookupSymbol(const void *address, SymbolInfo *info); diff --git a/stdlib/public/runtime/ImageInspectionCommon.cpp b/stdlib/public/runtime/ImageInspectionCommon.cpp index c70e886c06806..34e3eab5b2b91 100644 --- a/stdlib/public/runtime/ImageInspectionCommon.cpp +++ b/stdlib/public/runtime/ImageInspectionCommon.cpp @@ -81,6 +81,13 @@ void swift_addNewDSOImage(const void *addr) { replacements, dynamic_replacements.length, replacements_some, dynamic_replacements_some.length); } + + const auto &accessible_funcs_section = sections->swift5_accessible_functions; + const void *functions = + reinterpret_cast(accessible_funcs_section.start); + if (accessible_funcs_section.length) + swift::addImageAccessibleFunctionsBlockCallback( + functions, accessible_funcs_section.length); } void swift::initializeProtocolLookup() { @@ -131,6 +138,21 @@ void swift::initializeTypeMetadataRecordLookup() { void swift::initializeDynamicReplacementLookup() { } +void swift::initializeAccessibleFunctionsLookup() { + const swift::MetadataSections *sections = registered; + while (true) { + const swift::MetadataSectionRange &functions = + sections->swift5_accessible_functions; + if (functions.length) + addImageAccessibleFunctionsBlockCallbackUnsafe( + reinterpret_cast(functions.start), functions.length); + + if (sections->next == registered) + break; + sections = sections->next; + } +} + #ifndef NDEBUG SWIFT_RUNTIME_EXPORT @@ -177,4 +199,4 @@ size_t swift_getMetadataSectionCount() { #endif // !defined(__MACH__) -#endif // SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H \ No newline at end of file +#endif // SWIFT_RUNTIME_IMAGEINSPECTIONCOMMON_H diff --git a/stdlib/public/runtime/ImageInspectionCommon.h b/stdlib/public/runtime/ImageInspectionCommon.h index 56f1ea9774fd3..d5638d059ce3f 100644 --- a/stdlib/public/runtime/ImageInspectionCommon.h +++ b/stdlib/public/runtime/ImageInspectionCommon.h @@ -34,6 +34,9 @@ /// This lives within SEG_TEXT. #define MachODynamicReplacementSection "__swift5_replace" #define MachODynamicReplacementSomeSection "__swift5_replac2" +/// The Mach-O section name for the section containing accessible functions. +/// This lives within SEG_TEXT. +#define MachOAccessibleFunctionsSection "__swift5_acfuncs" #define MachOTextSegment "__TEXT" diff --git a/stdlib/public/runtime/ImageInspectionMachO.cpp b/stdlib/public/runtime/ImageInspectionMachO.cpp index b39816492828d..47b72ca71a665 100644 --- a/stdlib/public/runtime/ImageInspectionMachO.cpp +++ b/stdlib/public/runtime/ImageInspectionMachO.cpp @@ -43,6 +43,8 @@ constexpr const char DynamicReplacementSection[] = MachODynamicReplacementSection; constexpr const char DynamicReplacementSomeSection[] = MachODynamicReplacementSomeSection; +constexpr const char AccessibleFunctionsSection[] = + MachOAccessibleFunctionsSection; constexpr const char TextSegment[] = MachOTextSegment; #if __POINTER_WIDTH__ == 64 @@ -159,6 +161,12 @@ void swift::initializeDynamicReplacementLookup() { addImageDynamicReplacementBlockCallback>); } +void swift::initializeAccessibleFunctionsLookup() { + REGISTER_FUNC( + addImageCallback); +} + #if SWIFT_STDLIB_HAS_DLADDR int swift::lookupSymbol(const void *address, SymbolInfo *info) { Dl_info dlinfo; diff --git a/stdlib/public/runtime/ImageInspectionStatic.cpp b/stdlib/public/runtime/ImageInspectionStatic.cpp index 33181fad4a5b2..2fb1bfdeee217 100644 --- a/stdlib/public/runtime/ImageInspectionStatic.cpp +++ b/stdlib/public/runtime/ImageInspectionStatic.cpp @@ -74,5 +74,14 @@ void swift::initializeDynamicReplacementLookup() { return; addImageDynamicReplacementBlockCallback(start1, size1, start2, size2); } +void swift::initializeAccessibleFunctionsLookup() { + void *start; + uintptr_t size; + GET_SECTION_START_AND_SIZE(start, size, MachOTextSegment, + MachOAccessibleFunctionsSection); + if (start == nullptr || size == 0) + return; + addImageAccessibleFunctionBlockCallbackUnsafe(start, size); +} #endif // defined(__MACH__) && defined(SWIFT_RUNTIME_STATIC_IMAGE_INSPECTION) From 7eee8c0dd2165958ffc6829b3b88e1c17b8e9ecb Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Mon, 6 Dec 2021 13:50:42 -0800 Subject: [PATCH 24/38] [Distributed] Runtime: Cache previously requested accessible functions --- stdlib/public/runtime/AccessibleFunction.cpp | 75 ++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/stdlib/public/runtime/AccessibleFunction.cpp b/stdlib/public/runtime/AccessibleFunction.cpp index 3f903c393fb18..e9c0c5f2db410 100644 --- a/stdlib/public/runtime/AccessibleFunction.cpp +++ b/stdlib/public/runtime/AccessibleFunction.cpp @@ -46,7 +46,42 @@ struct AccessibleFunctionsSection { const AccessibleFunctionRecord *end() const { return End; } }; +struct AccessibleFunctionCacheEntry { +private: + const char *Name; + size_t NameLength; + + const AccessibleFunctionRecord *Func; + +public: + AccessibleFunctionCacheEntry(llvm::StringRef name, + const AccessibleFunctionRecord *func) + : Func(func) { + char *Name = reinterpret_cast(malloc(name.size())); + memcpy(Name, name.data(), name.size()); + + this->Name = Name; + this->NameLength = name.size(); + } + + const AccessibleFunctionRecord *getFunction() const { return Func; } + + bool matchesKey(llvm::StringRef name) { + return name == llvm::StringRef{Name, NameLength}; + } + + friend llvm::hash_code hash_value(const AccessibleFunctionCacheEntry &value) { + return hash_value(llvm::StringRef{value.Name, value.NameLength}); + } + + template + static size_t getExtraAllocationSize(T &&...ignored) { + return 0; + } +}; + struct AccessibleFunctionsState { + ConcurrentReadableHashMap Cache; ConcurrentReadableArray SectionsToScan; AccessibleFunctionsState() { @@ -78,3 +113,43 @@ void swift::addImageAccessibleFunctionsBlockCallback(const void *functions, Functions.get(); addImageAccessibleFunctionsBlockCallbackUnsafe(functions, size); } + +static const AccessibleFunctionRecord * +_searchForFunctionRecord(AccessibleFunctionsState &S, llvm::StringRef name) { + for (const auto §ion : S.SectionsToScan.snapshot()) { + for (auto &record : section) { + auto recordName = + swift::Demangle::makeSymbolicMangledNameStringRef(record.Name.get()); + if (recordName == name) + return &record; + } + } + return nullptr; +} + +static const AccessibleFunctionRecord * +_findAccessibleFunction(llvm::StringRef name) { + auto &S = Functions.get(); + + // Look for an existing entry. + { + auto snapshot = S.Cache.snapshot(); + if (auto E = snapshot.find(name)) + return E->getFunction(); + } + + // If entry doesn't exist (either record doesn't exist, hasn't been loaded, or + // requested yet), let's try to find it and add to the cache. + + auto *function = _searchForFunctionRecord(S, name); + if (function) { + S.Cache.getOrInsert( + name, [&](AccessibleFunctionCacheEntry *entry, bool created) { + if (created) + new (entry) AccessibleFunctionCacheEntry{name, function}; + return true; + }); + } + + return function; +} From d65906b1e873d64c01ae793009871c4a9400dfe5 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 7 Dec 2021 14:31:45 -0800 Subject: [PATCH 25/38] [Runtime] Expose accessible function lookup as stdlib SPI `findAccessibleFunction` has to be accessible from Concurrency and Distributed modules to be able to lookup distributed accessors. --- include/swift/Runtime/AccessibleFunction.h | 34 ++++++++++++++++++++ stdlib/public/runtime/AccessibleFunction.cpp | 10 ++++-- 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 include/swift/Runtime/AccessibleFunction.h diff --git a/include/swift/Runtime/AccessibleFunction.h b/include/swift/Runtime/AccessibleFunction.h new file mode 100644 index 0000000000000..a69d6b262b838 --- /dev/null +++ b/include/swift/Runtime/AccessibleFunction.h @@ -0,0 +1,34 @@ +//===---- AcceesibleFunction.h - Runtime accessible functions ---*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// The runtime interface for functions accessible by name. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_RUNTIME_ACCESSIBLE_FUNCTION_H +#define SWIFT_RUNTIME_ACCESSIBLE_FUNCTION_H + +#include "swift/ABI/Metadata.h" + +#include + +namespace swift { +namespace runtime { + +SWIFT_RUNTIME_STDLIB_SPI const AccessibleFunctionRecord * +swift_findAccessibleFunction(const char *targetNameStart, + size_t targetNameLength); + +} // end namespace runtime +} // end namespace swift + +#endif diff --git a/stdlib/public/runtime/AccessibleFunction.cpp b/stdlib/public/runtime/AccessibleFunction.cpp index e9c0c5f2db410..16569337f6ae3 100644 --- a/stdlib/public/runtime/AccessibleFunction.cpp +++ b/stdlib/public/runtime/AccessibleFunction.cpp @@ -18,9 +18,9 @@ #include "Private.h" #include "swift/Basic/Lazy.h" #include "swift/Demangling/Demangler.h" +#include "swift/Runtime/AccessibleFunction.h" #include "swift/Runtime/Concurrent.h" #include "swift/Runtime/Metadata.h" -#include "Private.h" #include @@ -127,10 +127,14 @@ _searchForFunctionRecord(AccessibleFunctionsState &S, llvm::StringRef name) { return nullptr; } -static const AccessibleFunctionRecord * -_findAccessibleFunction(llvm::StringRef name) { +SWIFT_RUNTIME_STDLIB_SPI +const AccessibleFunctionRecord * +swift::runtime::swift_findAccessibleFunction(const char *targetNameStart, + size_t targetNameLength) { auto &S = Functions.get(); + llvm::StringRef name{targetNameStart, targetNameLength}; + // Look for an existing entry. { auto snapshot = S.Cache.snapshot(); From 5af5501437e53eefeeeb8fd99191a8224d2a12ab Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 7 Dec 2021 14:38:43 -0800 Subject: [PATCH 26/38] [Distributed] Runtime: Prototype `executeDistributedTarget` function --- stdlib/public/Concurrency/Actor.cpp | 25 +++++++++++++++++++ .../public/Distributed/DistributedActor.swift | 10 ++++++++ 2 files changed, 35 insertions(+) diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index fe43f825f9ba0..7ac4b1f2556b8 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -27,6 +27,7 @@ #include "../CompatibilityOverride/CompatibilityOverride.h" #include "swift/Runtime/Atomic.h" +#include "swift/Runtime/AccessibleFunction.h" #include "swift/Runtime/Casting.h" #include "swift/Runtime/Once.h" #include "swift/Runtime/Mutex.h" @@ -2004,3 +2005,27 @@ bool DefaultActorImpl::isDistributedRemote() { auto state = CurrentState.load(std::memory_order_relaxed); return state.Flags.isDistributedRemote(); } + +static const AccessibleFunctionRecord * +findDistributedAccessor(const char *targetNameStart, size_t targetNameLength) { + if (auto *func = runtime::swift_findAccessibleFunction(targetNameStart, + targetNameLength)) { + assert(func->Flags.isDistributed()); + return func; + } + return nullptr; +} + +SWIFT_CC(swiftasync) +void swift_distributed_execute_target( + OpaqueValue *resultPointer, + SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, + DefaultActor *actor, + const char *targetNameStart, size_t targetNameLength, + void *argumentBuffer, + void *resultBuffer, + ThrowingTaskFutureWaitContinuationFunction *resumeFn, + AsyncContext *callContext) { + auto *accessor = findDistributedAccessor(targetNameStart, targetNameLength); + (void)accessor; +} diff --git a/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index c0e5a88ca7049..b1bafca4dd60e 100644 --- a/stdlib/public/Distributed/DistributedActor.swift +++ b/stdlib/public/Distributed/DistributedActor.swift @@ -184,3 +184,13 @@ func __isLocalActor(_ actor: AnyObject) -> Bool { @_silgen_name("swift_distributedActor_remote_initialize") func _distributedActorRemoteInitialize(_ actorType: Builtin.RawPointer) -> Any + +// ==== Remote target accesss ------------------------------------------------- + +@_silgen_name("swift_distributed_execute_target") +func _executeDistributedTarget( + on: AnyObject, + _ targetName: UnsafePointer, + _ targetNameLength: UInt, + argumentBuffer: Builtin.RawPointer, + resultBuffer: Builtin.RawPointer) async throws From 7ac42e11b661804090781b46063a74af032f3964 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 7 Dec 2021 18:01:58 -0800 Subject: [PATCH 27/38] [Distributed] IRGen: Store async function pointer to distributed accessor Direct pointer to the accessor cannot be called at runtime, so here is how everything is stored: - For `distributed` and `async` functions -> async function pointer; - For regular functions -> function pointer. --- include/swift/ABI/Metadata.h | 7 +++-- lib/IRGen/GenDecl.cpp | 22 ++++++++------- lib/IRGen/IRGenModule.h | 9 +++---- lib/IRGen/IRGenSIL.cpp | 3 +-- test/IRGen/distributed_actor_accessors.swift | 28 ++++++++++---------- 5 files changed, 34 insertions(+), 35 deletions(-) diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 4cf322ebfa2eb..02affd003b9d4 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -5050,10 +5050,9 @@ struct TargetAccessibleFunctionRecord final { RelativeDirectPointer FunctionType; /// The fully-abstracted function to call. - RelativeDirectPointer - Function; + /// + /// Could be a sync or async function pointer depending on flags. + RelativeDirectPointer Function; /// Flags providing more information about the function. AccessibleFunctionFlags Flags; diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index b5a3f1119253e..6e7054527af24 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -3894,9 +3894,8 @@ void IRGenModule::addProtocolConformance(ConformanceDescription &&record) { ProtocolConformances.push_back(std::move(record)); } -void IRGenModule::addAccessibleFunction(SILFunction *func, - llvm::Function *thunk) { - AccessibleFunctions.push_back({func, thunk}); +void IRGenModule::addAccessibleFunction(SILFunction *func) { + AccessibleFunctions.push_back(func); } /// Emit the protocol conformance list and return it (if asContiguousArray is @@ -4123,10 +4122,7 @@ void IRGenModule::emitAccessibleFunctions() { break; } - for (const auto &entry : AccessibleFunctions) { - SILFunction *func = entry.first; - llvm::Function *thunk = entry.second; - + for (auto *func : AccessibleFunctions) { auto mangledRecordName = LinkEntity::forAccessibleFunctionRecord(func).mangleAsString(); @@ -4151,8 +4147,16 @@ void IRGenModule::emitAccessibleFunctions() { .first; llvm::Constant *relativeType = emitDirectRelativeReference(type, var, {1}); - llvm::Function *funcAddr = - thunk ? thunk : getAddrOfSILFunction(func, NotForDefinition); + llvm::Constant *funcAddr = nullptr; + if (func->isDistributed()) { + funcAddr = getAddrOfAsyncFunctionPointer( + LinkEntity::forDistributedMethodAccessor(func)); + } else if (func->isAsync()) { + funcAddr = getAddrOfAsyncFunctionPointer(func); + } else { + funcAddr = getAddrOfSILFunction(func, NotForDefinition); + } + llvm::Constant *relativeFuncAddr = emitDirectRelativeReference(funcAddr, var, {2}); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index d6b2325b3e9f1..853827163eefb 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -1041,8 +1041,7 @@ class IRGenModule { void addObjCClass(llvm::Constant *addr, bool nonlazy); void addObjCClassStub(llvm::Constant *addr); void addProtocolConformance(ConformanceDescription &&conformance); - void addAccessibleFunction(SILFunction *func, - llvm::Function *thunk = nullptr); + void addAccessibleFunction(SILFunction *func); llvm::Constant *emitSwiftProtocols(bool asContiguousArray); llvm::Constant *emitProtocolConformances(bool asContiguousArray); @@ -1178,10 +1177,8 @@ class IRGenModule { /// categories. SmallVector ObjCCategoryDecls; /// List of all of the functions, which can be lookup by name - /// up at runtime. Second element is an optional "accessor" thunk - /// to call the given function through. - SmallVector, 4> - AccessibleFunctions; + /// up at runtime. + SmallVector AccessibleFunctions; /// Map of Objective-C protocols and protocol references, bitcast to i8*. /// The interesting global variables relating to an ObjC protocol. diff --git a/lib/IRGen/IRGenSIL.cpp b/lib/IRGen/IRGenSIL.cpp index a9e75fe03e3ee..d2076c41bfbb1 100644 --- a/lib/IRGen/IRGenSIL.cpp +++ b/lib/IRGen/IRGenSIL.cpp @@ -2203,8 +2203,7 @@ void IRGenSILFunction::emitSILFunction() { // by name at runtime through it. if (CurSILFn->isDistributed() && CurSILFn->isThunk()) { IGM.emitDistributedMethodAccessor(CurSILFn); - IGM.addAccessibleFunction(CurSILFn, IGM.getAddrOfDistributedMethodAccessor( - CurSILFn, NotForDefinition)); + IGM.addAccessibleFunction(CurSILFn); } // Configure the dominance resolver. diff --git a/test/IRGen/distributed_actor_accessors.swift b/test/IRGen/distributed_actor_accessors.swift index eda5ac0e50b30..2513c80bc356f 100644 --- a/test/IRGen/distributed_actor_accessors.swift +++ b/test/IRGen/distributed_actor_accessors.swift @@ -84,44 +84,44 @@ public distributed actor MyOtherActor { /// -> `MyActor.simple1` // CHECK: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" = private constant // CHECK-SAME: @"symbolic Si___________pIetMHygzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETF" -// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETFTu" to i64) +// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" /// -> `MyActor.simple2` // CHECK: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" = private constant // CHECK-SAME: @"symbolic Si_____SS______pIetMHygozo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETF" -// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETFTu" to i64) +// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" /// -> `MyActor.simple3` // CHECK: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" = private constant // CHECK-SAME: @"symbolic SS_____Si______pIetMHggdzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETF" -// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETFTu" to i64) +// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" /// -> `MyActor.single_case_enum` // CHECK: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" = private constant // CHECK-SAME: @"symbolic __________AA______pIetMHygdzo_ 27distributed_actor_accessors7SimpleEO AA7MyActorC s5ErrorP" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETF" -// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETFTu" to i64) +// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" /// -> `MyActor.with_indirect_enums` // CHECK: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" = private constant // CHECK-SAME: @"symbolic _____Si_____AA______pIetMHgygozo_ 27distributed_actor_accessors9IndirectEO AA7MyActorC s5ErrorP" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETF" -// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETFTu" to i64) +// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" /// -> `MyActor.complex` // CHECK: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" = private constant // CHECK-SAME: @"symbolic SaySiG_____SSSg__________AD______pIetMHgggngrzo_ 27distributed_actor_accessors3ObjC AA11LargeStructV AA7MyActorC s5ErrorP" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETF" -// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETFTu" to i64) +// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" /// -> `MyOtherActor.empty` // CHECK: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" = private constant // CHECK-SAME: @"symbolic ___________pIetMHgzo_ 27distributed_actor_accessors12MyOtherActorC s5ErrorP" -// CHECK-SAME: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETF" -// CHECK-SAME: , section "__TEXT, __swift5_acfunc, regular" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i64) +// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" // CHECK: @llvm.used = appending global [{{.*}} x i8*] [ // CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" From ed97120d7c2b30761bbfc4aee6cbf97d936bd989 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Wed, 8 Dec 2021 17:09:27 -0800 Subject: [PATCH 28/38] [Distributed] Runtime: Implement `_executeDistributedTarget` The implementation is as follows: - Looks up distributed accessor by the given target name - Extracts information required to setup async context from async function pointer stored in accessor record - Allocates context and calls accessor --- stdlib/public/Concurrency/Actor.cpp | 67 ++++++++++++++++--- .../public/Distributed/DistributedActor.swift | 1 + 2 files changed, 58 insertions(+), 10 deletions(-) diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 7ac4b1f2556b8..944f1a84460a3 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -2016,16 +2016,63 @@ findDistributedAccessor(const char *targetNameStart, size_t targetNameLength) { return nullptr; } +/// func _executeDistributedTarget( +/// on: AnyObject, +/// _ targetName: UnsafePointer, +/// _ targetNameLength: UInt, +/// argumentBuffer: Builtin.RawPointer, +/// resultBuffer: Builtin.RawPointer) async throws +using TargetExecutorSignature = + AsyncSignature; + +SWIFT_CC(swiftasync) +SWIFT_RUNTIME_STDLIB_SPI +TargetExecutorSignature::FunctionType swift_distributed_execute_target; + +/// Accessor takes a context, an argument buffer as a raw pointer, +/// and a reference to an actor. +using DistributedAccessorSignature = AsyncSignature; + +SWIFT_CC(swiftasync) +static DistributedAccessorSignature::ContinuationType + swift_distributed_execute_target_resume; + +SWIFT_CC(swiftasync) +static void ::swift_distributed_execute_target_resume( + SWIFT_ASYNC_CONTEXT AsyncContext *context, SWIFT_CONTEXT void *error) { + auto parentCtx = context->Parent; + auto resumeInParent = + reinterpret_cast( + parentCtx->ResumeParent); + swift_task_dealloc(context); + return resumeInParent(parentCtx, error); +} + SWIFT_CC(swiftasync) -void swift_distributed_execute_target( - OpaqueValue *resultPointer, - SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, - DefaultActor *actor, - const char *targetNameStart, size_t targetNameLength, - void *argumentBuffer, - void *resultBuffer, - ThrowingTaskFutureWaitContinuationFunction *resumeFn, - AsyncContext *callContext) { +void ::swift_distributed_execute_target( + SWIFT_ASYNC_CONTEXT AsyncContext *callerContext, DefaultActor *actor, + const char *targetNameStart, size_t targetNameLength, void *argumentBuffer, + void *resultBuffer) { auto *accessor = findDistributedAccessor(targetNameStart, targetNameLength); - (void)accessor; + + if (!accessor) + return; + + auto *asyncFnPtr = reinterpret_cast< + const AsyncFunctionPointer *>(accessor); + + DistributedAccessorSignature::FunctionType *accessorEntry = + asyncFnPtr->Function.get(); + + AsyncContext *calleeContext = reinterpret_cast( + swift_task_alloc(asyncFnPtr->ExpectedContextSize)); + + calleeContext->Parent = callerContext; + calleeContext->ResumeParent = reinterpret_cast( + swift_distributed_execute_target_resume); + + // TODO: Add resultBuffer as an argument to store an indirect result into. + accessorEntry(calleeContext, argumentBuffer, actor); } diff --git a/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index b1bafca4dd60e..e368168615719 100644 --- a/stdlib/public/Distributed/DistributedActor.swift +++ b/stdlib/public/Distributed/DistributedActor.swift @@ -187,6 +187,7 @@ func _distributedActorRemoteInitialize(_ actorType: Builtin.RawPointer) -> Any // ==== Remote target accesss ------------------------------------------------- +@available(SwiftStdlib 5.6, *) @_silgen_name("swift_distributed_execute_target") func _executeDistributedTarget( on: AnyObject, From 111ceb189a153440f4f9c8aee7ddaaf1075276b0 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 10 Dec 2021 15:32:47 -0800 Subject: [PATCH 29/38] [Distributed] IRGen: Adjust distributed method accessor to store result into a provided buffer Instead of trying to return result from distributed thunk directly, modify accessor to store result into the caller-provided buffer. Doing so helps us avoid boxing the result into `Any`. --- lib/IRGen/GenDistributed.cpp | 52 ++++++++++++-------- stdlib/public/Concurrency/Actor.cpp | 15 +++--- test/IRGen/distributed_actor_accessors.swift | 45 ++++++++++++----- 3 files changed, 74 insertions(+), 38 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index f259b54f88dd3..665bf66a64cea 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -98,7 +98,7 @@ static CanSILFunctionType getAccessorType(IRGenModule &IGM, SILFunction *DistMethod) { auto &Context = IGM.Context; - auto getParamForArguments = [&]() { + auto getRawPointerParmeter = [&]() { auto ptrType = Context.getUnsafeRawPointerType(); return SILParameterInfo(ptrType->getCanonicalType(), ParameterConvention::Direct_Guaranteed); @@ -121,9 +121,11 @@ static CanSILFunctionType getAccessorType(IRGenModule &IGM, // its result(s) out. return SILFunctionType::get( /*genericSignature=*/nullptr, extInfo, SILCoroutineKind::None, - ParameterConvention::Direct_Guaranteed, {getParamForArguments()}, + ParameterConvention::Direct_Guaranteed, + {/*argumentBuffer=*/getRawPointerParmeter(), + /*resultBuffer=*/getRawPointerParmeter()}, /*Yields=*/{}, - /*Results=*/methodTy->getResults(), + /*Results=*/{}, /*ErrorResult=*/methodTy->getErrorResult(), /*patternSubs=*/SubstitutionMap(), /*invocationSubs=*/SubstitutionMap(), Context); @@ -257,23 +259,16 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, void DistributedAccessor::emit() { auto methodTy = Method->getLoweredFunctionType(); - SILFunctionConventions conv(methodTy, IGF.getSILModule()); + SILFunctionConventions targetConv(methodTy, IGF.getSILModule()); + SILFunctionConventions accessorConv(AccessorType, IGF.getSILModule()); TypeExpansionContext expansionContext = IGM.getMaximalTypeExpansionContext(); auto params = IGF.collectParameters(); - auto directResultTy = conv.getSILResultType(expansionContext); + auto directResultTy = targetConv.getSILResultType(expansionContext); const auto &directResultTI = IGM.getTypeInfo(directResultTy); - auto &resultSchema = directResultTI.nativeReturnValueSchema(IGM); - llvm::Value *indirectResultSlot = nullptr; - - if (resultSchema.requiresIndirect()) - indirectResultSlot = params.claimNext(); Explosion arguments; - // Claim indirect results first, they are going to be passed - // through to the distributed method. - params.transferInto(arguments, conv.getNumIndirectSILResults()); unsigned numAsyncContextParams = (unsigned)AsyncFunctionArgumentIndex::Context + 1; @@ -281,6 +276,8 @@ void DistributedAccessor::emit() { // UnsafeRawPointer that holds all of the argument values. auto *argBuffer = params.claimNext(); + // UnsafeRawPointer that is used to store the result. + auto *resultBuffer = params.claimNext(); // Reference to a `self` of the actor to be called. auto *actorSelf = params.claimNext(); @@ -298,6 +295,17 @@ void DistributedAccessor::emit() { emitAsyncFunctionPointer(IGM, IGF.CurFn, entity, AsyncLayout.getSize()); } + auto *typedResultBuffer = IGF.Builder.CreateBitCast( + resultBuffer, IGM.getStoragePointerType(directResultTy)); + + if (targetConv.getNumIndirectSILResults()) { + // Since tuples are not allowed as valid result types (because they cannot + // conform to protocols), there could be only a single indirect result type + // associated with distributed method. + assert(targetConv.getNumIndirectSILResults() == 1); + arguments.add(typedResultBuffer); + } + // Step one is to load all of the data from argument buffer, // so it could be forwarded to the distributed method. computeArguments(argBuffer, arguments); @@ -316,13 +324,15 @@ void DistributedAccessor::emit() { emission->setArgs(arguments, /*isOutlined=*/false, /*witnessMetadata=*/nullptr); - if (resultSchema.requiresIndirect()) { - Address resultAddr(indirectResultSlot, + // Load result of the thunk into the location provided by the caller. + // This would only generate code for direct results, if thunk has an + // indirect result (e.g. large struct) it result buffer would be passed + // as an argument. + { + Address resultAddr(typedResultBuffer, directResultTI.getBestKnownAlignment()); emission->emitToMemory(resultAddr, cast(directResultTI), /*isOutlined=*/false); - } else { - emission->emitToExplosion(result, /*isOutlined=*/false); } // Both accessor and distributed method are always `async throws` @@ -330,7 +340,7 @@ void DistributedAccessor::emit() { { assert(methodTy->hasErrorResult()); - SILType errorType = conv.getSILErrorType(expansionContext); + SILType errorType = accessorConv.getSILErrorType(expansionContext); Address calleeErrorSlot = emission->getCalleeErrorSlot(errorType, /*isCalleeAsync=*/true); error.add(IGF.Builder.CreateLoad(calleeErrorSlot)); @@ -338,8 +348,10 @@ void DistributedAccessor::emit() { emission->end(); - emitAsyncReturn(IGF, AsyncLayout, directResultTy, AccessorType, result, - error); + Explosion voidResult; + emitAsyncReturn(IGF, AsyncLayout, + accessorConv.getSILResultType(expansionContext), + AccessorType, voidResult, error); } } diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 944f1a84460a3..adf599995e5d6 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -2030,10 +2030,14 @@ SWIFT_CC(swiftasync) SWIFT_RUNTIME_STDLIB_SPI TargetExecutorSignature::FunctionType swift_distributed_execute_target; -/// Accessor takes a context, an argument buffer as a raw pointer, -/// and a reference to an actor. -using DistributedAccessorSignature = AsyncSignature; +/// Accessor takes: +/// - an async context +/// - an argument buffer as a raw pointer +/// - a result buffer as a raw pointer +/// - a reference to an actor to execute method on. +using DistributedAccessorSignature = + AsyncSignature; SWIFT_CC(swiftasync) static DistributedAccessorSignature::ContinuationType @@ -2073,6 +2077,5 @@ void ::swift_distributed_execute_target( calleeContext->ResumeParent = reinterpret_cast( swift_distributed_execute_target_resume); - // TODO: Add resultBuffer as an argument to store an indirect result into. - accessorEntry(calleeContext, argumentBuffer, actor); + accessorEntry(calleeContext, argumentBuffer, resultBuffer, actor); } diff --git a/test/IRGen/distributed_actor_accessors.swift b/test/IRGen/distributed_actor_accessors.swift index 2513c80bc356f..243484f90e6a4 100644 --- a/test/IRGen/distributed_actor_accessors.swift +++ b/test/IRGen/distributed_actor_accessors.swift @@ -139,7 +139,7 @@ public distributed actor MyOtherActor { // CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTE" -// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETF"(%swift.context* swiftasync %0, i8* %1, %swift.refcounted* swiftself %2) +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETF"(%swift.context* swiftasync %0, i8* %1, i8* %2, %swift.refcounted* swiftself %3) /// Read the current offset and cast an element to `Int` @@ -192,14 +192,22 @@ public distributed actor MyOtherActor { // CHECK: [[STR_STRUCT:%.*]] = insertvalue { i64, %swift.bridge* } {{.*}}, %swift.bridge* {{.*}}, 1 // CHECK: [[STR_SIZE:%.*]] = extractvalue { i64, %swift.bridge* } [[STR_STRUCT]], 0 // CHECK-NEXT: [[STR_VAL:%.*]] = extractvalue { i64, %swift.bridge* } [[STR_STRUCT]], 1 -// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, i64 [[STR_SIZE]], %swift.bridge* [[STR_VAL]], %swift.error* {{.*}}) + +/// Initialize the result buffer with values produced by the thunk + +// CHECK: store i64 [[STR_SIZE]], i64* %._guts._object._countAndFlagsBits._value, align 8 +// CHECK: store %swift.bridge* [[STR_VAL]], %swift.bridge** %._guts._object._object, align 8 + +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) /// ---> Thunk and distributed method accessor for `simple3` // CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTE" /// !!! in `simple3` interesting bits are: argument value extraction (because string is exploded into N arguments) and call to distributed thunk -// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETF" +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETF"(%swift.context* swiftasync {{.*}}, i8* [[ARG_BUFF:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) + +// CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* [[RESULT_BUFF]] to %TSi* // CHECK: %argval = load %TSS, %TSS* {{.*}}, align 8 // CHECK: [[NATIVE_STR_PTR:%.*]] = bitcast %TSS* %argval.coercion.coerced to { i64, %swift.bridge* }* @@ -220,13 +228,15 @@ public distributed actor MyOtherActor { // CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 0 // CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) // CHECK: [[INT_RES:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 1 -// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, i64 [[INT_RES]], %swift.error* {{.*}}) +// CHECK: %._value = getelementptr inbounds %TSi, %TSi* [[TYPED_RESULT_BUFF]], i32 0, i32 0 +// CHECK: store i64 [[INT_RES]], i64* %._value, align 8 +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) /// --> Thunk and distributed method accessor for `single_case_enum` // CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTE" -// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETF"(%swift.context* swiftasync %0, i8* [[BUFFER:%.*]], %swift.refcounted* swiftself %2) +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETF"(%swift.context* swiftasync %0, i8* [[BUFFER:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) /// First, let's check that there were no loads from the argument buffer and no stores to "current offset". @@ -251,6 +261,7 @@ public distributed actor MyOtherActor { /// First, Load both arguments from the buffer. +// CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* %2 to %T27distributed_actor_accessors9IndirectEO* // CHECK: store i8* %1, i8** %offset, align 8 // CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 // CHECK-NEXT: [[ENUM_PTR:%.*]] = bitcast i8* %elt_offset to %T27distributed_actor_accessors9IndirectEO* @@ -261,7 +272,7 @@ public distributed actor MyOtherActor { // CHECK-NEXT: [[NATIVE_ENUM_VAL:%.*]] = load i64, i64* [[COERCED_ENUM_PTR]], align 8 // CHECK: [[ENUM_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT_LOC:%.*]] = add i64 [[ENUM_PTR_INT]], 8 -// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 %13 to i8* +// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 [[NEXT_ELT_LOC]] to i8* // CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 // CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset, align 8 // CHECK-NEXT: [[INT_PTR:%.*]] = bitcast i8* %elt_offset1 to %TSi* @@ -277,16 +288,22 @@ public distributed actor MyOtherActor { // CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 0 // CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) // CHECK: [[ENUM_RESULT:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 1 -// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, i64 [[ENUM_RESULT]], %swift.error* {{.*}}) +// CHECK: [[NATIVE_RESULT_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* [[TYPED_RESULT_BUFF]] to i64* +// CHECK-NEXT: store i64 [[ENUM_RESULT]], i64* [[NATIVE_RESULT_PTR]], align 8 + +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) /// ---> Thunk and distributed method for `complex` // CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTE" -// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETF"(%T27distributed_actor_accessors11LargeStructV* noalias nocapture [[INDIRECT_RES:%.*]], %swift.context* swiftasync %1, i8* %2, %swift.refcounted* swiftself %3) +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETF"(%swift.context* swiftasync {{.*}}, i8* [[ARG_BUFF:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) /// First, let's check that all of the different argument types here are loaded correctly. +/// Cast result buffer to the expected result type (in this case its indirect opaque pointer) +// CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* [[RESULT_BUFF]] to %swift.opaque* + /// -> [Int] // CHECK: %elt_offset = load i8*, i8** %offset, align 8 @@ -307,7 +324,7 @@ public distributed actor MyOtherActor { // CHECK-NEXT: [[NATIVE_OBJ_VAL:%.*]] = load %T27distributed_actor_accessors3ObjC*, %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]], align 8 // CHECK-NEXT: [[OBJ_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[OBJ_PTR_INT]], 8 -// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 %18 to i8* +// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* // CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 /// -> String? @@ -330,13 +347,16 @@ public distributed actor MyOtherActor { // CHECK-NEXT: %elt_offset5 = load i8*, i8** %offset, align 8 // CHECK-NEXT: [[STRUCT_PTR:%.*]] = bitcast i8* %elt_offset5 to %T27distributed_actor_accessors11LargeStructV* // CHECK-NEXT: [[STRUCT_VAL:%.*]] = load %T27distributed_actor_accessors11LargeStructV, %T27distributed_actor_accessors11LargeStructV* [[STRUCT_PTR]], align 8 + +// CHECK: [[INDIRECT_RESULT_BUFF:%.*]] = bitcast %swift.opaque* [[TYPED_RESULT_BUFF]] to %T27distributed_actor_accessors11LargeStructV* + // CHECK: store %T27distributed_actor_accessors11LargeStructV [[STRUCT_VAL]], %T27distributed_actor_accessors11LargeStructV* %argval6.coercion.coerced, align 8 // CHECK-NEXT: [[PTR_TO_STRUCT:%.*]] = bitcast %T27distributed_actor_accessors11LargeStructV* %argval6.coercion.coerced to %T27distributed_actor_accessors11LargeStructV** // CHECK-NEXT: [[NATIVE_STRUCT_VAL:%.*]] = load %T27distributed_actor_accessors11LargeStructV*, %T27distributed_actor_accessors11LargeStructV** [[PTR_TO_STRUCT]], align 8 /// Now let's make sure that distributed thunk call uses the arguments correctly -// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, %T27distributed_actor_accessors11LargeStructV* [[INDIRECT_RES]], %swift.context* {{.*}}, %swift.bridge* [[NATIVE_ARR_VAL]], %T27distributed_actor_accessors3ObjC* [[NATIVE_OBJ_VAL]], i64 [[NATIVE_OPT_VAL_0]], i64 [[NATIVE_OPT_VAL_1]], %T27distributed_actor_accessors11LargeStructV* [[NATIVE_STRUCT_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, %T27distributed_actor_accessors11LargeStructV* [[INDIRECT_RESULT_BUFF]], %swift.context* {{.*}}, %swift.bridge* [[NATIVE_ARR_VAL]], %T27distributed_actor_accessors3ObjC* [[NATIVE_OBJ_VAL]], i64 [[NATIVE_OPT_VAL_0]], i64 [[NATIVE_OPT_VAL_1]], %T27distributed_actor_accessors11LargeStructV* [[NATIVE_STRUCT_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) /// RESULT is returned indirectly so there is nothing to pass to `end` @@ -346,12 +366,13 @@ public distributed actor MyOtherActor { /// Let's check that there is no offset allocation here since parameter list is empty -// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETF" +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETF"(%swift.context* swiftasync {{.*}}, i8* [[ARG_BUFF:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) // CHECK-NEXT: entry: // CHECK-NEXT: {{.*}} = alloca %swift.context*, align 8 // CHECK-NEXT: %swifterror = alloca swifterror %swift.error*, align 8 // CHECK-NEXT: {{.*}} = call token @llvm.coro.id.async(i32 20, i32 16, i32 0, i8* bitcast (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i8*)) -// CHECK-NEXT: {{.*}} = call i8* @llvm.coro.begin(token %4, i8* null) +// CHECK-NEXT: {{.*}} = call i8* @llvm.coro.begin(token {{%.*}}, i8* null) // CHECK-NEXT: store %swift.context* {{.*}}, %swift.context** {{.*}}, align 8 // CHECK-NEXT: store %swift.error* null, %swift.error** %swifterror, align 8 +// CHECK-NEXT: {{.*}} = bitcast i8* [[RESULT_BUFF]] to %swift.opaque* // CHECK-NEXT: {{.*}} = load i32, i32* getelementptr inbounds (%swift.async_func_pointer, %swift.async_func_pointer* bitcast (void (%swift.context*, %T27distributed_actor_accessors12MyOtherActorC*)* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTE" to %swift.async_func_pointer*), i32 0, i32 0), align 8 From dd0d5a8b862c0e4e281624e6bd947c40328686ff Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 14 Dec 2021 14:09:24 -0800 Subject: [PATCH 30/38] [Distributed] Remove outdated declaration of `_executeDistributedTarget` from `DistributedActor.swift` The function should be (and is) declared in `DistributedActorSystem.swift` --- stdlib/public/Distributed/DistributedActor.swift | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index e368168615719..c0e5a88ca7049 100644 --- a/stdlib/public/Distributed/DistributedActor.swift +++ b/stdlib/public/Distributed/DistributedActor.swift @@ -184,14 +184,3 @@ func __isLocalActor(_ actor: AnyObject) -> Bool { @_silgen_name("swift_distributedActor_remote_initialize") func _distributedActorRemoteInitialize(_ actorType: Builtin.RawPointer) -> Any - -// ==== Remote target accesss ------------------------------------------------- - -@available(SwiftStdlib 5.6, *) -@_silgen_name("swift_distributed_execute_target") -func _executeDistributedTarget( - on: AnyObject, - _ targetName: UnsafePointer, - _ targetNameLength: UInt, - argumentBuffer: Builtin.RawPointer, - resultBuffer: Builtin.RawPointer) async throws From 151bae110e0050f7ee37e95e24521797b041266d Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 14 Dec 2021 17:30:09 -0800 Subject: [PATCH 31/38] [Distributed] NFC: Update accessor test-cases to use `FakeActorSystem` instead of `Transport` --- .../distributed_actor_accessors.swift | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) rename test/{IRGen => Distributed}/distributed_actor_accessors.swift (97%) diff --git a/test/IRGen/distributed_actor_accessors.swift b/test/Distributed/distributed_actor_accessors.swift similarity index 97% rename from test/IRGen/distributed_actor_accessors.swift rename to test/Distributed/distributed_actor_accessors.swift index 243484f90e6a4..c821797a07697 100644 --- a/test/IRGen/distributed_actor_accessors.swift +++ b/test/Distributed/distributed_actor_accessors.swift @@ -1,10 +1,17 @@ -// RUN: %target-swift-frontend -emit-irgen %s -swift-version 5 -enable-experimental-distributed | %IRGenFileCheck %s + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -emit-irgen -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s // UNSUPPORTED: back_deploy_concurrency // REQUIRES: concurrency // REQUIRES: distributed import _Distributed +import FakeDistributedActorSystems + +@available(SwiftStdlib 5.5, *) +typealias DefaultDistributedActorSystem = FakeActorSystem enum SimpleE : Codable { case a @@ -36,8 +43,6 @@ struct LargeStruct : Codable { @available(SwiftStdlib 5.6, *) public distributed actor MyActor { - public typealias Transport = AnyActorTransport - distributed func simple1(_: Int) { } @@ -72,8 +77,6 @@ public distributed actor MyActor { @available(SwiftStdlib 5.6, *) public distributed actor MyOtherActor { - public typealias Transport = AnyActorTransport - distributed func empty() { } } From 9b21742e58f71828dcf409b350052469a24994fa Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Tue, 14 Dec 2021 20:18:53 -0800 Subject: [PATCH 32/38] [Distributed] Adjust accessor tests to match Windows/Linux section name correctly --- ...tributed_actor_accessor_section_coff.swift | 138 +++++++++++++++++ ...stributed_actor_accessor_section_elf.swift | 138 +++++++++++++++++ ...ributed_actor_accessor_section_macho.swift | 139 ++++++++++++++++++ ...> distributed_actor_accessor_thunks.swift} | 64 +------- 4 files changed, 419 insertions(+), 60 deletions(-) create mode 100644 test/Distributed/distributed_actor_accessor_section_coff.swift create mode 100644 test/Distributed/distributed_actor_accessor_section_elf.swift create mode 100644 test/Distributed/distributed_actor_accessor_section_macho.swift rename test/Distributed/{distributed_actor_accessors.swift => distributed_actor_accessor_thunks.swift} (81%) diff --git a/test/Distributed/distributed_actor_accessor_section_coff.swift b/test/Distributed/distributed_actor_accessor_section_coff.swift new file mode 100644 index 0000000000000..8bd93bea18b80 --- /dev/null +++ b/test/Distributed/distributed_actor_accessor_section_coff.swift @@ -0,0 +1,138 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -emit-irgen -module-name distributed_actor_accessors -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s + +// UNSUPPORTED: back_deploy_concurrency +// REQUIRES: concurrency +// REQUIRES: distributed + +// REQUIRES: OS=windows-msvc + +import _Distributed +import FakeDistributedActorSystems + +@available(SwiftStdlib 5.5, *) +typealias DefaultDistributedActorSystem = FakeActorSystem + +enum SimpleE : Codable { +case a +} + +enum E : Codable { +case a, b, c +} + +enum IndirectE : Codable { + case empty + indirect case test(_: Int) +} + +final class Obj : Codable, Sendable { + let x: Int + + init(x: Int) { + self.x = x + } +} + +struct LargeStruct : Codable { + var a: Int + var b: Int + var c: String + var d: Double +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyActor { + distributed func simple1(_: Int) { + } + + // `String` would be a direct result as a struct type + distributed func simple2(_: Int) -> String { + return "" + } + + // `String` is an object that gets exploded into two parameters + distributed func simple3(_: String) -> Int { + return 42 + } + + // Enum with a single case are special because they have an empty + // native schema so they are dropped from parameters/result. + distributed func single_case_enum(_ e: SimpleE) -> SimpleE { + return e + } + + distributed func with_indirect_enums(_: IndirectE, _: Int) -> IndirectE { + return .empty + } + + // Combination of multiple arguments, reference type and indirect result + // + // Note: Tuple types cannot be used here is either position because they + // cannot conform to protocols. + distributed func complex(_: [Int], _: Obj, _: String?, _: LargeStruct) -> LargeStruct { + fatalError() + } +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyOtherActor { + distributed func empty() { + } +} + + +/// ---> Let's check that distributed accessors and thunks are emitted as accessible functions + +/// -> `MyActor.simple1` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" = private constant +// CHECK-SAME: @"symbolic Si___________pIetMHygzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETFTu" to i64) +// CHECK-SAME: , section ".sw5acfn$B", {{.*}} + +/// -> `MyActor.simple2` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" = private constant +// CHECK-SAME: @"symbolic Si_____SS______pIetMHygozo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETFTu" to i64 +// CHECK-SAME: , section ".sw5acfn$B", {{.*}} + +/// -> `MyActor.simple3` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" = private constant +// CHECK-SAME: @"symbolic SS_____Si______pIetMHggdzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETFTu" to i64) +// CHECK-SAME: , section ".sw5acfn$B", {{.*}} + +/// -> `MyActor.single_case_enum` +// CHECK: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" = private constant +// CHECK-SAME: @"symbolic __________AA______pIetMHygdzo_ 27distributed_actor_accessors7SimpleEO AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETFTu" to i64) +// CHECK-SAME: , section ".sw5acfn$B", {{.*}} + +/// -> `MyActor.with_indirect_enums` +// CHECK: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" = private constant +// CHECK-SAME: @"symbolic _____Si_____AA______pIetMHgygozo_ 27distributed_actor_accessors9IndirectEO AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETFTu" to i64 +// CHECK-SAME: , section ".sw5acfn$B", {{.*}} + +/// -> `MyActor.complex` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" = private constant +// CHECK-SAME: @"symbolic SaySiG_____SSSg__________AD______pIetMHgggngrzo_ 27distributed_actor_accessors3ObjC AA11LargeStructV AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETFTu" to i64) +// CHECK-SAME: , section ".sw5acfn$B", {{.*}} + +/// -> `MyOtherActor.empty` +// CHECK: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" = private constant +// CHECK-SAME: @"symbolic ___________pIetMHgzo_ 27distributed_actor_accessors12MyOtherActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i64) +// CHECK-SAME: , section ".sw5acfn$B", {{.*}} + +// CHECK: @llvm.used = appending global [{{.*}} x i8*] [ +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" +// CHECK-SAME: ], section "llvm.metadata" diff --git a/test/Distributed/distributed_actor_accessor_section_elf.swift b/test/Distributed/distributed_actor_accessor_section_elf.swift new file mode 100644 index 0000000000000..f2253209671e6 --- /dev/null +++ b/test/Distributed/distributed_actor_accessor_section_elf.swift @@ -0,0 +1,138 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -emit-irgen -module-name distributed_actor_accessors -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s + +// UNSUPPORTED: back_deploy_concurrency +// REQUIRES: concurrency +// REQUIRES: distributed + +// REQUIRES: OS=linux-gnu + +import _Distributed +import FakeDistributedActorSystems + +@available(SwiftStdlib 5.5, *) +typealias DefaultDistributedActorSystem = FakeActorSystem + +enum SimpleE : Codable { +case a +} + +enum E : Codable { +case a, b, c +} + +enum IndirectE : Codable { + case empty + indirect case test(_: Int) +} + +final class Obj : Codable, Sendable { + let x: Int + + init(x: Int) { + self.x = x + } +} + +struct LargeStruct : Codable { + var a: Int + var b: Int + var c: String + var d: Double +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyActor { + distributed func simple1(_: Int) { + } + + // `String` would be a direct result as a struct type + distributed func simple2(_: Int) -> String { + return "" + } + + // `String` is an object that gets exploded into two parameters + distributed func simple3(_: String) -> Int { + return 42 + } + + // Enum with a single case are special because they have an empty + // native schema so they are dropped from parameters/result. + distributed func single_case_enum(_ e: SimpleE) -> SimpleE { + return e + } + + distributed func with_indirect_enums(_: IndirectE, _: Int) -> IndirectE { + return .empty + } + + // Combination of multiple arguments, reference type and indirect result + // + // Note: Tuple types cannot be used here is either position because they + // cannot conform to protocols. + distributed func complex(_: [Int], _: Obj, _: String?, _: LargeStruct) -> LargeStruct { + fatalError() + } +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyOtherActor { + distributed func empty() { + } +} + + +/// ---> Let's check that distributed accessors and thunks are emitted as accessible functions + +/// -> `MyActor.simple1` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" = private constant +// CHECK-SAME: @"symbolic Si___________pIetMHygzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETFTu" to i64) +// CHECK-SAME: , section "swift5_accessible_functions", {{.*}} + +/// -> `MyActor.simple2` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" = private constant +// CHECK-SAME: @"symbolic Si_____SS______pIetMHygozo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETFTu" to i64) +// CHECK-SAME: , section "swift5_accessible_functions", {{.*}} + +/// -> `MyActor.simple3` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" = private constant +// CHECK-SAME: @"symbolic SS_____Si______pIetMHggdzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETFTu" to i64) +// CHECK-SAME: , section "swift5_accessible_functions", {{.*}} + +/// -> `MyActor.single_case_enum` +// CHECK: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" = private constant +// CHECK-SAME: @"symbolic __________AA______pIetMHygdzo_ 27distributed_actor_accessors7SimpleEO AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETFTu" to i64) +// CHECK-SAME: , section "swift5_accessible_functions", {{.*}} + +/// -> `MyActor.with_indirect_enums` +// CHECK: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" = private constant +// CHECK-SAME: @"symbolic _____Si_____AA______pIetMHgygozo_ 27distributed_actor_accessors9IndirectEO AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETFTu" to i64) +// CHECK-SAME: , section "swift5_accessible_functions", {{.*}} + +/// -> `MyActor.complex` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" = private constant +// CHECK-SAME: @"symbolic SaySiG_____SSSg__________AD______pIetMHgggngrzo_ 27distributed_actor_accessors3ObjC AA11LargeStructV AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETFTu" to i64) +// CHECK-SAME: , section "swift5_accessible_functions", {{.*}} + +/// -> `MyOtherActor.empty` +// CHECK: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" = private constant +// CHECK-SAME: @"symbolic ___________pIetMHgzo_ 27distributed_actor_accessors12MyOtherActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i64) +// CHECK-SAME: , section "swift5_accessible_functions", {{.*}} + +// CHECK: @llvm.compiler.used = appending global [{{.*}} x i8*] [ +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" +// CHECK-SAME: ], section "llvm.metadata" diff --git a/test/Distributed/distributed_actor_accessor_section_macho.swift b/test/Distributed/distributed_actor_accessor_section_macho.swift new file mode 100644 index 0000000000000..7948f3e5f7dac --- /dev/null +++ b/test/Distributed/distributed_actor_accessor_section_macho.swift @@ -0,0 +1,139 @@ + +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -emit-irgen -module-name distributed_actor_accessors -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s + +// UNSUPPORTED: back_deploy_concurrency +// REQUIRES: concurrency +// REQUIRES: distributed + +// REQUIRES: VENDOR=apple + +import _Distributed +import FakeDistributedActorSystems + +@available(SwiftStdlib 5.5, *) +typealias DefaultDistributedActorSystem = FakeActorSystem + +enum SimpleE : Codable { +case a +} + +enum E : Codable { +case a, b, c +} + +enum IndirectE : Codable { + case empty + indirect case test(_: Int) +} + +final class Obj : Codable, Sendable { + let x: Int + + init(x: Int) { + self.x = x + } +} + +struct LargeStruct : Codable { + var a: Int + var b: Int + var c: String + var d: Double +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyActor { + distributed func simple1(_: Int) { + } + + // `String` would be a direct result as a struct type + distributed func simple2(_: Int) -> String { + return "" + } + + // `String` is an object that gets exploded into two parameters + distributed func simple3(_: String) -> Int { + return 42 + } + + // Enum with a single case are special because they have an empty + // native schema so they are dropped from parameters/result. + distributed func single_case_enum(_ e: SimpleE) -> SimpleE { + return e + } + + distributed func with_indirect_enums(_: IndirectE, _: Int) -> IndirectE { + return .empty + } + + // Combination of multiple arguments, reference type and indirect result + // + // Note: Tuple types cannot be used here is either position because they + // cannot conform to protocols. + distributed func complex(_: [Int], _: Obj, _: String?, _: LargeStruct) -> LargeStruct { + fatalError() + } +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyOtherActor { + distributed func empty() { + } +} + + +/// ---> Let's check that distributed accessors and thunks are emitted as accessible functions + +/// -> `MyActor.simple1` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" = private constant +// CHECK-SAME: @"symbolic Si___________pIetMHygzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETFTu" to i64) +// CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} + +/// -> `MyActor.simple2` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" = private constant +// CHECK-SAME: @"symbolic Si_____SS______pIetMHygozo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETFTu" to i64) +// CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} + +/// -> `MyActor.simple3` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" = private constant +// CHECK-SAME: @"symbolic SS_____Si______pIetMHggdzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETFTu" to i64) +// CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} + +/// -> `MyActor.single_case_enum` +// CHECK: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" = private constant +// CHECK-SAME: @"symbolic __________AA______pIetMHygdzo_ 27distributed_actor_accessors7SimpleEO AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETFTu" to i64) +// CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} + +/// -> `MyActor.with_indirect_enums` +// CHECK: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" = private constant +// CHECK-SAME: @"symbolic _____Si_____AA______pIetMHgygozo_ 27distributed_actor_accessors9IndirectEO AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETFTu" to i64) +// CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} + +/// -> `MyActor.complex` +// CHECK: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" = private constant +// CHECK-SAME: @"symbolic SaySiG_____SSSg__________AD______pIetMHgggngrzo_ 27distributed_actor_accessors3ObjC AA11LargeStructV AA7MyActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETFTu" to i64) +// CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} + +/// -> `MyOtherActor.empty` +// CHECK: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" = private constant +// CHECK-SAME: @"symbolic ___________pIetMHgzo_ 27distributed_actor_accessors12MyOtherActorC s5ErrorP" +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i64) +// CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} + +// CHECK: @llvm.used = appending global [{{.*}} x i8*] [ +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" +// CHECK-SAME: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" +// CHECK-SAME: ], section "llvm.metadata" diff --git a/test/Distributed/distributed_actor_accessors.swift b/test/Distributed/distributed_actor_accessor_thunks.swift similarity index 81% rename from test/Distributed/distributed_actor_accessors.swift rename to test/Distributed/distributed_actor_accessor_thunks.swift index c821797a07697..45fbef7f9066e 100644 --- a/test/Distributed/distributed_actor_accessors.swift +++ b/test/Distributed/distributed_actor_accessor_thunks.swift @@ -1,7 +1,6 @@ - // RUN: %empty-directory(%t) // RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift -// RUN: %target-swift-frontend -emit-irgen -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s +// RUN: %target-swift-frontend -module-name distributed_actor_accessors -emit-irgen -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s // UNSUPPORTED: back_deploy_concurrency // REQUIRES: concurrency @@ -81,61 +80,6 @@ public distributed actor MyOtherActor { } } - -/// ---> Let's check that distributed accessors and thunks are emitted as accessible functions - -/// -> `MyActor.simple1` -// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" = private constant -// CHECK-SAME: @"symbolic Si___________pIetMHygzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETFTu" to i64) -// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" - -/// -> `MyActor.simple2` -// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" = private constant -// CHECK-SAME: @"symbolic Si_____SS______pIetMHygozo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETFTu" to i64) -// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" - -/// -> `MyActor.simple3` -// CHECK: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" = private constant -// CHECK-SAME: @"symbolic SS_____Si______pIetMHggdzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETFTu" to i64) -// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" - -/// -> `MyActor.single_case_enum` -// CHECK: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" = private constant -// CHECK-SAME: @"symbolic __________AA______pIetMHygdzo_ 27distributed_actor_accessors7SimpleEO AA7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETFTu" to i64) -// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" - -/// -> `MyActor.with_indirect_enums` -// CHECK: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" = private constant -// CHECK-SAME: @"symbolic _____Si_____AA______pIetMHgygozo_ 27distributed_actor_accessors9IndirectEO AA7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETFTu" to i64) -// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" - -/// -> `MyActor.complex` -// CHECK: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" = private constant -// CHECK-SAME: @"symbolic SaySiG_____SSSg__________AD______pIetMHgggngrzo_ 27distributed_actor_accessors3ObjC AA11LargeStructV AA7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETFTu" to i64) -// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" - -/// -> `MyOtherActor.empty` -// CHECK: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" = private constant -// CHECK-SAME: @"symbolic ___________pIetMHgzo_ 27distributed_actor_accessors12MyOtherActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i64) -// CHECK-SAME: , section "__TEXT, __swift5_acfuncs, regular" - -// CHECK: @llvm.used = appending global [{{.*}} x i8*] [ -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" -// CHECK-SAME: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" -// CHECK-SAME: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" -// CHECK-SAME: ], section "llvm.metadata" - /// ---> Thunk and distributed method accessor for `simple1` /// Let's make sure that accessor loads the data from the buffer and calls expected accessor @@ -313,8 +257,8 @@ public distributed actor MyOtherActor { // CHECK-NEXT: [[ARR_PTR:%.*]] = bitcast i8* %elt_offset to %TSa* // CHECK-NEXT: %argval = load %TSa, %TSa* [[ARR_PTR]], align 8 // CHECK: store %TSa %argval, %TSa* %argval.coercion.coerced, align 8 -// CHECK-NEXT: [[PTR_TO_NATIVE_ARR:%.*]] = bitcast %TSa* %argval.coercion.coerced to %swift.bridge** -// CHECK-NEXT: [[NATIVE_ARR_VAL:%.*]] = load %swift.bridge*, %swift.bridge** [[PTR_TO_NATIVE_ARR]], align 8 +// CHECK-NEXT: [[PTR_TO_NATIVE_ARR:%.*]] = bitcast %TSa* %argval.coercion.coerced to [[NATIVE_ARR_TYPE:%.*]] +// CHECK-NEXT: [[NATIVE_ARR_VAL:%.*]] = load {{.*}}, [[NATIVE_ARR_TYPE]] [[PTR_TO_NATIVE_ARR]], align 8 // CHECK: [[ARR_PTR_INT:%.*]] = ptrtoint %TSa* [[ARR_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[ARR_PTR_INT]], 8 // CHECK-NEXT: [[OPAQUE_NEXT_ELT:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* @@ -359,7 +303,7 @@ public distributed actor MyOtherActor { /// Now let's make sure that distributed thunk call uses the arguments correctly -// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, %T27distributed_actor_accessors11LargeStructV* [[INDIRECT_RESULT_BUFF]], %swift.context* {{.*}}, %swift.bridge* [[NATIVE_ARR_VAL]], %T27distributed_actor_accessors3ObjC* [[NATIVE_OBJ_VAL]], i64 [[NATIVE_OPT_VAL_0]], i64 [[NATIVE_OPT_VAL_1]], %T27distributed_actor_accessors11LargeStructV* [[NATIVE_STRUCT_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, %T27distributed_actor_accessors11LargeStructV* [[INDIRECT_RESULT_BUFF]], %swift.context* {{.*}}, {{.*}} [[NATIVE_ARR_VAL]], %T27distributed_actor_accessors3ObjC* [[NATIVE_OBJ_VAL]], i64 [[NATIVE_OPT_VAL_0]], i64 [[NATIVE_OPT_VAL_1]], %T27distributed_actor_accessors11LargeStructV* [[NATIVE_STRUCT_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) /// RESULT is returned indirectly so there is nothing to pass to `end` From 304f3db05b5ec8efbbf0d13e2ef5903e57b5313d Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 16 Dec 2021 16:23:03 -0800 Subject: [PATCH 33/38] [Distributed] IRGen: Load arguments directly into argument explosion It's incorrect to load from the pointer directly, instead accessor should use `loadAsCopy` for loadable types. --- lib/IRGen/GenDistributed.cpp | 25 ++----- .../distributed_actor_accessor_thunks.swift | 73 ++++++++----------- 2 files changed, 36 insertions(+), 62 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index 665bf66a64cea..c842e8efa2168 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -208,7 +208,6 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, if (paramTy.isObject()) { auto &nativeSchema = typeInfo.nativeParameterValueSchema(IGM); - auto expandedTy = nativeSchema.getExpandedType(IGM); if (nativeSchema.requiresIndirect()) { llvm_unreachable("indirect parameters are not supported"); @@ -219,25 +218,13 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, continue; // 5. Load argument value from the element pointer. - auto *argValue = IGF.Builder.CreateLoad(alignedOffset, "argval"); - - Explosion nonNativeParam; - nonNativeParam.add(argValue); - - // Convert SIL type into a native representation. - auto nativeParam = nativeSchema.mapIntoNative( - IGM, IGF, nonNativeParam, paramTy, /*isOutlined=*/false); - - // If expanded type is a struct we need to explode it to match - // expected argument schema. - if (auto *ST = dyn_cast(expandedTy)) { - IGF.emitAllExtractValues(nativeParam.claimNext(), ST, arguments); - } else { - arguments.add(nativeParam.claimNext()); - } + cast(typeInfo).loadAsCopy(IGF, alignedOffset, arguments); } else { - // 5. Load argument value from the element pointer. - arguments.add(IGF.Builder.CreateLoad(alignedOffset, "argval")); + // If the value is not loadable e.g. generic or resilient + // pass its address as an argument. + // + // TODO: This needs to be copied and destroyed. + arguments.add(alignedOffset.getAddress()); } // 6. Move the offset to the beginning of the next element, unless diff --git a/test/Distributed/distributed_actor_accessor_thunks.swift b/test/Distributed/distributed_actor_accessor_thunks.swift index 45fbef7f9066e..51f62c94ec0a2 100644 --- a/test/Distributed/distributed_actor_accessor_thunks.swift +++ b/test/Distributed/distributed_actor_accessor_thunks.swift @@ -93,9 +93,7 @@ public distributed actor MyOtherActor { // CHECK: store i8* %1, i8** %offset, align 8 // CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 // CHECK-NEXT: [[ELT_PTR:%.*]] = bitcast i8* %elt_offset to %TSi* -// CHECK-NEXT: %argval = load %TSi, %TSi* [[ELT_PTR]], align 8 - -// CHECK: [[NATIVE_VAL_LOC:%.*]] = bitcast %TSi* %argval.coercion.coerced to i64* +// CHECK-NEXT: [[NATIVE_VAL_LOC:%.*]] = getelementptr inbounds %TSi, %TSi* [[ELT_PTR]], i32 0, i32 0 // CHECK-NEXT: [[ARG_VAL:%.*]] = load i64, i64* [[NATIVE_VAL_LOC]], align 8 /// Retrieve an async pointer to the distributed thunk for `simple1` @@ -156,11 +154,11 @@ public distributed actor MyOtherActor { // CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* [[RESULT_BUFF]] to %TSi* -// CHECK: %argval = load %TSS, %TSS* {{.*}}, align 8 -// CHECK: [[NATIVE_STR_PTR:%.*]] = bitcast %TSS* %argval.coercion.coerced to { i64, %swift.bridge* }* -// CHECK-NEXT: [[NATIVE_STR:%.*]] = load { i64, %swift.bridge* }, { i64, %swift.bridge* }* [[NATIVE_STR_PTR]], align 8 -// CHECK: [[STR_SIZE:%.*]] = extractvalue { i64, %swift.bridge* } [[NATIVE_STR]], 0 -// CHECK-NEXT: [[STR_VAL:%.*]] = extractvalue { i64, %swift.bridge* } [[NATIVE_STR]], 1 +// CHECK: [[ELT_PTR:%.*]] = bitcast i8* %elt_offset to %TSS* +// CHECK-NEXT: %._guts = getelementptr inbounds %TSS, %TSS* [[ELT_PTR]], i32 0, i32 0 + +// CHECK: [[STR_SIZE:%.*]] = load i64, i64* %._guts._object._countAndFlagsBits._value +// CHECK: [[STR_VAL:%.*]] = load %swift.bridge*, %swift.bridge** %._guts._object._object, align 8 /// Load pointer to a distributed thunk for `simple3` @@ -211,23 +209,18 @@ public distributed actor MyOtherActor { // CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* %2 to %T27distributed_actor_accessors9IndirectEO* // CHECK: store i8* %1, i8** %offset, align 8 // CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 + // CHECK-NEXT: [[ENUM_PTR:%.*]] = bitcast i8* %elt_offset to %T27distributed_actor_accessors9IndirectEO* -// CHECK-NEXT: %argval = load %T27distributed_actor_accessors9IndirectEO, %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]], align 8 -// CHECK-NEXT: [[OPAQUE_ENUM_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* %argval.coercion.coerced to i8* -// CHECK: store %T27distributed_actor_accessors9IndirectEO %argval, %T27distributed_actor_accessors9IndirectEO* %argval.coercion.coerced, align 8 -// CHECK-NEXT: [[COERCED_ENUM_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* %argval.coercion.coerced to i64* -// CHECK-NEXT: [[NATIVE_ENUM_VAL:%.*]] = load i64, i64* [[COERCED_ENUM_PTR]], align 8 +// CHECK-NEXT: [[NATIVE_ENUM_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]] to i64* +// CHECK-NEXT: [[NATIVE_ENUM_VAL:%.*]] = load i64, i64* [[NATIVE_ENUM_PTR]] // CHECK: [[ENUM_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT_LOC:%.*]] = add i64 [[ENUM_PTR_INT]], 8 // CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 [[NEXT_ELT_LOC]] to i8* -// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 -// CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset, align 8 +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset +// CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset // CHECK-NEXT: [[INT_PTR:%.*]] = bitcast i8* %elt_offset1 to %TSi* -// CHECK-NEXT: %argval2 = load %TSi, %TSi* [[INT_PTR]], align 8 -// CHECK-NEXT: [[OPAQUE_INT_PTR:%.*]] = bitcast %TSi* %argval2.coercion.coerced to i8* -// CHECK: store %TSi %argval2, %TSi* %argval2.coercion.coerced, align 8 -// CHECK-NEXT: [[COERCED_INT_PTR:%.*]] = bitcast %TSi* %argval2.coercion.coerced to i64* -// CHECK-NEXT: [[NATIVE_INT_VAL:%.*]] = load i64, i64* [[COERCED_INT_PTR]], align 8 +// CHECK-NEXT: %._value = getelementptr inbounds %TSi, %TSi* [[INT_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[NATIVE_INT_VAL:%.*]] = load i64, i64* %._value /// Call distributed thunk with extracted arguments. @@ -255,10 +248,8 @@ public distributed actor MyOtherActor { // CHECK: %elt_offset = load i8*, i8** %offset, align 8 // CHECK-NEXT: [[ARR_PTR:%.*]] = bitcast i8* %elt_offset to %TSa* -// CHECK-NEXT: %argval = load %TSa, %TSa* [[ARR_PTR]], align 8 -// CHECK: store %TSa %argval, %TSa* %argval.coercion.coerced, align 8 -// CHECK-NEXT: [[PTR_TO_NATIVE_ARR:%.*]] = bitcast %TSa* %argval.coercion.coerced to [[NATIVE_ARR_TYPE:%.*]] -// CHECK-NEXT: [[NATIVE_ARR_VAL:%.*]] = load {{.*}}, [[NATIVE_ARR_TYPE]] [[PTR_TO_NATIVE_ARR]], align 8 +// CHECK-NEXT: %._buffer = getelementptr inbounds %TSa, %TSa* [[ARR_PTR]], i32 0, i32 0 +// CHECK: [[NATIVE_ARR_VAL:%.*]] = load [[ARR_STORAGE_TYPE:%.*]], [[ARR_STORAGE_TYPE]]* %._buffer._storage // CHECK: [[ARR_PTR_INT:%.*]] = ptrtoint %TSa* [[ARR_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[ARR_PTR_INT]], 8 // CHECK-NEXT: [[OPAQUE_NEXT_ELT:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* @@ -269,41 +260,37 @@ public distributed actor MyOtherActor { // CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset, align 8 // CHECK-NEXT: [[OBJ_PTR:%.*]] = bitcast i8* %elt_offset1 to %T27distributed_actor_accessors3ObjC** // CHECK-NEXT: [[NATIVE_OBJ_VAL:%.*]] = load %T27distributed_actor_accessors3ObjC*, %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]], align 8 -// CHECK-NEXT: [[OBJ_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]] to i64 +// CHECK: [[OBJ_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[OBJ_PTR_INT]], 8 // CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* // CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 /// -> String? -// CHECK-NEXT: %elt_offset3 = load i8*, i8** %offset, align 8 -// CHECK-NEXT: [[OPT_PTR:%.*]] = bitcast i8* %elt_offset3 to %TSSSg* -// CHECK-NEXT: %argval4 = load %TSSSg, %TSSSg* [[OPT_PTR]], align 8 -// CHECK: store %TSSSg %argval4, %TSSSg* %argval4.coercion.coerced, align 8 -// CHECK-NEXT: [[NATIVE_OPT_PTR:%.*]] = bitcast %TSSSg* %argval4.coercion.coerced to { i64, i64 }* -// CHECK-NEXT: [[NATIVE_OPT_VAL:%.*]] = load { i64, i64 }, { i64, i64 }* [[NATIVE_OPT_PTR]], align 8 -// CHECK: [[NATIVE_OPT_VAL_0:%.*]] = extractvalue { i64, i64 } [[NATIVE_OPT_VAL]], 0 -// CHECK-NEXT: [[NATIVE_OPT_VAL_1:%.*]] = extractvalue { i64, i64 } [[NATIVE_OPT_VAL]], 1 -// CHECK-NEXT: [[OPT_PTR_INT:%.*]] = ptrtoint %TSSSg* [[OPT_PTR]] to i64 +// CHECK-NEXT: %elt_offset2 = load i8*, i8** %offset +// CHECK-NEXT: [[OPT_PTR:%.*]] = bitcast i8* %elt_offset2 to %TSSSg* +// CHECK-NEXT: [[NATIVE_OPT_PTR:%.*]] = bitcast %TSSSg* %22 to { i64, i64 }* +// CHECK-NEXT: [[NATIVE_OPT_VAL_0_PTR:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[NATIVE_OPT_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[NATIVE_OPT_VAL_0:%.*]] = load i64, i64* [[NATIVE_OPT_VAL_0_PTR]] +// CHECK-NEXT: [[NATIVE_OPT_VAL_1_PTR:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[NATIVE_OPT_PTR]], i32 0, i32 1 +// CHECK-NEXT: [[NATIVE_OPT_VAL_1_OPAQUE:%.*]] = load i64, i64* [[NATIVE_OPT_VAL_1_PTR]] +// CHECK-NEXT: [[NATIVE_OPT_VAL_1_OBJ:%.*]] = inttoptr i64 [[NATIVE_OPT_VAL_1_OPAQUE]] to %swift.bridge* +// CHECK: [[NATIVE_OPT_VAL_1:%.*]] = ptrtoint %swift.bridge* [[NATIVE_OPT_VAL_1_OBJ]] to i64 +// CHECK: [[OPT_PTR_INT:%.*]] = ptrtoint %TSSSg* [[OPT_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[OPT_PTR_INT]], 16 // CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* -// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset /// -> LargeStruct (passed indirectly) -// CHECK-NEXT: %elt_offset5 = load i8*, i8** %offset, align 8 -// CHECK-NEXT: [[STRUCT_PTR:%.*]] = bitcast i8* %elt_offset5 to %T27distributed_actor_accessors11LargeStructV* -// CHECK-NEXT: [[STRUCT_VAL:%.*]] = load %T27distributed_actor_accessors11LargeStructV, %T27distributed_actor_accessors11LargeStructV* [[STRUCT_PTR]], align 8 +// CHECK-NEXT: %elt_offset3 = load i8*, i8** %offset, align 8 +// CHECK-NEXT: [[STRUCT_PTR:%.*]] = bitcast i8* %elt_offset3 to %T27distributed_actor_accessors11LargeStructV* // CHECK: [[INDIRECT_RESULT_BUFF:%.*]] = bitcast %swift.opaque* [[TYPED_RESULT_BUFF]] to %T27distributed_actor_accessors11LargeStructV* -// CHECK: store %T27distributed_actor_accessors11LargeStructV [[STRUCT_VAL]], %T27distributed_actor_accessors11LargeStructV* %argval6.coercion.coerced, align 8 -// CHECK-NEXT: [[PTR_TO_STRUCT:%.*]] = bitcast %T27distributed_actor_accessors11LargeStructV* %argval6.coercion.coerced to %T27distributed_actor_accessors11LargeStructV** -// CHECK-NEXT: [[NATIVE_STRUCT_VAL:%.*]] = load %T27distributed_actor_accessors11LargeStructV*, %T27distributed_actor_accessors11LargeStructV** [[PTR_TO_STRUCT]], align 8 - /// Now let's make sure that distributed thunk call uses the arguments correctly -// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, %T27distributed_actor_accessors11LargeStructV* [[INDIRECT_RESULT_BUFF]], %swift.context* {{.*}}, {{.*}} [[NATIVE_ARR_VAL]], %T27distributed_actor_accessors3ObjC* [[NATIVE_OBJ_VAL]], i64 [[NATIVE_OPT_VAL_0]], i64 [[NATIVE_OPT_VAL_1]], %T27distributed_actor_accessors11LargeStructV* [[NATIVE_STRUCT_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, %T27distributed_actor_accessors11LargeStructV* [[INDIRECT_RESULT_BUFF]], %swift.context* {{.*}}, {{.*}} [[NATIVE_ARR_VAL]], %T27distributed_actor_accessors3ObjC* [[NATIVE_OBJ_VAL]], i64 [[NATIVE_OPT_VAL_0]], i64 [[NATIVE_OPT_VAL_1]], %T27distributed_actor_accessors11LargeStructV* [[STRUCT_PTR]], %T27distributed_actor_accessors7MyActorC* {{.*}}) /// RESULT is returned indirectly so there is nothing to pass to `end` From 2180e4deed9edb1a8b562ee39831d9b63ecebab6 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 16 Dec 2021 17:53:06 -0800 Subject: [PATCH 34/38] [Distributed] IRGen: Make sure that arguments extracted from buffer have correct ownership Use parameter convention information to determine ownership of the extracted arguments. --- lib/IRGen/GenDistributed.cpp | 73 +++++++++++++++---- .../distributed_actor_accessor_thunks.swift | 8 +- 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/lib/IRGen/GenDistributed.cpp b/lib/IRGen/GenDistributed.cpp index c842e8efa2168..3a1b6e821c03f 100644 --- a/lib/IRGen/GenDistributed.cpp +++ b/lib/IRGen/GenDistributed.cpp @@ -64,6 +64,12 @@ llvm::Value *irgen::emitDistributedActorInitializeRemote( namespace { +struct AllocationInfo { + SILType Type; + const TypeInfo &TI; + StackAddress Addr; +}; + class DistributedAccessor { IRGenModule &IGM; IRGenFunction &IGF; @@ -76,6 +82,9 @@ class DistributedAccessor { /// The asynchronous context associated with this accessor. AsyncContextLayout AsyncLayout; + /// The list of all arguments that were allocated on the stack. + SmallVector AllocatedArguments; + public: DistributedAccessor(IRGenFunction &IGF, SILFunction *method, CanSILFunctionType accessorTy); @@ -203,28 +212,56 @@ void DistributedAccessor::computeArguments(llvm::Value *argumentBuffer, // 3. Adjust typed pointer to the alignement of the type. auto alignedOffset = typeInfo.roundUpToTypeAlignment(IGF, eltPtr, paramTy); - // 4. Create an exploded version of the type to pass as an - // argument to distributed method. - if (paramTy.isObject()) { auto &nativeSchema = typeInfo.nativeParameterValueSchema(IGM); - - if (nativeSchema.requiresIndirect()) { - llvm_unreachable("indirect parameters are not supported"); - } - // If schema is empty, skip to the next argument. if (nativeSchema.empty()) continue; + } + + // 4. Create an exploded version of the type to pass as an + // argument to distributed method. + + switch (param.getConvention()) { + case ParameterConvention::Indirect_In: + case ParameterConvention::Indirect_In_Constant: { + // The +1 argument is passed indirectly, so we need to copy it into + // a temporary. - // 5. Load argument value from the element pointer. - cast(typeInfo).loadAsCopy(IGF, alignedOffset, arguments); - } else { - // If the value is not loadable e.g. generic or resilient - // pass its address as an argument. - // - // TODO: This needs to be copied and destroyed. + auto stackAddr = typeInfo.allocateStack(IGF, paramTy, "arg.temp"); + auto argPtr = stackAddr.getAddress().getAddress(); + + typeInfo.initializeWithCopy(IGF, stackAddr.getAddress(), alignedOffset, + paramTy, /*isOutlined=*/false); + arguments.add(argPtr); + + // Remember to deallocate later. + AllocatedArguments.push_back({paramTy, typeInfo, stackAddr}); + break; + } + + case ParameterConvention::Indirect_In_Guaranteed: { + // The argument is +0, so we can use the address of the param in + // the context directly. arguments.add(alignedOffset.getAddress()); + break; + } + + case ParameterConvention::Indirect_Inout: + case ParameterConvention::Indirect_InoutAliasable: + llvm_unreachable("indirect parameters are not supported"); + + case ParameterConvention::Direct_Guaranteed: + case ParameterConvention::Direct_Unowned: { + cast(typeInfo).loadAsTake(IGF, alignedOffset, + arguments); + break; + } + + case ParameterConvention::Direct_Owned: + // Copy the value out at +1. + cast(typeInfo).loadAsCopy(IGF, alignedOffset, + arguments); } // 6. Move the offset to the beginning of the next element, unless @@ -335,6 +372,12 @@ void DistributedAccessor::emit() { emission->end(); + // Deallocate all of the copied arguments. + { + for (auto &entry : AllocatedArguments) + entry.TI.deallocateStack(IGF, entry.Addr, entry.Type); + } + Explosion voidResult; emitAsyncReturn(IGF, AsyncLayout, accessorConv.getSILResultType(expansionContext), diff --git a/test/Distributed/distributed_actor_accessor_thunks.swift b/test/Distributed/distributed_actor_accessor_thunks.swift index 51f62c94ec0a2..02709d671e8c6 100644 --- a/test/Distributed/distributed_actor_accessor_thunks.swift +++ b/test/Distributed/distributed_actor_accessor_thunks.swift @@ -269,14 +269,12 @@ public distributed actor MyOtherActor { // CHECK-NEXT: %elt_offset2 = load i8*, i8** %offset // CHECK-NEXT: [[OPT_PTR:%.*]] = bitcast i8* %elt_offset2 to %TSSSg* -// CHECK-NEXT: [[NATIVE_OPT_PTR:%.*]] = bitcast %TSSSg* %22 to { i64, i64 }* +// CHECK-NEXT: [[NATIVE_OPT_PTR:%.*]] = bitcast %TSSSg* [[OPT_PTR]] to { i64, i64 }* // CHECK-NEXT: [[NATIVE_OPT_VAL_0_PTR:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[NATIVE_OPT_PTR]], i32 0, i32 0 // CHECK-NEXT: [[NATIVE_OPT_VAL_0:%.*]] = load i64, i64* [[NATIVE_OPT_VAL_0_PTR]] // CHECK-NEXT: [[NATIVE_OPT_VAL_1_PTR:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 }* [[NATIVE_OPT_PTR]], i32 0, i32 1 -// CHECK-NEXT: [[NATIVE_OPT_VAL_1_OPAQUE:%.*]] = load i64, i64* [[NATIVE_OPT_VAL_1_PTR]] -// CHECK-NEXT: [[NATIVE_OPT_VAL_1_OBJ:%.*]] = inttoptr i64 [[NATIVE_OPT_VAL_1_OPAQUE]] to %swift.bridge* -// CHECK: [[NATIVE_OPT_VAL_1:%.*]] = ptrtoint %swift.bridge* [[NATIVE_OPT_VAL_1_OBJ]] to i64 -// CHECK: [[OPT_PTR_INT:%.*]] = ptrtoint %TSSSg* [[OPT_PTR]] to i64 +// CHECK-NEXT: [[NATIVE_OPT_VAL_1:%.*]] = load i64, i64* [[NATIVE_OPT_VAL_1_PTR]] +// CHECK-NEXT: [[OPT_PTR_INT:%.*]] = ptrtoint %TSSSg* [[OPT_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[OPT_PTR_INT]], 16 // CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* // CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset From bc09fa3a2f7b9ed97d55af5dcd1e9820c74e5bf6 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Thu, 16 Dec 2021 18:15:43 -0800 Subject: [PATCH 35/38] [Distributed] NFC: Remove `align 8` from the accessor thunks test-cases --- .../distributed_actor_accessor_thunks.swift | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/Distributed/distributed_actor_accessor_thunks.swift b/test/Distributed/distributed_actor_accessor_thunks.swift index 02709d671e8c6..c194fc53d9fed 100644 --- a/test/Distributed/distributed_actor_accessor_thunks.swift +++ b/test/Distributed/distributed_actor_accessor_thunks.swift @@ -90,11 +90,11 @@ public distributed actor MyOtherActor { /// Read the current offset and cast an element to `Int` -// CHECK: store i8* %1, i8** %offset, align 8 -// CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 +// CHECK: store i8* %1, i8** %offset +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset // CHECK-NEXT: [[ELT_PTR:%.*]] = bitcast i8* %elt_offset to %TSi* // CHECK-NEXT: [[NATIVE_VAL_LOC:%.*]] = getelementptr inbounds %TSi, %TSi* [[ELT_PTR]], i32 0, i32 0 -// CHECK-NEXT: [[ARG_VAL:%.*]] = load i64, i64* [[NATIVE_VAL_LOC]], align 8 +// CHECK-NEXT: [[ARG_VAL:%.*]] = load i64, i64* [[NATIVE_VAL_LOC]] /// Retrieve an async pointer to the distributed thunk for `simple1` @@ -117,7 +117,7 @@ public distributed actor MyOtherActor { // CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETF" /// !!! - We are not going to double-check argument extraction here since it's the same as `simple1`. -// CHECK: [[NATIVE_ARG_VAL:%.*]] = load i64, i64* {{.*}}, align 8 +// CHECK: [[NATIVE_ARG_VAL:%.*]] = load i64, i64* {{.*}} /// Load async pointer to distributed thunk for `simple2` @@ -140,8 +140,8 @@ public distributed actor MyOtherActor { /// Initialize the result buffer with values produced by the thunk -// CHECK: store i64 [[STR_SIZE]], i64* %._guts._object._countAndFlagsBits._value, align 8 -// CHECK: store %swift.bridge* [[STR_VAL]], %swift.bridge** %._guts._object._object, align 8 +// CHECK: store i64 [[STR_SIZE]], i64* %._guts._object._countAndFlagsBits._value +// CHECK: store %swift.bridge* [[STR_VAL]], %swift.bridge** %._guts._object._object // CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) @@ -158,7 +158,7 @@ public distributed actor MyOtherActor { // CHECK-NEXT: %._guts = getelementptr inbounds %TSS, %TSS* [[ELT_PTR]], i32 0, i32 0 // CHECK: [[STR_SIZE:%.*]] = load i64, i64* %._guts._object._countAndFlagsBits._value -// CHECK: [[STR_VAL:%.*]] = load %swift.bridge*, %swift.bridge** %._guts._object._object, align 8 +// CHECK: [[STR_VAL:%.*]] = load %swift.bridge*, %swift.bridge** %._guts._object._object /// Load pointer to a distributed thunk for `simple3` @@ -174,7 +174,7 @@ public distributed actor MyOtherActor { // CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) // CHECK: [[INT_RES:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 1 // CHECK: %._value = getelementptr inbounds %TSi, %TSi* [[TYPED_RESULT_BUFF]], i32 0, i32 0 -// CHECK: store i64 [[INT_RES]], i64* %._value, align 8 +// CHECK: store i64 [[INT_RES]], i64* %._value // CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) /// --> Thunk and distributed method accessor for `single_case_enum` @@ -187,8 +187,8 @@ public distributed actor MyOtherActor { // CHECK: [[OFFSET:%.*]] = bitcast i8** %offset to i8* // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[OFFSET]]) -// CHECK-NEXT: store i8* [[BUFFER]], i8** %offset, align 8 -// CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 +// CHECK-NEXT: store i8* [[BUFFER]], i8** %offset +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset // CHECK-NEXT: [[ELT_PTR:.*]] = bitcast i8* %elt_offset to %T27distributed_actor_accessors7SimpleEO* // CHECK-NEXT: [[OFFSET:%.*]] = bitcast i8** %offset to i8* // CHECK-NEXT call void @llvm.lifetime.end.p0i8(i64 8, i8* [[OFFSET]]) @@ -207,8 +207,8 @@ public distributed actor MyOtherActor { /// First, Load both arguments from the buffer. // CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* %2 to %T27distributed_actor_accessors9IndirectEO* -// CHECK: store i8* %1, i8** %offset, align 8 -// CHECK-NEXT: %elt_offset = load i8*, i8** %offset, align 8 +// CHECK: store i8* %1, i8** %offset +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset // CHECK-NEXT: [[ENUM_PTR:%.*]] = bitcast i8* %elt_offset to %T27distributed_actor_accessors9IndirectEO* // CHECK-NEXT: [[NATIVE_ENUM_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]] to i64* @@ -229,7 +229,7 @@ public distributed actor MyOtherActor { // CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) // CHECK: [[ENUM_RESULT:%.*]] = extractvalue { i8*, i64, %swift.error* } [[THUNK_RESULT]], 1 // CHECK: [[NATIVE_RESULT_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* [[TYPED_RESULT_BUFF]] to i64* -// CHECK-NEXT: store i64 [[ENUM_RESULT]], i64* [[NATIVE_RESULT_PTR]], align 8 +// CHECK-NEXT: store i64 [[ENUM_RESULT]], i64* [[NATIVE_RESULT_PTR]] // CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) @@ -246,24 +246,24 @@ public distributed actor MyOtherActor { /// -> [Int] -// CHECK: %elt_offset = load i8*, i8** %offset, align 8 +// CHECK: %elt_offset = load i8*, i8** %offset // CHECK-NEXT: [[ARR_PTR:%.*]] = bitcast i8* %elt_offset to %TSa* // CHECK-NEXT: %._buffer = getelementptr inbounds %TSa, %TSa* [[ARR_PTR]], i32 0, i32 0 // CHECK: [[NATIVE_ARR_VAL:%.*]] = load [[ARR_STORAGE_TYPE:%.*]], [[ARR_STORAGE_TYPE]]* %._buffer._storage // CHECK: [[ARR_PTR_INT:%.*]] = ptrtoint %TSa* [[ARR_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[ARR_PTR_INT]], 8 // CHECK-NEXT: [[OPAQUE_NEXT_ELT:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* -// CHECK-NEXT: store i8* [[OPAQUE_NEXT_ELT]], i8** %offset, align 8 +// CHECK-NEXT: store i8* [[OPAQUE_NEXT_ELT]], i8** %offset /// -> Obj -// CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset, align 8 +// CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset // CHECK-NEXT: [[OBJ_PTR:%.*]] = bitcast i8* %elt_offset1 to %T27distributed_actor_accessors3ObjC** -// CHECK-NEXT: [[NATIVE_OBJ_VAL:%.*]] = load %T27distributed_actor_accessors3ObjC*, %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]], align 8 +// CHECK-NEXT: [[NATIVE_OBJ_VAL:%.*]] = load %T27distributed_actor_accessors3ObjC*, %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]] // CHECK: [[OBJ_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]] to i64 // CHECK-NEXT: [[NEXT_ELT:%.*]] = add i64 [[OBJ_PTR_INT]], 8 // CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i64 [[NEXT_ELT]] to i8* -// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset, align 8 +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset /// -> String? @@ -281,7 +281,7 @@ public distributed actor MyOtherActor { /// -> LargeStruct (passed indirectly) -// CHECK-NEXT: %elt_offset3 = load i8*, i8** %offset, align 8 +// CHECK-NEXT: %elt_offset3 = load i8*, i8** %offset // CHECK-NEXT: [[STRUCT_PTR:%.*]] = bitcast i8* %elt_offset3 to %T27distributed_actor_accessors11LargeStructV* // CHECK: [[INDIRECT_RESULT_BUFF:%.*]] = bitcast %swift.opaque* [[TYPED_RESULT_BUFF]] to %T27distributed_actor_accessors11LargeStructV* @@ -300,11 +300,11 @@ public distributed actor MyOtherActor { // CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETF"(%swift.context* swiftasync {{.*}}, i8* [[ARG_BUFF:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) // CHECK-NEXT: entry: -// CHECK-NEXT: {{.*}} = alloca %swift.context*, align 8 -// CHECK-NEXT: %swifterror = alloca swifterror %swift.error*, align 8 +// CHECK-NEXT: {{.*}} = alloca %swift.context* +// CHECK-NEXT: %swifterror = alloca swifterror %swift.error* // CHECK-NEXT: {{.*}} = call token @llvm.coro.id.async(i32 20, i32 16, i32 0, i8* bitcast (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i8*)) // CHECK-NEXT: {{.*}} = call i8* @llvm.coro.begin(token {{%.*}}, i8* null) -// CHECK-NEXT: store %swift.context* {{.*}}, %swift.context** {{.*}}, align 8 -// CHECK-NEXT: store %swift.error* null, %swift.error** %swifterror, align 8 +// CHECK-NEXT: store %swift.context* {{.*}}, %swift.context** {{.*}} +// CHECK-NEXT: store %swift.error* null, %swift.error** %swifterror // CHECK-NEXT: {{.*}} = bitcast i8* [[RESULT_BUFF]] to %swift.opaque* -// CHECK-NEXT: {{.*}} = load i32, i32* getelementptr inbounds (%swift.async_func_pointer, %swift.async_func_pointer* bitcast (void (%swift.context*, %T27distributed_actor_accessors12MyOtherActorC*)* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTE" to %swift.async_func_pointer*), i32 0, i32 0), align 8 +// CHECK-NEXT: {{.*}} = load i32, i32* getelementptr inbounds (%swift.async_func_pointer, %swift.async_func_pointer* bitcast (void (%swift.context*, %T27distributed_actor_accessors12MyOtherActorC*)* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTE" to %swift.async_func_pointer*), i32 0, i32 0) From 8d14443f940a03ef2a5f3aede5d721a2c7cbbc73 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 17 Dec 2021 01:17:47 -0800 Subject: [PATCH 36/38] [Distributed] Runtime: Fix accessor section test-case to support 32/64 bit platforms --- .../distributed_actor_accessor_section_macho.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/Distributed/distributed_actor_accessor_section_macho.swift b/test/Distributed/distributed_actor_accessor_section_macho.swift index 7948f3e5f7dac..b9e718976a7e7 100644 --- a/test/Distributed/distributed_actor_accessor_section_macho.swift +++ b/test/Distributed/distributed_actor_accessor_section_macho.swift @@ -89,43 +89,43 @@ public distributed actor MyOtherActor { /// -> `MyActor.simple1` // CHECK: @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTEHF" = private constant // CHECK-SAME: @"symbolic Si___________pIetMHygzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETFTu" to i64) +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETFTu" to i{{32|64}}) // CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} /// -> `MyActor.simple2` // CHECK: @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTEHF" = private constant // CHECK-SAME: @"symbolic Si_____SS______pIetMHygozo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETFTu" to i64) +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETFTu" to i{{32|64}}) // CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} /// -> `MyActor.simple3` // CHECK: @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTEHF" = private constant // CHECK-SAME: @"symbolic SS_____Si______pIetMHggdzo_ 27distributed_actor_accessors7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETFTu" to i64) +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETFTu" to i{{32|64}}) // CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} /// -> `MyActor.single_case_enum` // CHECK: @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTEHF" = private constant // CHECK-SAME: @"symbolic __________AA______pIetMHygdzo_ 27distributed_actor_accessors7SimpleEO AA7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETFTu" to i64) +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETFTu" to i{{32|64}}) // CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} /// -> `MyActor.with_indirect_enums` // CHECK: @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTEHF" = private constant // CHECK-SAME: @"symbolic _____Si_____AA______pIetMHgygozo_ 27distributed_actor_accessors9IndirectEO AA7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETFTu" to i64) +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETFTu" to i{{32|64}}) // CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} /// -> `MyActor.complex` // CHECK: @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTEHF" = private constant // CHECK-SAME: @"symbolic SaySiG_____SSSg__________AD______pIetMHgggngrzo_ 27distributed_actor_accessors3ObjC AA11LargeStructV AA7MyActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETFTu" to i64) +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETFTu" to i{{32|64}}) // CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} /// -> `MyOtherActor.empty` // CHECK: @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTEHF" = private constant // CHECK-SAME: @"symbolic ___________pIetMHgzo_ 27distributed_actor_accessors12MyOtherActorC s5ErrorP" -// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i64) +// CHECK-SAME: (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i{{32|64}}) // CHECK-SAME: , section {{"swift5_accessible_functions"|".sw5acfn$B"|"__TEXT, __swift5_acfuncs, regular"}} // CHECK: @llvm.used = appending global [{{.*}} x i8*] [ From 351300e1c3cbb2ec568e97c6552ce063c456fe9b Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 17 Dec 2021 10:27:10 -0800 Subject: [PATCH 37/38] [Distributed] Runtime/NFC: Split accessor thunk tests into 32/64 bit versions --- ...tributed_actor_accessor_thunks_32bit.swift | 334 ++++++++++++++++++ ...ributed_actor_accessor_thunks_64bit.swift} | 2 + 2 files changed, 336 insertions(+) create mode 100644 test/Distributed/distributed_actor_accessor_thunks_32bit.swift rename test/Distributed/{distributed_actor_accessor_thunks.swift => distributed_actor_accessor_thunks_64bit.swift} (99%) diff --git a/test/Distributed/distributed_actor_accessor_thunks_32bit.swift b/test/Distributed/distributed_actor_accessor_thunks_32bit.swift new file mode 100644 index 0000000000000..a302fce0d2ab7 --- /dev/null +++ b/test/Distributed/distributed_actor_accessor_thunks_32bit.swift @@ -0,0 +1,334 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -module-name distributed_actor_accessors -emit-irgen -enable-experimental-distributed -disable-availability-checking -I %t 2>&1 %s | %IRGenFileCheck %s + +// UNSUPPORTED: back_deploy_concurrency +// REQUIRES: concurrency +// REQUIRES: distributed + +// REQUIRES: CPU=i386 + +import _Distributed +import FakeDistributedActorSystems + +@available(SwiftStdlib 5.5, *) +typealias DefaultDistributedActorSystem = FakeActorSystem + +enum SimpleE : Codable { +case a +} + +enum E : Codable { +case a, b, c +} + +enum IndirectE : Codable { + case empty + indirect case test(_: Int) +} + +final class Obj : Codable, Sendable { + let x: Int + + init(x: Int) { + self.x = x + } +} + +struct LargeStruct : Codable { + var a: Int + var b: Int + var c: String + var d: Double +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyActor { + distributed func simple1(_: Int) { + } + + // `String` would be a direct result as a struct type + distributed func simple2(_: Int) -> String { + return "" + } + + // `String` is an object that gets exploded into two parameters + distributed func simple3(_: String) -> Int { + return 42 + } + + // Enum with a single case are special because they have an empty + // native schema so they are dropped from parameters/result. + distributed func single_case_enum(_ e: SimpleE) -> SimpleE { + return e + } + + distributed func with_indirect_enums(_: IndirectE, _: Int) -> IndirectE { + return .empty + } + + // Combination of multiple arguments, reference type and indirect result + // + // Note: Tuple types cannot be used here is either position because they + // cannot conform to protocols. + distributed func complex(_: [Int], _: Obj, _: String?, _: LargeStruct) -> LargeStruct { + fatalError() + } +} + +@available(SwiftStdlib 5.6, *) +public distributed actor MyOtherActor { + distributed func empty() { + } +} + +/// ---> Thunk and distributed method accessor for `simple1` + +/// Let's make sure that accessor loads the data from the buffer and calls expected accessor + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTE" + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTETF"(%swift.context* swiftasync %0, i8* %1, i8* %2, %swift.refcounted* swiftself %3) + +/// Read the current offset and cast an element to `Int` + +// CHECK: store i8* %1, i8** %offset +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset +// CHECK-NEXT: [[ELT_PTR:%.*]] = bitcast i8* %elt_offset to %TSi* +// CHECK-NEXT: [[NATIVE_VAL_LOC:%.*]] = getelementptr inbounds %TSi, %TSi* [[ELT_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[ARG_VAL:%.*]] = load i32, i32* [[NATIVE_VAL_LOC]] + +/// Retrieve an async pointer to the distributed thunk for `simple1` + +// CHECK: [[THUNK_LOC:%.*]] = add i32 ptrtoint (void (%swift.context*, i32, %T27distributed_actor_accessors7MyActorC*)* @"$s27distributed_actor_accessors7MyActorC7simple1yySiFTE" to i32), {{.*}} +// CHECK-NEXT: [[OPAQUE_THUNK_PTR:%.*]] = inttoptr i32 [[THUNK_LOC]] to i8* +// CHECK-NEXT: [[THUNK_PTR:%.*]] = bitcast i8* [[OPAQUE_THUNK_PTR]] to void (%swift.context*, i32, %T27distributed_actor_accessors7MyActorC*)* + +/// Call distributed thunk for `simple1` and `end` async context without results + +// CHECK: [[THUNK_PTR_REF:%.*]] = bitcast void (%swift.context*, i32, %T27distributed_actor_accessors7MyActorC*)* [[THUNK_PTR]] to i8* +// CHECK-NEXT: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, i8* [[THUNK_PTR_REF]], %swift.context* {{.*}}, i32 [[ARG_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, %swift.error* } [[THUNK_RESULT]], 0 +// CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// ---> Thunk and distributed method accessor for `simple2` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTE" + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTETF" + +// CHECK: [[COERCED_RESULT_SLOT:%.*]] = bitcast i8* {{.*}} to %TSS* + +/// !!! - We are not going to double-check argument extraction here since it's the same as `simple1`. +// CHECK: [[NATIVE_ARG_VAL:%.*]] = load i32, i32* {{.*}} + +/// Load async pointer to distributed thunk for `simple2` + +// CHECK: [[THUNK_LOC:%.*]] = add i32 ptrtoint (void (%swift.context*, i32, %T27distributed_actor_accessors7MyActorC*)* @"$s27distributed_actor_accessors7MyActorC7simple2ySSSiFTE" to i32), {{.*}} +// CHECK-NEXT: [[OPAQUE_THUNK_PTR:%.*]] = inttoptr i32 [[THUNK_LOC]] to i8* +// CHECK-NEXT: [[THUNK_PTR:%.*]] = bitcast i8* [[OPAQUE_THUNK_PTR]] to void (%swift.context*, i32, %T27distributed_actor_accessors7MyActorC*)* + +/// Call the thunk with extracted argument value + +// CHECK: [[THUNK_PTR_REF:%.*]] = bitcast void (%swift.context*, i32, %T27distributed_actor_accessors7MyActorC*)* [[THUNK_PTR]] to i8* +// CHECK-NEXT: [[THUNK_RESULT:%.*]] = call { i8*, i32, i32, i32, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8i32i32i32p0s_swift.errorss({{.*}}, i8* [[THUNK_PTR_REF]], %swift.context* {{.*}}, i32 [[NATIVE_ARG_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, i32, i32, i32, %swift.error* } [[THUNK_RESULT]], 0 +// CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) + +/// Initialize the result buffer with values produced by the thunk + +// CHECK: %._guts1 = getelementptr inbounds %TSS, %TSS* [[COERCED_RESULT_SLOT]], i32 0, i32 0 +// CHECK: store i32 {{.*}}, i32* %._guts1._object._count._value +// CHECK: store i8 {{.*}}, i8* %._guts1._object._discriminator._value +// CHECK: store i16 {{.*}}, i16* %._guts1._object._flags._value, align 2 + +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// ---> Thunk and distributed method accessor for `simple3` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTE" + +/// !!! in `simple3` interesting bits are: argument value extraction (because string is exploded into N arguments) and call to distributed thunk +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTETF"(%swift.context* swiftasync {{.*}}, i8* [[ARG_BUFF:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) + +// CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* [[RESULT_BUFF]] to %TSi* + +// CHECK: [[ELT_PTR:%.*]] = bitcast i8* %elt_offset to %TSS* +// CHECK-NEXT: %._guts = getelementptr inbounds %TSS, %TSS* [[ELT_PTR]], i32 0, i32 0 + +// CHECK: [[STR_SIZE:%.*]] = load i32, i32* %._guts._object._count._value +// CHECK-NEXT: %._guts._object._variant = getelementptr inbounds %Ts13_StringObjectV, %Ts13_StringObjectV* %._guts._object, i32 0, i32 1 +// CHECK-NEXT: [[NATIVE_STR_VAL_PTR:%.*]] = bitcast %Ts13_StringObjectV7VariantO* %._guts._object._variant to i32* +// CHECK-NEXT: [[STR_VAL:%.*]] = load i32, i32* [[NATIVE_STR_VAL_PTR]] + +/// Load pointer to a distributed thunk for `simple3` + +// CHECK: [[THUNK_LOC:%.*]] = add i32 ptrtoint (void (%swift.context*, i32, i32, i32, %T27distributed_actor_accessors7MyActorC*)* @"$s27distributed_actor_accessors7MyActorC7simple3ySiSSFTE" to i32) +// CHECK-NEXT: [[OPAQUE_THUNK_PTR:%.*]] = inttoptr i32 [[THUNK_LOC]] to i8* +// CHECK-NEXT: [[THUNK_PTR:%.*]] = bitcast i8* [[OPAQUE_THUNK_PTR]] to void (%swift.context*, i32, i32, i32, %T27distributed_actor_accessors7MyActorC*)* + +// CHECK: [[TMP_STR_ARG:%.*]] = bitcast { i32, i32, i32 }* %temp-coercion.coerced to %TSS* +// CHECK-NEXT: %._guts1 = getelementptr inbounds %TSS, %TSS* [[TMP_STR_ARG]], i32 0, i32 0 + +// CHECK: store i32 %10, i32* %._guts1._object._count._value, align 4 +// CHECK: store i32 %12, i32* %28, align 4 + +// CHECK: [[STR_ARG_SIZE_PTR:%.*]] = getelementptr inbounds { i32, i32, i32 }, { i32, i32, i32 }* %temp-coercion.coerced, i32 0, i32 0 +// CHECK: [[STR_ARG_SIZE:%.*]] = load i32, i32* [[STR_ARG_SIZE_PTR]] + +// CHECK: [[STR_ARG_VAL_PTR:%.*]] = getelementptr inbounds { i32, i32, i32 }, { i32, i32, i32 }* %temp-coercion.coerced, i32 0, i32 1 +// CHECK: [[STR_ARG_VAL:%.*]] = load i32, i32* [[STR_ARG_VAL_PTR]] + +// CHECK: [[STR_ARG_FLAGS_PTR:%.*]] = getelementptr inbounds { i32, i32, i32 }, { i32, i32, i32 }* %temp-coercion.coerced, i32 0, i32 2 +// CHECK: [[STR_ARG_FLAGS:%.*]] = load i32, i32* [[STR_ARG_FLAGS_PTR]] + +/// Call distributed thunk with exploaded string value + +// CHECK: [[OPAQUE_THUNK_PTR:%.*]] = bitcast void (%swift.context*, i32, i32, i32, %T27distributed_actor_accessors7MyActorC*)* [[THUNK_PTR]] to i8* +// CHECK-NEXT: [[THUNK_RESULT:%.*]] = call { i8*, i32, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8i32p0s_swift.errorss({{.*}}, i8* [[OPAQUE_THUNK_PTR]], %swift.context* {{.*}}, i32 [[STR_ARG_SIZE]], i32 [[STR_ARG_VAL]], i32 [[STR_ARG_FLAGS]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, i32, %swift.error* } [[THUNK_RESULT]], 0 +// CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) +// CHECK: [[INT_RES:%.*]] = extractvalue { i8*, i32, %swift.error* } [[THUNK_RESULT]], 1 +// CHECK: %._value = getelementptr inbounds %TSi, %TSi* [[TYPED_RESULT_BUFF]], i32 0, i32 0 +// CHECK: store i32 [[INT_RES]], i32* %._value +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// --> Thunk and distributed method accessor for `single_case_enum` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTE" + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC16single_case_enumyAA7SimpleEOAFFTETF"(%swift.context* swiftasync %0, i8* [[BUFFER:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) + +/// First, let's check that there were no loads from the argument buffer and no stores to "current offset". + +// CHECK: [[OFFSET:%.*]] = bitcast i8** %offset to i8* +// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 4, i8* [[OFFSET]]) +// CHECK-NEXT: store i8* [[BUFFER]], i8** %offset +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset +// CHECK-NEXT: [[ELT_PTR:.*]] = bitcast i8* %elt_offset to %T27distributed_actor_accessors7SimpleEO* +// CHECK-NEXT: [[OFFSET:%.*]] = bitcast i8** %offset to i8* +// CHECK-NEXT call void @llvm.lifetime.end.p0i8(i32 8, i8* [[OFFSET]]) + +/// Now, let's check that the call doesn't have any arguments and returns nothing. + +// CHECK: [[THUNK_REF:%.*]] = bitcast void (%swift.context*, %T27distributed_actor_accessors7MyActorC*)* {{.*}} to i8* +// CHECK: {{.*}} = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, i8* [[THUNK_REF]], %swift.context* {{.*}}, %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, i8* {{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// --> Thunk and distributed method accessor for `with_indirect_enums` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTE" +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC19with_indirect_enumsyAA9IndirectEOAF_SitFTETF" + +/// First, Load both arguments from the buffer. + +// CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* %2 to %T27distributed_actor_accessors9IndirectEO* +// CHECK: store i8* %1, i8** %offset +// CHECK-NEXT: %elt_offset = load i8*, i8** %offset + +// CHECK-NEXT: [[ENUM_PTR:%.*]] = bitcast i8* %elt_offset to %T27distributed_actor_accessors9IndirectEO* +// CHECK-NEXT: [[NATIVE_ENUM_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]] to i32* +// CHECK-NEXT: [[NATIVE_ENUM_VAL:%.*]] = load i32, i32* [[NATIVE_ENUM_PTR]] +// CHECK: [[ENUM_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors9IndirectEO* [[ENUM_PTR]] to i32 +// CHECK-NEXT: [[NEXT_ELT_LOC:%.*]] = add i32 [[ENUM_PTR_INT]], 4 +// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i32 [[NEXT_ELT_LOC]] to i8* +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset +// CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset +// CHECK-NEXT: [[INT_PTR:%.*]] = bitcast i8* %elt_offset1 to %TSi* +// CHECK-NEXT: %._value = getelementptr inbounds %TSi, %TSi* [[INT_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[NATIVE_INT_VAL:%.*]] = load i32, i32* %._value + +/// Call distributed thunk with extracted arguments. + +// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, i32, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8i32p0s_swift.errorss({{.*}}, %swift.context* {{.*}}, i32 [[NATIVE_ENUM_VAL]], i32 [[NATIVE_INT_VAL]], %T27distributed_actor_accessors7MyActorC* {{.*}}) +// CHECK-NEXT: [[TASK_REF:%.*]] = extractvalue { i8*, i32, %swift.error* } [[THUNK_RESULT]], 0 +// CHECK-NEXT: {{.*}} = call i8* @__swift_async_resume_project_context(i8* [[TASK_REF]]) +// CHECK: [[ENUM_RESULT:%.*]] = extractvalue { i8*, i32, %swift.error* } [[THUNK_RESULT]], 1 +// CHECK: [[NATIVE_RESULT_PTR:%.*]] = bitcast %T27distributed_actor_accessors9IndirectEO* [[TYPED_RESULT_BUFF]] to i32* +// CHECK-NEXT: store i32 [[ENUM_RESULT]], i32* [[NATIVE_RESULT_PTR]] + +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// ---> Thunk and distributed method for `complex` + +// CHECK: define hidden swifttailcc void @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTE" + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors7MyActorC7complexyAA11LargeStructVSaySiG_AA3ObjCSSSgAFtFTETF"(%swift.context* swiftasync {{.*}}, i8* [[ARG_BUFF:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) + +/// First, let's check that all of the different argument types here are loaded correctly. + +/// Cast result buffer to the expected result type (in this case its indirect opaque pointer) +// CHECK: [[TYPED_RESULT_BUFF:%.*]] = bitcast i8* [[RESULT_BUFF]] to %swift.opaque* + +/// -> [Int] + +// CHECK: %elt_offset = load i8*, i8** %offset +// CHECK-NEXT: [[ARR_PTR:%.*]] = bitcast i8* %elt_offset to %TSa* +// CHECK-NEXT: %._buffer = getelementptr inbounds %TSa, %TSa* [[ARR_PTR]], i32 0, i32 0 +// CHECK: [[NATIVE_ARR_VAL:%.*]] = load [[ARR_STORAGE_TYPE:%.*]], [[ARR_STORAGE_TYPE]]* %._buffer._storage +// CHECK: [[ARR_PTR_INT:%.*]] = ptrtoint %TSa* [[ARR_PTR]] to i32 +// CHECK-NEXT: [[NEXT_ELT:%.*]] = add i32 [[ARR_PTR_INT]], 4 +// CHECK-NEXT: [[OPAQUE_NEXT_ELT:%.*]] = inttoptr i32 [[NEXT_ELT]] to i8* +// CHECK-NEXT: store i8* [[OPAQUE_NEXT_ELT]], i8** %offset + +/// -> Obj + +// CHECK-NEXT: %elt_offset1 = load i8*, i8** %offset +// CHECK-NEXT: [[OBJ_PTR:%.*]] = bitcast i8* %elt_offset1 to %T27distributed_actor_accessors3ObjC** +// CHECK-NEXT: [[NATIVE_OBJ_VAL:%.*]] = load %T27distributed_actor_accessors3ObjC*, %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]] +// CHECK: [[OBJ_PTR_INT:%.*]] = ptrtoint %T27distributed_actor_accessors3ObjC** [[OBJ_PTR]] to i32 +// CHECK-NEXT: [[NEXT_ELT:%.*]] = add i32 [[OBJ_PTR_INT]], 4 +// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i32 [[NEXT_ELT]] to i8* +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset + +/// -> String? + +// CHECK-NEXT: %elt_offset2 = load i8*, i8** %offset +// CHECK-NEXT: [[OPT_PTR:%.*]] = bitcast i8* %elt_offset2 to %TSSSg* +// CHECK-NEXT: [[NATIVE_OPT_PTR:%.*]] = bitcast %TSSSg* [[OPT_PTR]] to { i32, i32, i32 }* +// CHECK-NEXT: [[NATIVE_OPT_VAL_0_PTR:%.*]] = getelementptr inbounds { i32, i32, i32 }, { i32, i32, i32 }* [[NATIVE_OPT_PTR]], i32 0, i32 0 +// CHECK-NEXT: [[NATIVE_OPT_VAL_0:%.*]] = load i32, i32* [[NATIVE_OPT_VAL_0_PTR]] +// CHECK-NEXT: [[NATIVE_OPT_VAL_1_PTR:%.*]] = getelementptr inbounds { i32, i32, i32 }, { i32, i32, i32 }* [[NATIVE_OPT_PTR]], i32 0, i32 1 +// CHECK-NEXT: [[NATIVE_OPT_VAL_1:%.*]] = load i32, i32* [[NATIVE_OPT_VAL_1_PTR]] +// CHECK-NEXT: [[NATIVE_OPT_VAL_2_PTR:%.*]] = getelementptr inbounds { i32, i32, i32 }, { i32, i32, i32 }* [[NATIVE_OPT_PTR]], i32 0, i32 2 +// CHECK-NEXT: [[NATIVE_OPT_VAL_2:%.*]] = load i32, i32* [[NATIVE_OPT_VAL_2_PTR]] +// CHECK-NEXT: [[OPT_PTR_INT:%.*]] = ptrtoint %TSSSg* [[OPT_PTR]] to i32 +// CHECK-NEXT: [[NEXT_ELT:%.*]] = add i32 [[OPT_PTR_INT]], 12 +// CHECK-NEXT: [[NEXT_ELT_PTR:%.*]] = inttoptr i32 [[NEXT_ELT]] to i8* +// CHECK-NEXT: store i8* [[NEXT_ELT_PTR]], i8** %offset + +/// -> LargeStruct (passed indirectly) + +// CHECK-NEXT: %elt_offset3 = load i8*, i8** %offset +// CHECK-NEXT: [[STRUCT_PTR:%.*]] = bitcast i8* %elt_offset3 to %T27distributed_actor_accessors11LargeStructV* +// CHECK-NEXT: [[STRUCT_PTR_VAL:%.*]] = ptrtoint %T27distributed_actor_accessors11LargeStructV* [[STRUCT_PTR]] to i32 +// CHECK-NEXT: [[STRUCT_PTR_VAL_ADJ_1:%.*]] = add nuw i32 [[STRUCT_PTR_VAL]], 7 +// CHECK-NEXT: [[STRUCT_PTR_VAL_ADJ_2:%.*]] = and i32 [[STRUCT_PTR_VAL_ADJ_1]], -8 +// CHECK-NEXT: [[STRUCT_PTR:%.*]] = inttoptr i32 [[STRUCT_PTR_VAL_ADJ_2]] to %T27distributed_actor_accessors11LargeStructV* + + +// CHECK: [[INDIRECT_RESULT_BUFF:%.*]] = bitcast %swift.opaque* [[TYPED_RESULT_BUFF]] to %T27distributed_actor_accessors11LargeStructV* + +/// Now let's make sure that distributed thunk call uses the arguments correctly + +// CHECK: [[THUNK_RESULT:%.*]] = call { i8*, %swift.error* } (i32, i8*, i8*, ...) @llvm.coro.suspend.async.sl_p0i8p0s_swift.errorss({{.*}}, %T27distributed_actor_accessors11LargeStructV* [[INDIRECT_RESULT_BUFF]], %swift.context* {{.*}}, {{.*}} [[NATIVE_ARR_VAL]], %T27distributed_actor_accessors3ObjC* [[NATIVE_OBJ_VAL]], i32 [[NATIVE_OPT_VAL_0]], i32 [[NATIVE_OPT_VAL_1]], i32 [[NATIVE_OPT_VAL_2]], %T27distributed_actor_accessors11LargeStructV* [[STRUCT_PTR]], %T27distributed_actor_accessors7MyActorC* {{.*}}) + +/// RESULT is returned indirectly so there is nothing to pass to `end` + +// CHECK: {{.*}} = call i1 (i8*, i1, ...) @llvm.coro.end.async({{.*}}, %swift.context* {{.*}}, %swift.error* {{.*}}) + +/// ---> Thunk and distributed method for `MyOtherActor.empty` + +/// Let's check that there is no offset allocation here since parameter list is empty + +// CHECK: define internal swifttailcc void @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETF"(%swift.context* swiftasync {{.*}}, i8* [[ARG_BUFF:%.*]], i8* [[RESULT_BUFF:%.*]], %swift.refcounted* swiftself {{.*}}) +// CHECK-NEXT: entry: +// CHECK-NEXT: {{.*}} = alloca %swift.context* +// CHECK-NEXT: %swifterror = alloca %swift.error* +// CHECK-NEXT: {{.*}} = call token @llvm.coro.id.async(i32 12, i32 16, i32 0, i8* bitcast (%swift.async_func_pointer* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTETFTu" to i8*)) +// CHECK-NEXT: {{.*}} = call i8* @llvm.coro.begin(token {{%.*}}, i8* null) +// CHECK-NEXT: store %swift.context* {{.*}}, %swift.context** {{.*}} +// CHECK-NEXT: store %swift.error* null, %swift.error** %swifterror +// CHECK-NEXT: {{.*}} = bitcast i8* [[RESULT_BUFF]] to %swift.opaque* +// CHECK-NEXT: {{.*}} = load i32, i32* getelementptr inbounds (%swift.async_func_pointer, %swift.async_func_pointer* bitcast (void (%swift.context*, %T27distributed_actor_accessors12MyOtherActorC*)* @"$s27distributed_actor_accessors12MyOtherActorC5emptyyyFTE" to %swift.async_func_pointer*), i32 0, i32 0) diff --git a/test/Distributed/distributed_actor_accessor_thunks.swift b/test/Distributed/distributed_actor_accessor_thunks_64bit.swift similarity index 99% rename from test/Distributed/distributed_actor_accessor_thunks.swift rename to test/Distributed/distributed_actor_accessor_thunks_64bit.swift index c194fc53d9fed..94693a66d3d49 100644 --- a/test/Distributed/distributed_actor_accessor_thunks.swift +++ b/test/Distributed/distributed_actor_accessor_thunks_64bit.swift @@ -6,6 +6,8 @@ // REQUIRES: concurrency // REQUIRES: distributed +// REQUIRES: CPU=x86_64 + import _Distributed import FakeDistributedActorSystems From d6d9b551fa688be50fd43f8f3d8cb12ec70849d0 Mon Sep 17 00:00:00 2001 From: Pavel Yaskevich Date: Fri, 17 Dec 2021 10:34:51 -0800 Subject: [PATCH 38/38] [Distributed] Temporary disable accessor tests on Windows I don't have access to Windows machine so there is no way for me to debug and fix them. --- test/Distributed/distributed_actor_accessor_section_coff.swift | 2 ++ test/Distributed/distributed_actor_accessor_thunks_32bit.swift | 2 ++ test/Distributed/distributed_actor_accessor_thunks_64bit.swift | 2 ++ 3 files changed, 6 insertions(+) diff --git a/test/Distributed/distributed_actor_accessor_section_coff.swift b/test/Distributed/distributed_actor_accessor_section_coff.swift index 8bd93bea18b80..6306b5f47633d 100644 --- a/test/Distributed/distributed_actor_accessor_section_coff.swift +++ b/test/Distributed/distributed_actor_accessor_section_coff.swift @@ -7,6 +7,8 @@ // REQUIRES: distributed // REQUIRES: OS=windows-msvc +// FIXME: Test is temporary disabled (no way to debug) +// REQUIRES: fix import _Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/distributed_actor_accessor_thunks_32bit.swift b/test/Distributed/distributed_actor_accessor_thunks_32bit.swift index a302fce0d2ab7..c37f1d63498c9 100644 --- a/test/Distributed/distributed_actor_accessor_thunks_32bit.swift +++ b/test/Distributed/distributed_actor_accessor_thunks_32bit.swift @@ -8,6 +8,8 @@ // REQUIRES: CPU=i386 +// UNSUPPORTED: OS=windows-msvc + import _Distributed import FakeDistributedActorSystems diff --git a/test/Distributed/distributed_actor_accessor_thunks_64bit.swift b/test/Distributed/distributed_actor_accessor_thunks_64bit.swift index 94693a66d3d49..105e0fd91dcf7 100644 --- a/test/Distributed/distributed_actor_accessor_thunks_64bit.swift +++ b/test/Distributed/distributed_actor_accessor_thunks_64bit.swift @@ -8,6 +8,8 @@ // REQUIRES: CPU=x86_64 +// UNSUPPORTED: OS=windows-msvc + import _Distributed import FakeDistributedActorSystems