2020#include " swift/AST/ASTContext.h"
2121#include " swift/AST/GenericEnvironment.h"
2222#include " swift/Runtime/Config.h"
23+ #include " swift/SIL/SILModule.h"
2324#include " swift/SIL/SILType.h"
2425#include " clang/AST/ASTContext.h"
2526#include " clang/AST/RecordLayout.h"
@@ -121,17 +122,52 @@ AsyncContextLayout irgen::getAsyncContextLayout(
121122 indirectReturnInfos.push_back (indirectResult);
122123 }
123124
125+ // ResultTypes directResults...;
126+ auto directResults = fnConv.getDirectSILResults ();
127+ for (auto result : directResults) {
128+ auto ty =
129+ fnConv.getSILType (result, IGF.IGM .getMaximalTypeExpansionContext ());
130+ auto &ti = IGF.getTypeInfoForLowered (ty.getASTType ());
131+ valTypes.push_back (ty);
132+ typeInfos.push_back (&ti);
133+ directReturnInfos.push_back (result);
134+ }
135+
124136 // SelfType self?;
125137 bool hasLocalContextParameter = hasSelfContextParameter (substitutedType);
126138 bool canHaveValidError = substitutedType->hasErrorResult ();
127- bool hasLocalContext = (hasLocalContextParameter || canHaveValidError ||
128- substitutedType->getRepresentation () ==
129- SILFunctionTypeRepresentation::Thick);
139+ bool hasLocalContext = (hasLocalContextParameter || canHaveValidError);
130140 SILParameterInfo localContextParameter =
131141 hasLocalContextParameter ? parameters.back () : SILParameterInfo ();
132142 if (hasLocalContextParameter) {
133143 parameters = parameters.drop_back ();
134144 }
145+
146+ // ArgTypes formalArguments...;
147+ for (auto parameter : parameters) {
148+ SILType ty = IGF.IGM .silConv .getSILType (
149+ parameter, substitutedType, IGF.IGM .getMaximalTypeExpansionContext ());
150+
151+ auto argumentLoweringType =
152+ getArgumentLoweringType (ty.getASTType (), parameter,
153+ /* isNoEscape*/ true );
154+
155+ auto &ti = IGF.getTypeInfoForLowered (argumentLoweringType);
156+
157+ valTypes.push_back (ty);
158+ typeInfos.push_back (&ti);
159+ paramInfos.push_back ({ty, parameter.getConvention ()});
160+ }
161+ auto bindings = NecessaryBindings::forAsyncFunctionInvocation (
162+ IGF.IGM , originalType, substitutionMap);
163+ if (!bindings.empty ()) {
164+ auto bindingsSize = bindings.getBufferSize (IGF.IGM );
165+ auto &bindingsTI = IGF.IGM .getOpaqueStorageTypeInfo (
166+ bindingsSize, IGF.IGM .getPointerAlignment ());
167+ valTypes.push_back (SILType ());
168+ typeInfos.push_back (&bindingsTI);
169+ }
170+
135171 Optional<AsyncContextLayout::ArgumentInfo> localContextInfo = llvm::None;
136172 if (hasLocalContext) {
137173 if (hasLocalContextParameter) {
@@ -156,30 +192,6 @@ AsyncContextLayout irgen::getAsyncContextLayout(
156192 }
157193 }
158194
159- // ArgTypes formalArguments...;
160- auto bindings = NecessaryBindings::forAsyncFunctionInvocation (
161- IGF.IGM , originalType, substitutionMap);
162- if (!bindings.empty ()) {
163- auto bindingsSize = bindings.getBufferSize (IGF.IGM );
164- auto &bindingsTI = IGF.IGM .getOpaqueStorageTypeInfo (
165- bindingsSize, IGF.IGM .getPointerAlignment ());
166- valTypes.push_back (SILType ());
167- typeInfos.push_back (&bindingsTI);
168- }
169- for (auto parameter : parameters) {
170- SILType ty = IGF.IGM .silConv .getSILType (
171- parameter, substitutedType, IGF.IGM .getMaximalTypeExpansionContext ());
172-
173- auto argumentLoweringType =
174- getArgumentLoweringType (ty.getASTType (), parameter,
175- /* isNoEscape*/ true );
176-
177- auto &ti = IGF.getTypeInfoForLowered (argumentLoweringType);
178-
179- valTypes.push_back (ty);
180- typeInfos.push_back (&ti);
181- paramInfos.push_back ({ty, parameter.getConvention ()});
182- }
183195
184196 Optional<AsyncContextLayout::TrailingWitnessInfo> trailingWitnessInfo;
185197 if (originalType->getRepresentation () ==
@@ -203,17 +215,6 @@ AsyncContextLayout irgen::getAsyncContextLayout(
203215 trailingWitnessInfo = AsyncContextLayout::TrailingWitnessInfo ();
204216 }
205217
206- // ResultTypes directResults...;
207- auto directResults = fnConv.getDirectSILResults ();
208- for (auto result : directResults) {
209- auto ty =
210- fnConv.getSILType (result, IGF.IGM .getMaximalTypeExpansionContext ());
211- auto &ti = IGF.getTypeInfoForLowered (ty.getASTType ());
212- valTypes.push_back (ty);
213- typeInfos.push_back (&ti);
214- directReturnInfos.push_back (result);
215- }
216-
217218 return AsyncContextLayout (
218219 IGF.IGM , LayoutStrategy::Optimal, valTypes, typeInfos, IGF, originalType,
219220 substitutedType, substitutionMap, std::move (bindings),
@@ -692,6 +693,10 @@ void SignatureExpansion::addAsyncParameters() {
692693 ParamIRTypes.push_back (IGM.SwiftContextPtrTy );
693694 // TODO: Add actor.
694695 // TODO: Add task.
696+ if (FnType->getRepresentation () == SILFunctionTypeRepresentation::Thick) {
697+ IGM.addSwiftSelfAttributes (Attrs, ParamIRTypes.size ());
698+ ParamIRTypes.push_back (IGM.RefCountedPtrTy );
699+ }
695700}
696701
697702void SignatureExpansion::addCoroutineContextParameter () {
@@ -1748,6 +1753,116 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
17481753 Explosion &in, Explosion &out,
17491754 TemporarySet &temporaries, bool isOutlined);
17501755
1756+ llvm::Value *irgen::getDynamicAsyncContextSize (IRGenFunction &IGF,
1757+ AsyncContextLayout layout,
1758+ CanSILFunctionType functionType,
1759+ llvm::Value *thickContext) {
1760+ switch (functionType->getRepresentation ()) {
1761+ case SILFunctionTypeRepresentation::Thick: {
1762+ // If the called function is thick, the size of the called function's
1763+ // async context may not be statically knowable.
1764+ //
1765+ // Specifically, if the thick function was produced by a partial_apply,
1766+ // the function which was originally partially applied determines the
1767+ // size of the needed async context. That original function isn't known
1768+ // statically. The dynamic size is available within the context as an
1769+ // i32 at the first index: <{ %swift.refcounted*, /*size*/ i32, ... }>.
1770+ //
1771+ // On the other hand, if the thick function was produced by a
1772+ // thin_to_thick_function, then the context will be nullptr. In that
1773+ // case, the size of the needed async context is known statically to
1774+ // be the size dictated by the function signature.
1775+ //
1776+ // We are currently emitting into some basic block. To handle these two
1777+ // cases, we need to branch based on whether the context is nullptr; each
1778+ // branch must then determine the size in the manner appropriate to it.
1779+ // Finally, both blocks must join back together to make the call:
1780+ //
1781+ // SIL: IR:
1782+ // +-----+ +-------------------------+
1783+ // |.....| |%cond = %ctx == nullptr |
1784+ // |apply| |br %cond, static, dynamic|
1785+ // |.....| +--------/--------------\-+
1786+ // +-----+ / \
1787+ // +-static-------+ +-dynamic----------------------------------------------+
1788+ // |%size = K | |%layout = bitcast %context to <{%swift.context*, i32}>|
1789+ // |br join(%size)| |%size_addr = getelementptr %layout, i32 1, i32 0 |
1790+ // +-----\--------+ |%size = load %size_addr |
1791+ // \ |br join(%size) |
1792+ // \ +------------------------------------------------------+
1793+ // \ /
1794+ // +-join(%size)-----------------------------------------------------------+
1795+ // |%dataAddr = swift_taskAlloc(%task, %size) |
1796+ // |%async_context = bitcast %dataAddr to ASYNC_CONTEXT(static_callee_type)|
1797+ // |... // populate the fields %context with arguments |
1798+ // |call %callee(%async_context, %context) |
1799+ // +-----------------------------------------------------------------------+
1800+ auto *staticSizeBlock = llvm::BasicBlock::Create (IGF.IGM .getLLVMContext ());
1801+ auto *dynamicSizeBlock = llvm::BasicBlock::Create (IGF.IGM .getLLVMContext ());
1802+ auto *joinBlock = llvm::BasicBlock::Create (IGF.IGM .getLLVMContext ());
1803+
1804+ auto hasThickContext =
1805+ IGF.Builder .CreateICmpNE (thickContext, IGF.IGM .RefCountedNull );
1806+ IGF.Builder .CreateCondBr (hasThickContext, dynamicSizeBlock,
1807+ staticSizeBlock);
1808+
1809+ SmallVector<std::pair<llvm::BasicBlock *, llvm::Value *>, 2 > phiValues;
1810+ {
1811+ IGF.Builder .emitBlock (staticSizeBlock);
1812+ auto size = getAsyncContextSize (layout);
1813+ auto *sizeValue =
1814+ llvm::ConstantInt::get (IGF.IGM .Int32Ty , size.getValue ());
1815+ phiValues.push_back ({staticSizeBlock, sizeValue});
1816+ IGF.Builder .CreateBr (joinBlock);
1817+ }
1818+
1819+ {
1820+ IGF.Builder .emitBlock (dynamicSizeBlock);
1821+ SmallVector<const TypeInfo *, 4 > argTypeInfos;
1822+ SmallVector<SILType, 4 > argValTypes;
1823+ auto int32ASTType =
1824+ BuiltinIntegerType::get (32 , IGF.IGM .IRGen .SIL .getASTContext ())
1825+ ->getCanonicalType ();
1826+ auto int32SILType = SILType::getPrimitiveObjectType (int32ASTType);
1827+ const TypeInfo &int32TI = IGF.IGM .getTypeInfo (int32SILType);
1828+ argValTypes.push_back (int32SILType);
1829+ argTypeInfos.push_back (&int32TI);
1830+ HeapLayout layout (IGF.IGM , LayoutStrategy::Optimal, argValTypes,
1831+ argTypeInfos,
1832+ /* typeToFill*/ nullptr , NecessaryBindings ());
1833+ auto castThickContext =
1834+ layout.emitCastTo (IGF, thickContext, " context.prefix" );
1835+ auto sizeLayout = layout.getElement (0 );
1836+ auto sizeAddr = sizeLayout.project (IGF, castThickContext,
1837+ /* NonFixedOffsets*/ llvm::None);
1838+ auto *sizeValue = IGF.Builder .CreateLoad (sizeAddr);
1839+ phiValues.push_back ({dynamicSizeBlock, sizeValue});
1840+ IGF.Builder .CreateBr (joinBlock);
1841+ }
1842+
1843+ {
1844+ IGF.Builder .emitBlock (joinBlock);
1845+ auto *phi = IGF.Builder .CreatePHI (IGF.IGM .Int32Ty , phiValues.size ());
1846+ for (auto &entry : phiValues) {
1847+ phi->addIncoming (entry.second , entry.first );
1848+ }
1849+ return phi;
1850+ }
1851+ }
1852+ case SILFunctionTypeRepresentation::Thin:
1853+ case SILFunctionTypeRepresentation::CFunctionPointer:
1854+ case SILFunctionTypeRepresentation::Method:
1855+ case SILFunctionTypeRepresentation::ObjCMethod:
1856+ case SILFunctionTypeRepresentation::WitnessMethod:
1857+ case SILFunctionTypeRepresentation::Closure:
1858+ case SILFunctionTypeRepresentation::Block: {
1859+ auto size = getAsyncContextSize (layout);
1860+ auto *sizeValue = llvm::ConstantInt::get (IGF.IGM .Int32Ty , size.getValue ());
1861+ return sizeValue;
1862+ }
1863+ }
1864+ }
1865+
17511866namespace {
17521867
17531868class SyncCallEmission final : public CallEmission {
@@ -1958,6 +2073,7 @@ class AsyncCallEmission final : public CallEmission {
19582073 Address contextBuffer;
19592074 Size contextSize;
19602075 Address context;
2076+ llvm::Value *thickContext = nullptr ;
19612077
19622078 AsyncContextLayout getAsyncContextLayout () {
19632079 return ::getAsyncContextLayout (IGF, getCallee ().getOrigFunctionType (),
@@ -1972,8 +2088,8 @@ class AsyncCallEmission final : public CallEmission {
19722088 }
19732089 void loadValue (ElementLayout layout, Explosion &explosion) {
19742090 Address addr = layout.project (IGF, context, /* offsets*/ llvm::None);
1975- auto &ti = layout.getType ();
1976- cast<LoadableTypeInfo>(ti) .loadAsTake (IGF, addr, explosion);
2091+ auto &ti = cast<LoadableTypeInfo>( layout.getType () );
2092+ ti .loadAsTake (IGF, addr, explosion);
19772093 }
19782094
19792095public:
@@ -1986,9 +2102,14 @@ class AsyncCallEmission final : public CallEmission {
19862102 super::begin ();
19872103 assert (!contextBuffer.isValid ());
19882104 assert (!context.isValid ());
1989- // Allocate space for the async arguments.
19902105 auto layout = getAsyncContextLayout ();
1991- std::tie (contextBuffer, contextSize) = emitAllocAsyncContext (IGF, layout);
2106+ // Allocate space for the async arguments.
2107+ auto *dynamicContextSize32 = getDynamicAsyncContextSize (
2108+ IGF, layout, CurCallee.getOrigFunctionType (), thickContext);
2109+ auto *dynamicContextSize =
2110+ IGF.Builder .CreateZExt (dynamicContextSize32, IGF.IGM .SizeTy );
2111+ std::tie (contextBuffer, contextSize) = emitAllocAsyncContext (
2112+ IGF, layout, dynamicContextSize, getAsyncContextSize (layout));
19922113 context = layout.emitCastTo (IGF, contextBuffer.getAddress ());
19932114 if (layout.canHaveError ()) {
19942115 auto fieldLayout = layout.getErrorLayout ();
@@ -2004,22 +2125,26 @@ class AsyncCallEmission final : public CallEmission {
20042125 emitDeallocAsyncContext (IGF, contextBuffer, contextSize);
20052126 super::end ();
20062127 }
2007- void setFromCallee () override { super::setFromCallee (); }
2128+ void setFromCallee () override {
2129+ super::setFromCallee ();
2130+ thickContext = CurCallee.getSwiftContext ();
2131+ }
20082132 SILType getParameterType (unsigned index) override {
20092133 return getAsyncContextLayout ().getParameterType (index);
20102134 }
20112135 void setArgs (Explosion &llArgs, bool isOutlined,
20122136 WitnessMetadata *witnessMetadata) override {
20132137 Explosion asyncExplosion;
20142138 asyncExplosion.add (contextBuffer.getAddress ());
2139+ if (getCallee ().getRepresentation () ==
2140+ SILFunctionTypeRepresentation::Thick) {
2141+ asyncExplosion.add (getCallee ().getSwiftContext ());
2142+ }
20152143 super::setArgs (asyncExplosion, false , witnessMetadata);
20162144 SILFunctionConventions fnConv (getCallee ().getSubstFunctionType (),
20172145 IGF.getSILModule ());
20182146
20192147 // Move all the arguments into the context.
2020- if (selfValue) {
2021- llArgs.add (selfValue);
2022- }
20232148 auto layout = getAsyncContextLayout ();
20242149 for (unsigned index = 0 , count = layout.getIndirectReturnCount ();
20252150 index < count; ++index) {
@@ -2037,8 +2162,10 @@ class AsyncCallEmission final : public CallEmission {
20372162 layout.getBindings ().save (IGF, bindingsAddr, llArgs);
20382163 }
20392164 if (selfValue) {
2165+ Explosion selfExplosion;
2166+ selfExplosion.add (selfValue);
20402167 auto fieldLayout = layout.getLocalContextLayout ();
2041- saveValue (fieldLayout, llArgs , isOutlined);
2168+ saveValue (fieldLayout, selfExplosion , isOutlined);
20422169 }
20432170 }
20442171 void emitCallToUnmappedExplosion (llvm::CallInst *call, Explosion &out) override {
@@ -3213,14 +3340,21 @@ void irgen::emitTaskDealloc(IRGenFunction &IGF, Address address,
32133340 llvm::Attribute::ReadNone);
32143341}
32153342
3343+ std::pair<Address, Size> irgen::emitAllocAsyncContext (IRGenFunction &IGF,
3344+ AsyncContextLayout layout,
3345+ llvm::Value *sizeValue,
3346+ Size sizeLowerBound) {
3347+ auto alignment = getAsyncContextAlignment (IGF.IGM );
3348+ auto address = emitTaskAlloc (IGF, sizeValue, alignment);
3349+ IGF.Builder .CreateLifetimeStart (address, sizeLowerBound);
3350+ return {address, sizeLowerBound};
3351+ }
3352+
32163353std::pair<Address, Size>
32173354irgen::emitAllocAsyncContext (IRGenFunction &IGF, AsyncContextLayout layout) {
32183355 auto size = getAsyncContextSize (layout);
32193356 auto *sizeValue = llvm::ConstantInt::get (IGF.IGM .SizeTy , size.getValue ());
3220- auto alignment = getAsyncContextAlignment (IGF.IGM );
3221- auto address = emitTaskAlloc (IGF, sizeValue, alignment);
3222- IGF.Builder .CreateLifetimeStart (address, size);
3223- return {address, size};
3357+ return emitAllocAsyncContext (IGF, layout, sizeValue, size);
32243358}
32253359
32263360void irgen::emitDeallocAsyncContext (IRGenFunction &IGF, Address context,
0 commit comments