Skip to content

Commit 64ec60b

Browse files
authored
Merge pull request swiftlang#34370 from nate-chandler/concurrency/irgen/partial-apply
2 parents 785b182 + 506473d commit 64ec60b

21 files changed

+2449
-223
lines changed

lib/IRGen/Explosion.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,6 @@ class Explosion {
152152
return Values[NextValue-1];
153153
}
154154

155-
llvm::Value *peek(unsigned n) {
156-
assert(n < Values.size());
157-
return Values[n];
158-
}
159-
160155
/// Claim and remove the last item in the array.
161156
/// Unlike the normal 'claim' methods, the item is gone forever.
162157
llvm::Value *takeLast() {

lib/IRGen/GenCall.cpp

Lines changed: 185 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
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

697702
void 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+
17511866
namespace {
17521867

17531868
class 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

19792095
public:
@@ -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+
32163353
std::pair<Address, Size>
32173354
irgen::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

32263360
void irgen::emitDeallocAsyncContext(IRGenFunction &IGF, Address context,

0 commit comments

Comments
 (0)