20
20
#include " swift/AST/ASTContext.h"
21
21
#include " swift/AST/GenericEnvironment.h"
22
22
#include " swift/Runtime/Config.h"
23
+ #include " swift/SIL/SILModule.h"
23
24
#include " swift/SIL/SILType.h"
24
25
#include " clang/AST/ASTContext.h"
25
26
#include " clang/AST/RecordLayout.h"
@@ -121,17 +122,52 @@ AsyncContextLayout irgen::getAsyncContextLayout(
121
122
indirectReturnInfos.push_back (indirectResult);
122
123
}
123
124
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
+
124
136
// SelfType self?;
125
137
bool hasLocalContextParameter = hasSelfContextParameter (substitutedType);
126
138
bool canHaveValidError = substitutedType->hasErrorResult ();
127
- bool hasLocalContext = (hasLocalContextParameter || canHaveValidError ||
128
- substitutedType->getRepresentation () ==
129
- SILFunctionTypeRepresentation::Thick);
139
+ bool hasLocalContext = (hasLocalContextParameter || canHaveValidError);
130
140
SILParameterInfo localContextParameter =
131
141
hasLocalContextParameter ? parameters.back () : SILParameterInfo ();
132
142
if (hasLocalContextParameter) {
133
143
parameters = parameters.drop_back ();
134
144
}
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
+
135
171
Optional<AsyncContextLayout::ArgumentInfo> localContextInfo = llvm::None;
136
172
if (hasLocalContext) {
137
173
if (hasLocalContextParameter) {
@@ -156,30 +192,6 @@ AsyncContextLayout irgen::getAsyncContextLayout(
156
192
}
157
193
}
158
194
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
- }
183
195
184
196
Optional<AsyncContextLayout::TrailingWitnessInfo> trailingWitnessInfo;
185
197
if (originalType->getRepresentation () ==
@@ -203,17 +215,6 @@ AsyncContextLayout irgen::getAsyncContextLayout(
203
215
trailingWitnessInfo = AsyncContextLayout::TrailingWitnessInfo ();
204
216
}
205
217
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
-
217
218
return AsyncContextLayout (
218
219
IGF.IGM , LayoutStrategy::Optimal, valTypes, typeInfos, IGF, originalType,
219
220
substitutedType, substitutionMap, std::move (bindings),
@@ -692,6 +693,10 @@ void SignatureExpansion::addAsyncParameters() {
692
693
ParamIRTypes.push_back (IGM.SwiftContextPtrTy );
693
694
// TODO: Add actor.
694
695
// TODO: Add task.
696
+ if (FnType->getRepresentation () == SILFunctionTypeRepresentation::Thick) {
697
+ IGM.addSwiftSelfAttributes (Attrs, ParamIRTypes.size ());
698
+ ParamIRTypes.push_back (IGM.RefCountedPtrTy );
699
+ }
695
700
}
696
701
697
702
void SignatureExpansion::addCoroutineContextParameter () {
@@ -1748,6 +1753,116 @@ static void externalizeArguments(IRGenFunction &IGF, const Callee &callee,
1748
1753
Explosion &in, Explosion &out,
1749
1754
TemporarySet &temporaries, bool isOutlined);
1750
1755
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
+
1751
1866
namespace {
1752
1867
1753
1868
class SyncCallEmission final : public CallEmission {
@@ -1958,6 +2073,7 @@ class AsyncCallEmission final : public CallEmission {
1958
2073
Address contextBuffer;
1959
2074
Size contextSize;
1960
2075
Address context;
2076
+ llvm::Value *thickContext = nullptr ;
1961
2077
1962
2078
AsyncContextLayout getAsyncContextLayout () {
1963
2079
return ::getAsyncContextLayout (IGF, getCallee ().getOrigFunctionType (),
@@ -1972,8 +2088,8 @@ class AsyncCallEmission final : public CallEmission {
1972
2088
}
1973
2089
void loadValue (ElementLayout layout, Explosion &explosion) {
1974
2090
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);
1977
2093
}
1978
2094
1979
2095
public:
@@ -1986,9 +2102,14 @@ class AsyncCallEmission final : public CallEmission {
1986
2102
super::begin ();
1987
2103
assert (!contextBuffer.isValid ());
1988
2104
assert (!context.isValid ());
1989
- // Allocate space for the async arguments.
1990
2105
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));
1992
2113
context = layout.emitCastTo (IGF, contextBuffer.getAddress ());
1993
2114
if (layout.canHaveError ()) {
1994
2115
auto fieldLayout = layout.getErrorLayout ();
@@ -2004,22 +2125,26 @@ class AsyncCallEmission final : public CallEmission {
2004
2125
emitDeallocAsyncContext (IGF, contextBuffer, contextSize);
2005
2126
super::end ();
2006
2127
}
2007
- void setFromCallee () override { super::setFromCallee (); }
2128
+ void setFromCallee () override {
2129
+ super::setFromCallee ();
2130
+ thickContext = CurCallee.getSwiftContext ();
2131
+ }
2008
2132
SILType getParameterType (unsigned index) override {
2009
2133
return getAsyncContextLayout ().getParameterType (index);
2010
2134
}
2011
2135
void setArgs (Explosion &llArgs, bool isOutlined,
2012
2136
WitnessMetadata *witnessMetadata) override {
2013
2137
Explosion asyncExplosion;
2014
2138
asyncExplosion.add (contextBuffer.getAddress ());
2139
+ if (getCallee ().getRepresentation () ==
2140
+ SILFunctionTypeRepresentation::Thick) {
2141
+ asyncExplosion.add (getCallee ().getSwiftContext ());
2142
+ }
2015
2143
super::setArgs (asyncExplosion, false , witnessMetadata);
2016
2144
SILFunctionConventions fnConv (getCallee ().getSubstFunctionType (),
2017
2145
IGF.getSILModule ());
2018
2146
2019
2147
// Move all the arguments into the context.
2020
- if (selfValue) {
2021
- llArgs.add (selfValue);
2022
- }
2023
2148
auto layout = getAsyncContextLayout ();
2024
2149
for (unsigned index = 0 , count = layout.getIndirectReturnCount ();
2025
2150
index < count; ++index) {
@@ -2037,8 +2162,10 @@ class AsyncCallEmission final : public CallEmission {
2037
2162
layout.getBindings ().save (IGF, bindingsAddr, llArgs);
2038
2163
}
2039
2164
if (selfValue) {
2165
+ Explosion selfExplosion;
2166
+ selfExplosion.add (selfValue);
2040
2167
auto fieldLayout = layout.getLocalContextLayout ();
2041
- saveValue (fieldLayout, llArgs , isOutlined);
2168
+ saveValue (fieldLayout, selfExplosion , isOutlined);
2042
2169
}
2043
2170
}
2044
2171
void emitCallToUnmappedExplosion (llvm::CallInst *call, Explosion &out) override {
@@ -3213,14 +3340,21 @@ void irgen::emitTaskDealloc(IRGenFunction &IGF, Address address,
3213
3340
llvm::Attribute::ReadNone);
3214
3341
}
3215
3342
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
+
3216
3353
std::pair<Address, Size>
3217
3354
irgen::emitAllocAsyncContext (IRGenFunction &IGF, AsyncContextLayout layout) {
3218
3355
auto size = getAsyncContextSize (layout);
3219
3356
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);
3224
3358
}
3225
3359
3226
3360
void irgen::emitDeallocAsyncContext (IRGenFunction &IGF, Address context,
0 commit comments