Skip to content

[Async CC] Support for protocol witness methods. #34211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 64 additions & 49 deletions lib/IRGen/GenCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,11 @@ AsyncContextLayout irgen::getAsyncContextLayout(
SILType ty =
IGF.IGM.silConv.getSILType(localContextParameter, substitutedType,
IGF.IGM.getMaximalTypeExpansionContext());
auto &ti = IGF.getTypeInfoForLowered(ty.getASTType());
auto argumentLoweringType =
getArgumentLoweringType(ty.getASTType(), localContextParameter,
/*isNoEscape*/ true);

auto &ti = IGF.getTypeInfoForLowered(argumentLoweringType);
valTypes.push_back(ty);
typeInfos.push_back(&ti);
localContextInfo = {ty, localContextParameter.getConvention()};
Expand All @@ -153,7 +157,7 @@ AsyncContextLayout irgen::getAsyncContextLayout(
}

// ArgTypes formalArguments...;
auto bindings = NecessaryBindings::forAsyncFunctionInvocations(
auto bindings = NecessaryBindings::forAsyncFunctionInvocation(
IGF.IGM, originalType, substitutionMap);
if (!bindings.empty()) {
auto bindingsSize = bindings.getBufferSize(IGF.IGM);
Expand All @@ -177,6 +181,28 @@ AsyncContextLayout irgen::getAsyncContextLayout(
paramInfos.push_back({ty, parameter.getConvention()});
}

Optional<AsyncContextLayout::TrailingWitnessInfo> trailingWitnessInfo;
if (originalType->getRepresentation() ==
SILFunctionTypeRepresentation::WitnessMethod) {
assert(getTrailingWitnessSignatureLength(IGF.IGM, originalType) == 2);

// First, the Self metadata.
{
auto ty = SILType();
auto &ti = IGF.IGM.getTypeMetadataPtrTypeInfo();
valTypes.push_back(ty);
typeInfos.push_back(&ti);
}
// Then, the Self witness table.
{
auto ty = SILType();
auto &ti = IGF.IGM.getWitnessTablePtrTypeInfo();
valTypes.push_back(ty);
typeInfos.push_back(&ti);
}
trailingWitnessInfo = AsyncContextLayout::TrailingWitnessInfo();
}

// ResultTypes directResults...;
auto directResults = fnConv.getDirectSILResults();
for (auto result : directResults) {
Expand All @@ -188,20 +214,20 @@ AsyncContextLayout irgen::getAsyncContextLayout(
directReturnInfos.push_back(result);
}

return AsyncContextLayout(IGF.IGM, LayoutStrategy::Optimal, valTypes,
typeInfos, IGF, originalType, substitutedType,
substitutionMap, std::move(bindings), errorType,
canHaveValidError, paramInfos, indirectReturnInfos,
directReturnInfos, localContextInfo);
return AsyncContextLayout(
IGF.IGM, LayoutStrategy::Optimal, valTypes, typeInfos, IGF, originalType,
substitutedType, substitutionMap, std::move(bindings),
trailingWitnessInfo, errorType, canHaveValidError, paramInfos,
indirectReturnInfos, directReturnInfos, localContextInfo);
}

AsyncContextLayout::AsyncContextLayout(
IRGenModule &IGM, LayoutStrategy strategy, ArrayRef<SILType> fieldTypes,
ArrayRef<const TypeInfo *> fieldTypeInfos, IRGenFunction &IGF,
CanSILFunctionType originalType, CanSILFunctionType substitutedType,
SubstitutionMap substitutionMap, NecessaryBindings &&bindings,
SILType errorType, bool canHaveValidError,
ArrayRef<ArgumentInfo> argumentInfos,
Optional<TrailingWitnessInfo> trailingWitnessInfo, SILType errorType,
bool canHaveValidError, ArrayRef<ArgumentInfo> argumentInfos,
ArrayRef<SILResultInfo> indirectReturnInfos,
ArrayRef<SILResultInfo> directReturnInfos,
Optional<AsyncContextLayout::ArgumentInfo> localContextInfo)
Expand All @@ -214,6 +240,7 @@ AsyncContextLayout::AsyncContextLayout(
indirectReturnInfos(indirectReturnInfos.begin(),
indirectReturnInfos.end()),
localContextInfo(localContextInfo), bindings(std::move(bindings)),
trailingWitnessInfo(trailingWitnessInfo),
argumentInfos(argumentInfos.begin(), argumentInfos.end()) {
#ifndef NDEBUG
assert(fieldTypeInfos.size() == fieldTypes.size() &&
Expand Down Expand Up @@ -1925,6 +1952,17 @@ class AsyncCallEmission final : public CallEmission {
getCallee().getSubstitutions());
}

void saveValue(ElementLayout layout, Explosion &explosion, bool isOutlined) {
Address addr = layout.project(IGF, context, /*offsets*/ llvm::None);
auto &ti = cast<LoadableTypeInfo>(layout.getType());
ti.initialize(IGF, explosion, addr, isOutlined);
}
void loadValue(ElementLayout layout, Explosion &explosion) {
Address addr = layout.project(IGF, context, /*offsets*/ llvm::None);
auto &ti = layout.getType();
cast<LoadableTypeInfo>(ti).loadAsTake(IGF, addr, explosion);
}

public:
AsyncCallEmission(IRGenFunction &IGF, llvm::Value *selfValue, Callee &&callee)
: CallEmission(IGF, selfValue, std::move(callee)) {
Expand Down Expand Up @@ -1970,40 +2008,25 @@ class AsyncCallEmission final : public CallEmission {
llArgs.add(selfValue);
}
auto layout = getAsyncContextLayout();
auto params = fnConv.getParameters();
for (auto index : indices(params)) {
Optional<ElementLayout> fieldLayout;
if (selfValue && index == params.size() - 1) {
fieldLayout = layout.getLocalContextLayout();
} else {
fieldLayout = layout.getArgumentLayout(index);
}
Address fieldAddr =
fieldLayout->project(IGF, context, /*offsets*/ llvm::None);
auto &ti = cast<LoadableTypeInfo>(fieldLayout->getType());
ti.initialize(IGF, llArgs, fieldAddr, isOutlined);
}
unsigned index = 0;
for (auto indirectResult : fnConv.getIndirectSILResultTypes(
IGF.IGM.getMaximalTypeExpansionContext())) {
(void)indirectResult;
for (unsigned index = 0, count = layout.getIndirectReturnCount();
index < count; ++index) {
auto fieldLayout = layout.getIndirectReturnLayout(index);
Address fieldAddr =
fieldLayout.project(IGF, context, /*offsets*/ llvm::None);
cast<LoadableTypeInfo>(fieldLayout.getType())
.initialize(IGF, llArgs, fieldAddr, isOutlined);
++index;
saveValue(fieldLayout, llArgs, isOutlined);
}
for (unsigned index = 0, count = layout.getArgumentCount(); index < count;
++index) {
auto fieldLayout = layout.getArgumentLayout(index);
saveValue(fieldLayout, llArgs, isOutlined);
}
if (layout.hasBindings()) {
auto bindingLayout = layout.getBindingsLayout();
auto bindingsAddr = bindingLayout.project(IGF, context, /*offsets*/ None);
layout.getBindings().save(IGF, bindingsAddr);
layout.getBindings().save(IGF, bindingsAddr, llArgs);
}
if (selfValue) {
auto fieldLayout = layout.getLocalContextLayout();
saveValue(fieldLayout, llArgs, isOutlined);
}
// At this point, llArgs contains the arguments that are being passed along
// via the async context. We can safely drop them on the floor.
(void)llArgs.claimAll();
// TODO: Validation: we should be able to check that the contents of llArgs
// matches what is expected by the layout.
}
void emitCallToUnmappedExplosion(llvm::CallInst *call, Explosion &out) override {
SILFunctionConventions fnConv(getCallee().getSubstFunctionType(),
Expand All @@ -2018,21 +2041,13 @@ class AsyncCallEmission final : public CallEmission {
// argument buffer.
return;
}
assert(call->arg_size() == 1);
auto context = call->arg_begin()->get();
// Gather the values.
Explosion nativeExplosion;
auto layout = getAsyncContextLayout();
auto dataAddr = layout.emitCastTo(IGF, context);
int index = layout.getFirstDirectReturnIndex();
for (auto result : fnConv.getDirectSILResults()) {
auto &fieldLayout = layout.getElement(index);
Address fieldAddr =
fieldLayout.project(IGF, dataAddr, /*offsets*/ llvm::None);
auto &fieldTI = fieldLayout.getType();
cast<LoadableTypeInfo>(fieldTI).loadAsTake(IGF, fieldAddr,
nativeExplosion);
++index;
for (unsigned index = 0, count = layout.getDirectReturnCount();
index < count; ++index) {
auto fieldLayout = layout.getDirectReturnLayout(index);
loadValue(fieldLayout, nativeExplosion);
}

out = nativeSchema.mapFromNative(IGF.IGM, IGF, nativeExplosion, resultType);
Expand Down
106 changes: 65 additions & 41 deletions lib/IRGen/GenCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ namespace irgen {
SILType type;
ParameterConvention convention;
};
struct TrailingWitnessInfo {};

private:
enum class FixedIndex : unsigned {
Expand All @@ -107,28 +108,59 @@ namespace irgen {
SmallVector<SILResultInfo, 4> indirectReturnInfos;
Optional<ArgumentInfo> localContextInfo;
NecessaryBindings bindings;
Optional<TrailingWitnessInfo> trailingWitnessInfo;
SmallVector<ArgumentInfo, 4> argumentInfos;

unsigned getErrorIndex() { return (unsigned)FixedIndex::Error; }
unsigned getFirstIndirectReturnIndex() {
return getErrorIndex() + getErrorCount();
}
unsigned getLocalContextIndex() {
assert(hasLocalContext());
return getFirstIndirectReturnIndex() + getIndirectReturnCount();
}
unsigned getIndexAfterLocalContext() {
return getFirstIndirectReturnIndex() + getIndirectReturnCount() +
(hasLocalContext() ? 1 : 0);
}
unsigned getBindingsIndex() {
assert(hasBindings());
return getIndexAfterLocalContext();
}
unsigned getIndexAfterBindings() {
return getIndexAfterLocalContext() + (hasBindings() ? 1 : 0);
}
unsigned getFirstArgumentIndex() { return getIndexAfterBindings(); }
unsigned getIndexAfterArguments() {
return getFirstArgumentIndex() + getArgumentCount();
}
unsigned getSelfMetadataIndex() {
assert(hasTrailingWitnesses());
return getIndexAfterArguments();
}
unsigned getSelfWitnessTableIndex() {
assert(hasTrailingWitnesses());
return getIndexAfterArguments() + 1;
}
unsigned getIndexAfterTrailingWitnesses() {
return getIndexAfterArguments() + (hasTrailingWitnesses() ? 2 : 0);
}
unsigned getFirstDirectReturnIndex() {
return getIndexAfterTrailingWitnesses();
}

public:
bool canHaveError() { return canHaveValidError; }
unsigned getErrorIndex() { return (unsigned)FixedIndex::Error; }
ElementLayout getErrorLayout() { return getElement(getErrorIndex()); }
unsigned getErrorCount() { return (unsigned)FixedCount::Error; }
SILType getErrorType() { return errorType; }

unsigned getFirstIndirectReturnIndex() {
return getErrorIndex() + getErrorCount();
}
ElementLayout getIndirectReturnLayout(unsigned index) {
return getElement(getFirstIndirectReturnIndex() + index);
}
unsigned getIndirectReturnCount() { return indirectReturnInfos.size(); }

bool hasLocalContext() { return (bool)localContextInfo; }
unsigned getLocalContextIndex() {
assert(hasLocalContext());
return getFirstIndirectReturnIndex() + getIndirectReturnCount();
}
ElementLayout getLocalContextLayout() {
assert(hasLocalContext());
return getElement(getLocalContextIndex());
Expand All @@ -141,61 +173,53 @@ namespace irgen {
assert(hasLocalContext());
return localContextInfo->type;
}
unsigned getIndexAfterLocalContext() {
return getFirstIndirectReturnIndex() + getIndirectReturnCount() +
(hasLocalContext() ? 1 : 0);
}

bool hasBindings() const { return !bindings.empty(); }
unsigned getBindingsIndex() {
assert(hasBindings());
return getIndexAfterLocalContext();
}
ElementLayout getBindingsLayout() {
assert(hasBindings());
return getElement(getBindingsIndex());
}
ParameterConvention getBindingsConvention() {
return ParameterConvention::Direct_Unowned;
}
const NecessaryBindings &getBindings() const { return bindings; }

unsigned getFirstArgumentIndex() {
return getIndexAfterLocalContext() + (hasBindings() ? 1 : 0);
}
ElementLayout getArgumentLayout(unsigned index) {
return getElement(getFirstArgumentIndex() + index);
}
ParameterConvention getArgumentConvention(unsigned index) {
return argumentInfos[index].convention;
}
SILType getArgumentType(unsigned index) {
return argumentInfos[index].type;
}
// Returns the type of a parameter of the substituted function using the
// indexing of the function parameters, *not* the indexing of
// AsyncContextLayout.
SILType getParameterType(unsigned index) {
SILFunctionConventions origConv(substitutedType, IGF.getSILModule());
return origConv.getSILArgumentType(
index, IGF.IGM.getMaximalTypeExpansionContext());
}
unsigned getArgumentCount() { return argumentInfos.size(); }
unsigned getIndexAfterArguments() {
return getFirstArgumentIndex() + getArgumentCount();
bool hasTrailingWitnesses() { return (bool)trailingWitnessInfo; }
ElementLayout getSelfMetadataLayout() {
assert(hasTrailingWitnesses());
return getElement(getSelfMetadataIndex());
}
ElementLayout getSelfWitnessTableLayout() {
return getElement(getSelfWitnessTableIndex());
}

unsigned getDirectReturnCount() { return directReturnInfos.size(); }
ElementLayout getDirectReturnLayout(unsigned index) {
return getElement(getFirstDirectReturnIndex() + index);
}

unsigned getFirstDirectReturnIndex() { return getIndexAfterArguments(); }

AsyncContextLayout(IRGenModule &IGM, LayoutStrategy strategy,
ArrayRef<SILType> fieldTypes,
ArrayRef<const TypeInfo *> fieldTypeInfos,
IRGenFunction &IGF, CanSILFunctionType originalType,
CanSILFunctionType substitutedType,
SubstitutionMap substitutionMap,
NecessaryBindings &&bindings, SILType errorType,
bool canHaveValidError,
ArrayRef<ArgumentInfo> argumentInfos,
ArrayRef<SILResultInfo> directReturnInfos,
ArrayRef<SILResultInfo> indirectReturnInfos,
Optional<ArgumentInfo> localContextInfo);
AsyncContextLayout(
IRGenModule &IGM, LayoutStrategy strategy, ArrayRef<SILType> fieldTypes,
ArrayRef<const TypeInfo *> fieldTypeInfos, IRGenFunction &IGF,
CanSILFunctionType originalType, CanSILFunctionType substitutedType,
SubstitutionMap substitutionMap, NecessaryBindings &&bindings,
Optional<TrailingWitnessInfo> trailingWitnessInfo, SILType errorType,
bool canHaveValidError, ArrayRef<ArgumentInfo> argumentInfos,
ArrayRef<SILResultInfo> directReturnInfos,
ArrayRef<SILResultInfo> indirectReturnInfos,
Optional<ArgumentInfo> localContextInfo);
};

AsyncContextLayout getAsyncContextLayout(IRGenFunction &IGF,
Expand Down
Loading