Skip to content

Commit 44e0f44

Browse files
authored
Merge pull request #20493 from rjmccall/keypath-compiler-abi
Change the compiler ABI of keypaths.
2 parents 9d0c97e + 3e5165d commit 44e0f44

23 files changed

+731
-446
lines changed

include/swift/ABI/Metadata.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -625,11 +625,27 @@ struct TargetMetadata {
625625
getValueWitnesses()->_asEVWT()->destructiveInjectEnumTag(value, tag, this);
626626
}
627627

628+
size_t vw_size() const {
629+
return getValueWitnesses()->getSize();
630+
}
631+
632+
size_t vw_alignment() const {
633+
return getValueWitnesses()->getAlignment();
634+
}
635+
636+
size_t vw_stride() const {
637+
return getValueWitnesses()->getStride();
638+
}
639+
628640
/// Allocate an out-of-line buffer if values of this type don't fit in the
629641
/// ValueBuffer.
630642
/// NOTE: This is not a box for copy-on-write existentials.
631643
OpaqueValue *allocateBufferIn(ValueBuffer *buffer) const;
632644

645+
/// Get the address of the memory previously allocated in the ValueBuffer.
646+
/// NOTE: This is not a box for copy-on-write existentials.
647+
OpaqueValue *projectBufferFrom(ValueBuffer *buffer) const;
648+
633649
/// Deallocate an out-of-line buffer stored in 'buffer' if values of this type
634650
/// are not stored inline in the ValueBuffer.
635651
void deallocateBufferIn(ValueBuffer *buffer) const;

include/swift/AST/KnownDecls.def

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,15 @@ FUNC_DECL(GetErrorEmbeddedNSError, "_getErrorEmbeddedNSError")
7171

7272
FUNC_DECL(UnsafeBitCast, "unsafeBitCast")
7373

74-
FUNC_DECL(ProjectKeyPathAny, "_projectKeyPathAny")
75-
FUNC_DECL(ProjectKeyPathPartial, "_projectKeyPathPartial")
76-
FUNC_DECL(ProjectKeyPathReadOnly, "_projectKeyPathReadOnly")
77-
FUNC_DECL(ProjectKeyPathWritable, "_projectKeyPathWritable")
78-
FUNC_DECL(ProjectKeyPathReferenceWritable, "_projectKeyPathReferenceWritable")
74+
FUNC_DECL(GetAtKeyPath, "_getAtKeyPath")
75+
FUNC_DECL(GetAtAnyKeyPath, "_getAtAnyKeyPath")
76+
FUNC_DECL(GetAtPartialKeyPath, "_getAtPartialKeyPath")
77+
FUNC_DECL(SetAtWritableKeyPath, "_setAtWritableKeyPath")
78+
FUNC_DECL(SetAtReferenceWritableKeyPath, "_setAtReferenceWritableKeyPath")
79+
// These don't actually have AST nodes associated with them right now.
80+
FUNC_DECL(ReadAtKeyPath, "_readAtKeyPath")
81+
FUNC_DECL(ModifyAtWritableKeyPath, "_modifyAtWritableKeyPath")
82+
FUNC_DECL(ModifyAtReferenceWritableKeyPath, "_modifyAtReferenceWritableKeyPath")
7983

8084
FUNC_DECL(Swap, "swap")
8185

include/swift/Runtime/Metadata.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,37 @@
2222

2323
namespace swift {
2424

25+
#pragma clang diagnostic push
26+
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
27+
28+
/// The buffer used by a yield-once coroutine (such as the generalized
29+
/// accessors `read` and `modify`).
30+
struct YieldOnceBuffer {
31+
void *Data[NumWords_YieldOnceBuffer];
32+
};
33+
using YieldOnceContinuation =
34+
SWIFT_CC(swift) void (YieldOnceBuffer *buffer, bool forUnwind);
35+
36+
/// The return type of a call to a yield-once coroutine. The function
37+
/// must be declared with the swiftcall calling convention.
38+
template <class ResultTy>
39+
struct YieldOnceResult {
40+
YieldOnceContinuation *Continuation;
41+
ResultTy YieldValue;
42+
};
43+
44+
template <class FnTy>
45+
struct YieldOnceCoroutine;
46+
47+
/// A template which generates the type of the ramp function of a
48+
/// yield-once coroutine.
49+
template <class ResultTy, class... ArgTys>
50+
struct YieldOnceCoroutine<ResultTy(ArgTys...)> {
51+
using type =
52+
SWIFT_CC(swift) YieldOnceResult<ResultTy> (YieldOnceBuffer *buffer,
53+
ArgTys...);
54+
};
55+
2556
#if SWIFT_OBJC_INTEROP
2657

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

840+
/// Given a pointer to a borrowed value of type `Root` and a
841+
/// `KeyPath<Root, Value>`, project a pointer to a borrowed value of type
842+
/// `Value`.
843+
SWIFT_RUNTIME_EXPORT
844+
YieldOnceCoroutine<const OpaqueValue* (const OpaqueValue *root,
845+
void *keyPath)>::type
846+
swift_readAtKeyPath;
847+
848+
/// Given a pointer to a mutable value of type `Root` and a
849+
/// `WritableKeyPath<Root, Value>`, project a pointer to a mutable value
850+
/// of type `Value`.
851+
SWIFT_RUNTIME_EXPORT
852+
YieldOnceCoroutine<OpaqueValue* (OpaqueValue *root, void *keyPath)>::type
853+
swift_modifyAtWritableKeyPath;
854+
855+
/// Given a pointer to a borrowed value of type `Root` and a
856+
/// `ReferenceWritableKeyPath<Root, Value>`, project a pointer to a
857+
/// mutable value of type `Value`.
858+
SWIFT_RUNTIME_EXPORT
859+
YieldOnceCoroutine<OpaqueValue* (const OpaqueValue *root, void *keyPath)>::type
860+
swift_modifyAtReferenceWritableKeyPath;
861+
809862
SWIFT_RUNTIME_EXPORT
810863
void swift_enableDynamicReplacementScope(const DynamicReplacementScope *scope);
811864

812865
SWIFT_RUNTIME_EXPORT
813866
void swift_disableDynamicReplacementScope(const DynamicReplacementScope *scope);
814867

868+
#pragma clang diagnostic pop
869+
815870
} // end namespace swift
816871

817872
#endif // SWIFT_RUNTIME_METADATA_H

lib/SILGen/SILGen.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,93 @@ ProtocolConformance *SILGenModule::getNSErrorConformanceToError() {
381381
return *NSErrorConformanceToError;
382382
}
383383

384+
SILFunction *
385+
SILGenModule::getKeyPathProjectionCoroutine(bool isReadAccess,
386+
KeyPathTypeKind typeKind) {
387+
bool isBaseInout;
388+
bool isResultInout;
389+
StringRef functionName;
390+
NominalTypeDecl *keyPathDecl;
391+
if (isReadAccess) {
392+
assert(typeKind == KPTK_KeyPath ||
393+
typeKind == KPTK_WritableKeyPath ||
394+
typeKind == KPTK_ReferenceWritableKeyPath);
395+
functionName = "swift_readAtKeyPath";
396+
isBaseInout = false;
397+
isResultInout = false;
398+
keyPathDecl = getASTContext().getKeyPathDecl();
399+
} else if (typeKind == KPTK_WritableKeyPath) {
400+
functionName = "swift_modifyAtWritableKeyPath";
401+
isBaseInout = true;
402+
isResultInout = true;
403+
keyPathDecl = getASTContext().getWritableKeyPathDecl();
404+
} else if (typeKind == KPTK_ReferenceWritableKeyPath) {
405+
functionName = "swift_modifyAtReferenceWritableKeyPath";
406+
isBaseInout = false;
407+
isResultInout = true;
408+
keyPathDecl = getASTContext().getReferenceWritableKeyPathDecl();
409+
} else {
410+
llvm_unreachable("bad combination");
411+
}
412+
413+
auto fn = M.lookUpFunction(functionName);
414+
if (fn) return fn;
415+
416+
auto rootType = CanGenericTypeParamType::get(0, 0, getASTContext());
417+
auto valueType = CanGenericTypeParamType::get(0, 1, getASTContext());
418+
419+
// Build the generic signature <A, B>.
420+
auto sig = GenericSignature::get({rootType, valueType}, {});
421+
422+
auto keyPathTy = BoundGenericType::get(keyPathDecl, Type(),
423+
{ rootType, valueType })
424+
->getCanonicalType();
425+
426+
// (@in_guaranteed/@inout Root, @guaranteed KeyPath<Root, Value>)
427+
SILParameterInfo params[] = {
428+
{ rootType,
429+
isBaseInout ? ParameterConvention::Indirect_Inout
430+
: ParameterConvention::Indirect_In_Guaranteed },
431+
{ keyPathTy, ParameterConvention::Direct_Guaranteed },
432+
};
433+
434+
// -> @yields @in_guaranteed/@inout Value
435+
SILYieldInfo yields[] = {
436+
{ valueType,
437+
isResultInout ? ParameterConvention::Indirect_Inout
438+
: ParameterConvention::Indirect_In_Guaranteed },
439+
};
440+
441+
auto extInfo =
442+
SILFunctionType::ExtInfo(SILFunctionTypeRepresentation::Thin,
443+
/*pseudogeneric*/false,
444+
/*non-escaping*/false);
445+
446+
auto functionTy = SILFunctionType::get(sig, extInfo,
447+
SILCoroutineKind::YieldOnce,
448+
ParameterConvention::Direct_Unowned,
449+
params,
450+
yields,
451+
/*results*/ {},
452+
/*error result*/ {},
453+
getASTContext());
454+
455+
auto env = sig->createGenericEnvironment();
456+
457+
SILGenFunctionBuilder builder(*this);
458+
fn = builder.createFunction(SILLinkage::PublicExternal,
459+
functionName,
460+
functionTy,
461+
env,
462+
/*location*/ None,
463+
IsNotBare,
464+
IsNotTransparent,
465+
IsNotSerialized,
466+
IsNotDynamic);
467+
468+
return fn;
469+
}
470+
384471

385472
SILFunction *SILGenModule::emitTopLevelFunction(SILLocation Loc) {
386473
ASTContext &C = M.getASTContext();

lib/SILGen/SILGen.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
407407
/// Retrieve the conformance of NSError to the Error protocol.
408408
ProtocolConformance *getNSErrorConformanceToError();
409409

410+
SILFunction *getKeyPathProjectionCoroutine(bool isReadAccess,
411+
KeyPathTypeKind typeKind);
412+
410413
/// Report a diagnostic.
411414
template<typename...T, typename...U>
412415
InFlightDiagnostic diagnose(SourceLoc loc, Diag<T...> diag,

lib/SILGen/SILGenApply.cpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4344,30 +4344,41 @@ CallEmission::applyCoroutine(SmallVectorImpl<ManagedValue> &yields) {
43444344

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

4347-
// Emit the uncurried call.
4347+
return SGF.emitBeginApply(uncurriedLoc.getValue(), fnValue,
4348+
callee.getSubstitutions(), uncurriedArgs,
4349+
calleeTypeInfo.substFnType, options, yields);
4350+
}
4351+
4352+
CleanupHandle
4353+
SILGenFunction::emitBeginApply(SILLocation loc, ManagedValue fn,
4354+
SubstitutionMap subs,
4355+
ArrayRef<ManagedValue> args,
4356+
CanSILFunctionType substFnType,
4357+
ApplyOptions options,
4358+
SmallVectorImpl<ManagedValue> &yields) {
4359+
// Emit the call.
43484360
SmallVector<SILValue, 4> rawResults;
4349-
emitRawApply(SGF, uncurriedLoc.getValue(), fnValue, callee.getSubstitutions(),
4350-
uncurriedArgs, calleeTypeInfo.substFnType, options,
4361+
emitRawApply(*this, loc, fn, subs, args, substFnType, options,
43514362
/*indirect results*/ {}, rawResults);
43524363

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

43564367
// Push a cleanup to end the application.
43574368
// TODO: destroy all the arguments at exactly this point?
4358-
SGF.Cleanups.pushCleanup<EndCoroutineApply>(token);
4359-
auto endApplyHandle = SGF.getTopCleanup();
4369+
Cleanups.pushCleanup<EndCoroutineApply>(token);
4370+
auto endApplyHandle = getTopCleanup();
43604371

43614372
// Manage all the yielded values.
4362-
auto yieldInfos = calleeTypeInfo.substFnType->getYields();
4373+
auto yieldInfos = substFnType->getYields();
43634374
assert(yieldValues.size() == yieldInfos.size());
43644375
for (auto i : indices(yieldValues)) {
43654376
auto value = yieldValues[i];
43664377
auto info = yieldInfos[i];
43674378
if (info.isIndirectInOut()) {
43684379
yields.push_back(ManagedValue::forLValue(value));
43694380
} else if (info.isConsumed()) {
4370-
yields.push_back(SGF.emitManagedRValueWithCleanup(value));
4381+
yields.push_back(emitManagedRValueWithCleanup(value));
43714382
} else if (info.isDirectGuaranteed()) {
43724383
yields.push_back(ManagedValue::forBorrowedRValue(value));
43734384
} else {
@@ -5115,11 +5126,12 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
51155126
return normalBB->createPhiArgument(resultType, ValueOwnershipKind::Owned);
51165127
}
51175128

5118-
SILValue SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
5119-
SILType substFnType,
5120-
SubstitutionMap subs,
5121-
ArrayRef<SILValue> args,
5122-
SmallVectorImpl<SILValue> &yields) {
5129+
std::pair<SILValue, CleanupHandle>
5130+
SILGenFunction::emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
5131+
SILType substFnType,
5132+
SubstitutionMap subs,
5133+
ArrayRef<SILValue> args,
5134+
SmallVectorImpl<SILValue> &yields) {
51235135
// TODO: adjust this to create try_begin_apply when appropriate.
51245136
assert(!substFnType.castTo<SILFunctionType>()->hasErrorResult());
51255137

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

5131-
return beginApply->getTokenResult();
5143+
auto token = beginApply->getTokenResult();
5144+
5145+
Cleanups.pushCleanup<EndCoroutineApply>(token);
5146+
auto abortCleanup = Cleanups.getTopCleanup();
5147+
5148+
return { token, abortCleanup };
51325149
}
51335150

51345151
void SILGenFunction::emitEndApplyWithRethrow(SILLocation loc, SILValue token) {

lib/SILGen/SILGenExpr.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4314,6 +4314,19 @@ static void emitSimpleAssignment(SILGenFunction &SGF, SILLocation loc,
43144314
// also prevents us from getting into that case.
43154315
if (dest->getType()->isEqual(srcLoad->getSubExpr()->getType())) {
43164316
assert(!dest->getType()->is<TupleType>());
4317+
4318+
dest = dest->getSemanticsProvidingExpr();
4319+
if (isa<DiscardAssignmentExpr>(dest)) {
4320+
// The logical thing to do here would be emitIgnoredExpr, but that
4321+
// changed some test results in a way I wanted to avoid, so instead
4322+
// we're doing this.
4323+
FormalEvaluationScope writeback(SGF);
4324+
auto srcLV = SGF.emitLValue(srcLoad->getSubExpr(),
4325+
SGFAccessKind::IgnoredRead);
4326+
(void) SGF.emitLoadOfLValue(loc, std::move(srcLV), SGFContext());
4327+
return;
4328+
}
4329+
43174330
FormalEvaluationScope writeback(SGF);
43184331
auto destLV = SGF.emitLValue(dest, SGFAccessKind::Write);
43194332
auto srcLV = SGF.emitLValue(srcLoad->getSubExpr(),

lib/SILGen/SILGenFunction.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,16 +1471,21 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
14711471
ArrayRef<ManagedValue> args,
14721472
SGFContext ctx);
14731473

1474+
CleanupHandle emitBeginApply(SILLocation loc, ManagedValue fn,
1475+
SubstitutionMap subs, ArrayRef<ManagedValue> args,
1476+
CanSILFunctionType substFnType,
1477+
ApplyOptions options,
1478+
SmallVectorImpl<ManagedValue> &yields);
1479+
14741480
SILValue emitApplyWithRethrow(SILLocation loc, SILValue fn,
14751481
SILType substFnType,
14761482
SubstitutionMap subs,
14771483
ArrayRef<SILValue> args);
14781484

1479-
SILValue emitBeginApplyWithRethrow(SILLocation loc, SILValue fn,
1480-
SILType substFnType,
1481-
SubstitutionMap subs,
1482-
ArrayRef<SILValue> args,
1483-
SmallVectorImpl<SILValue> &yields);
1485+
std::pair<SILValue, CleanupHandle>
1486+
emitBeginApplyWithRethrow(SILLocation loc, SILValue fn, SILType substFnType,
1487+
SubstitutionMap subs, ArrayRef<SILValue> args,
1488+
SmallVectorImpl<SILValue> &yields);
14841489
void emitEndApplyWithRethrow(SILLocation loc, SILValue token);
14851490

14861491
/// Emit a literal that applies the various initializers.

0 commit comments

Comments
 (0)