Skip to content

Change the compiler ABI of keypaths. #20493

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
merged 5 commits into from
Nov 10, 2018
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
16 changes: 16 additions & 0 deletions include/swift/ABI/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,11 +625,27 @@ struct TargetMetadata {
getValueWitnesses()->_asEVWT()->destructiveInjectEnumTag(value, tag, this);
}

size_t vw_size() const {
return getValueWitnesses()->getSize();
}

size_t vw_alignment() const {
return getValueWitnesses()->getAlignment();
}

size_t vw_stride() const {
return getValueWitnesses()->getStride();
}

/// Allocate an out-of-line buffer if values of this type don't fit in the
/// ValueBuffer.
/// NOTE: This is not a box for copy-on-write existentials.
OpaqueValue *allocateBufferIn(ValueBuffer *buffer) const;

/// Get the address of the memory previously allocated in the ValueBuffer.
/// NOTE: This is not a box for copy-on-write existentials.
OpaqueValue *projectBufferFrom(ValueBuffer *buffer) const;

/// Deallocate an out-of-line buffer stored in 'buffer' if values of this type
/// are not stored inline in the ValueBuffer.
void deallocateBufferIn(ValueBuffer *buffer) const;
Expand Down
14 changes: 9 additions & 5 deletions include/swift/AST/KnownDecls.def
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,15 @@ FUNC_DECL(GetErrorEmbeddedNSError, "_getErrorEmbeddedNSError")

FUNC_DECL(UnsafeBitCast, "unsafeBitCast")

FUNC_DECL(ProjectKeyPathAny, "_projectKeyPathAny")
FUNC_DECL(ProjectKeyPathPartial, "_projectKeyPathPartial")
FUNC_DECL(ProjectKeyPathReadOnly, "_projectKeyPathReadOnly")
FUNC_DECL(ProjectKeyPathWritable, "_projectKeyPathWritable")
FUNC_DECL(ProjectKeyPathReferenceWritable, "_projectKeyPathReferenceWritable")
FUNC_DECL(GetAtKeyPath, "_getAtKeyPath")
FUNC_DECL(GetAtAnyKeyPath, "_getAtAnyKeyPath")
FUNC_DECL(GetAtPartialKeyPath, "_getAtPartialKeyPath")
FUNC_DECL(SetAtWritableKeyPath, "_setAtWritableKeyPath")
FUNC_DECL(SetAtReferenceWritableKeyPath, "_setAtReferenceWritableKeyPath")
// These don't actually have AST nodes associated with them right now.
FUNC_DECL(ReadAtKeyPath, "_readAtKeyPath")
FUNC_DECL(ModifyAtWritableKeyPath, "_modifyAtWritableKeyPath")
FUNC_DECL(ModifyAtReferenceWritableKeyPath, "_modifyAtReferenceWritableKeyPath")

FUNC_DECL(Swap, "swap")

Expand Down
55 changes: 55 additions & 0 deletions include/swift/Runtime/Metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,37 @@

namespace swift {

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"

/// The buffer used by a yield-once coroutine (such as the generalized
/// accessors `read` and `modify`).
struct YieldOnceBuffer {
void *Data[NumWords_YieldOnceBuffer];
};
using YieldOnceContinuation =
SWIFT_CC(swift) void (YieldOnceBuffer *buffer, bool forUnwind);

/// The return type of a call to a yield-once coroutine. The function
/// must be declared with the swiftcall calling convention.
template <class ResultTy>
struct YieldOnceResult {
YieldOnceContinuation *Continuation;
ResultTy YieldValue;
};

template <class FnTy>
struct YieldOnceCoroutine;

/// A template which generates the type of the ramp function of a
/// yield-once coroutine.
template <class ResultTy, class... ArgTys>
struct YieldOnceCoroutine<ResultTy(ArgTys...)> {
using type =
SWIFT_CC(swift) YieldOnceResult<ResultTy> (YieldOnceBuffer *buffer,
ArgTys...);
};

#if SWIFT_OBJC_INTEROP

// Const cast shorthands for ObjC types.
Expand Down Expand Up @@ -806,12 +837,36 @@ const TypeContextDescriptor *swift_getTypeContextDescriptor(const Metadata *type
SWIFT_RUNTIME_EXPORT
const HeapObject *swift_getKeyPath(const void *pattern, const void *arguments);

/// Given a pointer to a borrowed value of type `Root` and a
/// `KeyPath<Root, Value>`, project a pointer to a borrowed value of type
/// `Value`.
SWIFT_RUNTIME_EXPORT
YieldOnceCoroutine<const OpaqueValue* (const OpaqueValue *root,
void *keyPath)>::type
swift_readAtKeyPath;

/// Given a pointer to a mutable value of type `Root` and a
/// `WritableKeyPath<Root, Value>`, project a pointer to a mutable value
/// of type `Value`.
SWIFT_RUNTIME_EXPORT
YieldOnceCoroutine<OpaqueValue* (OpaqueValue *root, void *keyPath)>::type
swift_modifyAtWritableKeyPath;

/// Given a pointer to a borrowed value of type `Root` and a
/// `ReferenceWritableKeyPath<Root, Value>`, project a pointer to a
/// mutable value of type `Value`.
SWIFT_RUNTIME_EXPORT
YieldOnceCoroutine<OpaqueValue* (const OpaqueValue *root, void *keyPath)>::type
swift_modifyAtReferenceWritableKeyPath;

SWIFT_RUNTIME_EXPORT
void swift_enableDynamicReplacementScope(const DynamicReplacementScope *scope);

SWIFT_RUNTIME_EXPORT
void swift_disableDynamicReplacementScope(const DynamicReplacementScope *scope);

#pragma clang diagnostic pop

} // end namespace swift

#endif // SWIFT_RUNTIME_METADATA_H
87 changes: 87 additions & 0 deletions lib/SILGen/SILGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,93 @@ ProtocolConformance *SILGenModule::getNSErrorConformanceToError() {
return *NSErrorConformanceToError;
}

SILFunction *
SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess,
KeyPathTypeKind typeKind) {
bool isBaseInout;
bool isResultInout;
StringRef functionName;
NominalTypeDecl *keyPathDecl;
if (isReadAccess) {
assert(typeKind == KPTK_KeyPath ||
typeKind == KPTK_WritableKeyPath ||
typeKind == KPTK_ReferenceWritableKeyPath);
functionName = "swift_readAtKeyPath";
isBaseInout = false;
isResultInout = false;
keyPathDecl = getASTContext().getKeyPathDecl();
} else if (typeKind == KPTK_WritableKeyPath) {
functionName = "swift_modifyAtWritableKeyPath";
isBaseInout = true;
isResultInout = true;
keyPathDecl = getASTContext().getWritableKeyPathDecl();
} else if (typeKind == KPTK_ReferenceWritableKeyPath) {
functionName = "swift_modifyAtReferenceWritableKeyPath";
isBaseInout = false;
isResultInout = true;
keyPathDecl = getASTContext().getReferenceWritableKeyPathDecl();
} else {
llvm_unreachable("bad combination");
}

auto fn = M.lookUpFunction(functionName);
if (fn) return fn;

auto rootType = CanGenericTypeParamType::get(0, 0, getASTContext());
auto valueType = CanGenericTypeParamType::get(0, 1, getASTContext());

// Build the generic signature <A, B>.
auto sig = GenericSignature::get({rootType, valueType}, {});

auto keyPathTy = BoundGenericType::get(keyPathDecl, Type(),
{ rootType, valueType })
->getCanonicalType();

// (@in_guaranteed/@inout Root, @guaranteed KeyPath<Root, Value>)
SILParameterInfo params[] = {
{ rootType,
isBaseInout ? ParameterConvention::Indirect_Inout
: ParameterConvention::Indirect_In_Guaranteed },
{ keyPathTy, ParameterConvention::Direct_Guaranteed },
};

// -> @yields @in_guaranteed/@inout Value
SILYieldInfo yields[] = {
{ valueType,
isResultInout ? ParameterConvention::Indirect_Inout
: ParameterConvention::Indirect_In_Guaranteed },
};

auto extInfo =
SILFunctionType::ExtInfo(SILFunctionTypeRepresentation::Thin,
/*pseudogeneric*/false,
/*non-escaping*/false);

auto functionTy = SILFunctionType::get(sig, extInfo,
SILCoroutineKind::YieldOnce,
ParameterConvention::Direct_Unowned,
params,
yields,
/*results*/ {},
/*error result*/ {},
getASTContext());

auto env = sig->createGenericEnvironment();

SILGenFunctionBuilder builder(*this);
fn = builder.createFunction(SILLinkage::PublicExternal,
functionName,
functionTy,
env,
/*location*/ None,
IsNotBare,
IsNotTransparent,
IsNotSerialized,
IsNotDynamic);

return fn;
}


SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) {
ASTContext &C = M.getASTContext();
Expand Down
3 changes: 3 additions & 0 deletions lib/SILGen/SILGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
/// Retrieve the conformance of NSError to the Error protocol.
ProtocolConformance *getNSErrorConformanceToError();

SILFunction *getKeyPathProjectionCoroutine(bool isReadAccess,
KeyPathTypeKind typeKind);

/// Report a diagnostic.
template<typename...T, typename...U>
InFlightDiagnostic diagnose(SourceLoc loc, Diag<T...> diag,
Expand Down
43 changes: 30 additions & 13 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4344,30 +4344,41 @@ CallEmission::applyCoroutine(SmallVectorImpl<ManagedValue> &yields) {

auto fnValue = callee.getFnValue(SGF, isCurried, borrowedSelf);

// Emit the uncurried call.
return SGF.emitBeginApply(uncurriedLoc.getValue(), fnValue,
callee.getSubstitutions(), uncurriedArgs,
calleeTypeInfo.substFnType, options, yields);
}

CleanupHandle
SILGenFunction::emitBeginApply(SILLocation loc, ManagedValue fn,
SubstitutionMap subs,
ArrayRef<ManagedValue> args,
CanSILFunctionType substFnType,
ApplyOptions options,
SmallVectorImpl<ManagedValue> &yields) {
// Emit the call.
SmallVector<SILValue, 4> rawResults;
emitRawApply(SGF, uncurriedLoc.getValue(), fnValue, callee.getSubstitutions(),
uncurriedArgs, calleeTypeInfo.substFnType, options,
emitRawApply(*this, loc, fn, subs, args, substFnType, options,
/*indirect results*/ {}, rawResults);

auto token = rawResults.pop_back_val();
auto yieldValues = llvm::makeArrayRef(rawResults);

// Push a cleanup to end the application.
// TODO: destroy all the arguments at exactly this point?
SGF.Cleanups.pushCleanup<EndCoroutineApply>(token);
auto endApplyHandle = SGF.getTopCleanup();
Cleanups.pushCleanup<EndCoroutineApply>(token);
auto endApplyHandle = getTopCleanup();

// Manage all the yielded values.
auto yieldInfos = calleeTypeInfo.substFnType->getYields();
auto yieldInfos = substFnType->getYields();
assert(yieldValues.size() == yieldInfos.size());
for (auto i : indices(yieldValues)) {
auto value = yieldValues[i];
auto info = yieldInfos[i];
if (info.isIndirectInOut()) {
yields.push_back(ManagedValue::forLValue(value));
} else if (info.isConsumed()) {
yields.push_back(SGF.emitManagedRValueWithCleanup(value));
yields.push_back(emitManagedRValueWithCleanup(value));
} else if (info.isDirectGuaranteed()) {
yields.push_back(ManagedValue::forBorrowedRValue(value));
} else {
Expand Down Expand Up @@ -5115,11 +5126,12 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
return normalBB->createPhiArgument(resultType, ValueOwnershipKind::Owned);
}

SILValue SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
SILType substFnType,
SubstitutionMap subs,
ArrayRef<SILValue> args,
SmallVectorImpl<SILValue> &yields) {
std::pair<SILValue, CleanupHandle>
SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
SILType substFnType,
SubstitutionMap subs,
ArrayRef<SILValue> args,
SmallVectorImpl<SILValue> &yields) {
// TODO: adjust this to create try_begin_apply when appropriate.
assert(!substFnType.castTo<SILFunctionType>()->hasErrorResult());

Expand All @@ -5128,7 +5140,12 @@ SILValue SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
auto yieldResults = beginApply->getYieldedValues();
yields.append(yieldResults.begin(), yieldResults.end());

return beginApply->getTokenResult();
auto token = beginApply->getTokenResult();

Cleanups.pushCleanup<EndCoroutineApply>(token);
auto abortCleanup = Cleanups.getTopCleanup();

return { token, abortCleanup };
}

void SILGenFunction::emitEndApplyWithRethrow(SILLocation loc, SILValue token) {
Expand Down
13 changes: 13 additions & 0 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4314,6 +4314,19 @@ static void emitSimpleAssignment(SILGenFunction &SGF, SILLocation loc,
// also prevents us from getting into that case.
if (dest->getType()->isEqual(srcLoad->getSubExpr()->getType())) {
assert(!dest->getType()->is<TupleType>());

dest = dest->getSemanticsProvidingExpr();
if (isa<DiscardAssignmentExpr>(dest)) {
// The logical thing to do here would be emitIgnoredExpr, but that
// changed some test results in a way I wanted to avoid, so instead
// we're doing this.
FormalEvaluationScope writeback(SGF);
auto srcLV = SGF.emitLValue(srcLoad->getSubExpr(),
SGFAccessKind::IgnoredRead);
(void) SGF.emitLoadOfLValue(loc, std::move(srcLV), SGFContext());
return;
}

FormalEvaluationScope writeback(SGF);
auto destLV = SGF.emitLValue(dest, SGFAccessKind::Write);
auto srcLV = SGF.emitLValue(srcLoad->getSubExpr(),
Expand Down
15 changes: 10 additions & 5 deletions lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1471,16 +1471,21 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
ArrayRef<ManagedValue> args,
SGFContext ctx);

CleanupHandle emitBeginApply(SILLocation loc, ManagedValue fn,
SubstitutionMap subs, ArrayRef<ManagedValue> args,
CanSILFunctionType substFnType,
ApplyOptions options,
SmallVectorImpl<ManagedValue> &yields);

SILValue emitApplyWithRethrow(SILLocation loc, SILValue fn,
SILType substFnType,
SubstitutionMap subs,
ArrayRef<SILValue> args);

SILValue emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
SILType substFnType,
SubstitutionMap subs,
ArrayRef<SILValue> args,
SmallVectorImpl<SILValue> &yields);
std::pair<SILValue, CleanupHandle>
emitBeginApplyWithRethrow(SILLocation loc, SILValue fn, SILType substFnType,
SubstitutionMap subs, ArrayRef<SILValue> args,
SmallVectorImpl<SILValue> &yields);
void emitEndApplyWithRethrow(SILLocation loc, SILValue token);

/// Emit a literal that applies the various initializers.
Expand Down
Loading