Skip to content

Commit 90d942c

Browse files
Merge pull request swiftlang#29740 from aschwaighofer/irgen_cache_optional_metadata_construction
IRGen: Cache type metadata construction of Optional types
2 parents 5a8e3ea + ea5fa5a commit 90d942c

File tree

2 files changed

+120
-127
lines changed

2 files changed

+120
-127
lines changed

lib/IRGen/MetadataRequest.cpp

Lines changed: 110 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -2591,156 +2591,139 @@ namespace {
25912591
///
25922592
/// NOTE: If you modify the special cases in this, you should update
25932593
/// isTypeMetadataForLayoutAccessible in SIL.cpp.
2594-
class EmitTypeMetadataRefForLayout
2595-
: public CanTypeVisitor<EmitTypeMetadataRefForLayout, llvm::Value *,
2596-
DynamicMetadataRequest> {
2597-
private:
2598-
IRGenFunction &IGF;
2599-
public:
2600-
EmitTypeMetadataRefForLayout(IRGenFunction &IGF) : IGF(IGF) {}
2601-
2602-
llvm::Value *emitDirectMetadataRef(CanType type,
2603-
DynamicMetadataRequest request) {
2604-
return IGF.IGM.getAddrOfTypeMetadata(type);
2605-
}
2606-
2607-
/// For most types, we can just emit the usual metadata.
2608-
llvm::Value *visitType(CanType t, DynamicMetadataRequest request) {
2609-
return IGF.emitTypeMetadataRef(t, request).getMetadata();
2610-
}
2611-
2612-
llvm::Value *visitBoundGenericEnumType(CanBoundGenericEnumType type,
2613-
DynamicMetadataRequest request) {
2614-
// Optionals have a lowered payload type, so we recurse here.
2615-
if (auto objectTy = type.getOptionalObjectType()) {
2616-
if (auto metadata = tryGetLocal(type, request))
2617-
return metadata;
2618-
2619-
auto payloadMetadata = visit(objectTy, request);
2620-
llvm::Value *args[] = { payloadMetadata };
2621-
llvm::Type *types[] = { IGF.IGM.TypeMetadataPtrTy };
2622-
2623-
// Call the generic metadata accessor function.
2624-
llvm::Function *accessor =
2625-
IGF.IGM.getAddrOfGenericTypeMetadataAccessFunction(
2626-
type->getDecl(), types, NotForDefinition);
2627-
2628-
auto response =
2629-
IGF.emitGenericTypeMetadataAccessFunctionCall(accessor, args,
2630-
request);
2631-
2632-
return setLocal(type, response);
2633-
}
2594+
class EmitTypeMetadataRefForLayout
2595+
: public CanTypeVisitor<EmitTypeMetadataRefForLayout, CanType> {
2596+
public:
2597+
EmitTypeMetadataRefForLayout() {}
2598+
2599+
/// For most types, we can just emit the usual metadata.
2600+
CanType visitType(CanType t) { return t; }
2601+
2602+
CanType visitBoundGenericEnumType(CanBoundGenericEnumType ty) {
2603+
// Optionals have a lowered payload type, so we recurse here.
2604+
if (auto objectTy = ty.getOptionalObjectType()) {
2605+
auto payloadTy = visit(objectTy);
2606+
if (payloadTy == objectTy)
2607+
return ty;
2608+
auto &C = ty->getASTContext();
2609+
auto optDecl = C.getOptionalDecl();
2610+
return CanType(BoundGenericEnumType::get(optDecl, Type(), payloadTy));
2611+
}
2612+
2613+
// Otherwise, generic arguments are not lowered.
2614+
return ty;
2615+
}
26342616

2635-
// Otherwise, generic arguments are not lowered.
2636-
return visitType(type, request);
2637-
}
2617+
CanType visitTupleType(CanTupleType ty) {
2618+
bool changed = false;
2619+
SmallVector<TupleTypeElt, 4> loweredElts;
2620+
loweredElts.reserve(ty->getNumElements());
26382621

2639-
llvm::Value *visitTupleType(CanTupleType type,
2640-
DynamicMetadataRequest request) {
2641-
if (auto metadata = tryGetLocal(type, request))
2642-
return metadata;
2622+
for (auto i : indices(ty->getElementTypes())) {
2623+
auto substEltType = ty.getElementType(i);
2624+
auto &substElt = ty->getElement(i);
26432625

2644-
auto response = emitTupleTypeMetadataRef(IGF, type, request,
2645-
/*labels*/ false,
2646-
[&](CanType eltType, DynamicMetadataRequest eltRequest) {
2647-
// This use of 'forComplete' is technically questionable, but in
2648-
// this class we're always producing responses we can ignore, so
2649-
// it's okay.
2650-
return MetadataResponse::forComplete(visit(eltType, eltRequest));
2651-
});
2626+
// Make sure we don't have something non-materializable.
2627+
auto Flags = substElt.getParameterFlags();
2628+
assert(Flags.getValueOwnership() == ValueOwnership::Default);
2629+
assert(!Flags.isVariadic());
26522630

2653-
return setLocal(type, response);
2654-
}
2631+
CanType loweredSubstEltType = visit(substEltType);
2632+
changed =
2633+
(changed || substEltType != loweredSubstEltType || !Flags.isNone());
26552634

2656-
llvm::Value *visitAnyFunctionType(CanAnyFunctionType type,
2657-
DynamicMetadataRequest request) {
2658-
llvm_unreachable("not a SIL type");
2659-
}
2660-
2661-
llvm::Value *visitSILFunctionType(CanSILFunctionType type,
2662-
DynamicMetadataRequest request) {
2663-
// All function types have the same layout regardless of arguments or
2664-
// abstraction level. Use the metadata for () -> () for thick functions,
2665-
// or AnyObject for block functions.
2666-
auto &C = type->getASTContext();
2667-
switch (type->getRepresentation()) {
2668-
case SILFunctionType::Representation::Thin:
2669-
case SILFunctionType::Representation::Method:
2670-
case SILFunctionType::Representation::WitnessMethod:
2671-
case SILFunctionType::Representation::ObjCMethod:
2672-
case SILFunctionType::Representation::CFunctionPointer:
2673-
case SILFunctionType::Representation::Closure:
2674-
// A thin function looks like a plain pointer.
2675-
// FIXME: Except for extra inhabitants?
2676-
return emitDirectMetadataRef(C.TheRawPointerType, request);
2677-
case SILFunctionType::Representation::Thick:
2678-
// All function types look like () -> ().
2679-
// FIXME: It'd be nice not to have to call through the runtime here.
2680-
return IGF.emitTypeMetadataRef(
2681-
CanFunctionType::get({}, C.TheEmptyTupleType),
2682-
request).getMetadata();
2683-
case SILFunctionType::Representation::Block:
2684-
// All block types look like AnyObject.
2685-
return emitDirectMetadataRef(C.getAnyObjectType(), request);
2686-
}
2687-
2688-
llvm_unreachable("Not a valid SILFunctionType.");
2635+
// Note: we drop @escaping and @autoclosure which can still appear on
2636+
// materializable tuple types.
2637+
//
2638+
// FIXME: Replace this with an assertion that the original tuple element
2639+
// did not have any flags.
2640+
loweredElts.emplace_back(loweredSubstEltType, substElt.getName(),
2641+
ParameterTypeFlags());
26892642
}
26902643

2691-
llvm::Value *visitAnyMetatypeType(CanAnyMetatypeType type,
2692-
DynamicMetadataRequest request) {
2693-
2694-
assert(type->hasRepresentation()
2695-
&& "not a lowered metatype");
2644+
if (!changed)
2645+
return ty;
26962646

2697-
switch (type->getRepresentation()) {
2698-
case MetatypeRepresentation::Thin:
2699-
// Thin metatypes are empty, so they look like the empty tuple type.
2700-
return emitEmptyTupleTypeMetadataRef(IGF.IGM);
2647+
// The cast should succeed, because if we end up with a one-element
2648+
// tuple type here, it must have a label.
2649+
return cast<TupleType>(
2650+
CanType(TupleType::get(loweredElts, ty->getASTContext())));
2651+
}
27012652

2702-
case MetatypeRepresentation::Thick:
2703-
case MetatypeRepresentation::ObjC:
2704-
// Thick and ObjC metatypes look like pointers with extra inhabitants.
2705-
// Get the metatype metadata from the runtime.
2706-
// FIXME: It'd be nice not to need a runtime call here; we should just
2707-
// have a standard aligned-pointer type metadata.
2708-
return IGF.emitTypeMetadataRef(type);
2709-
}
2653+
CanType visitAnyFunctionType(CanAnyFunctionType ty) {
2654+
llvm_unreachable("not a SIL type");
2655+
}
27102656

2711-
llvm_unreachable("Not a valid MetatypeRepresentation.");
2712-
}
2657+
CanType visitSILFunctionType(CanSILFunctionType ty) {
2658+
// All function types have the same layout regardless of arguments or
2659+
// abstraction level. Use the metadata for () -> () for thick functions,
2660+
// or AnyObject for block functions.
2661+
auto &C = ty->getASTContext();
2662+
switch (ty->getRepresentation()) {
2663+
case SILFunctionType::Representation::Thin:
2664+
case SILFunctionType::Representation::Method:
2665+
case SILFunctionType::Representation::WitnessMethod:
2666+
case SILFunctionType::Representation::ObjCMethod:
2667+
case SILFunctionType::Representation::CFunctionPointer:
2668+
case SILFunctionType::Representation::Closure:
2669+
// A thin function looks like a plain pointer.
2670+
// FIXME: Except for extra inhabitants?
2671+
return C.TheRawPointerType;
2672+
case SILFunctionType::Representation::Thick:
2673+
// All function types look like () -> ().
2674+
// FIXME: It'd be nice not to have to call through the runtime here.
2675+
return CanFunctionType::get({}, C.TheEmptyTupleType);
2676+
case SILFunctionType::Representation::Block:
2677+
// All block types look like AnyObject.
2678+
return C.getAnyObjectType();
2679+
}
2680+
2681+
llvm_unreachable("Not a valid SILFunctionType.");
2682+
}
27132683

2714-
/// Try to find the metatype in local data.
2715-
llvm::Value *tryGetLocal(CanType type, DynamicMetadataRequest request) {
2716-
auto response = IGF.tryGetLocalTypeMetadataForLayout(
2717-
SILType::getPrimitiveObjectType(type),
2718-
request);
2719-
assert(request.canResponseStatusBeIgnored());
2720-
return (response ? response.getMetadata() : nullptr);
2721-
}
2684+
CanType visitAnyMetatypeType(CanAnyMetatypeType ty) {
2685+
assert(ty->hasRepresentation() && "not a lowered metatype");
2686+
auto &C = ty->getASTContext();
2687+
switch (ty->getRepresentation()) {
2688+
case MetatypeRepresentation::Thin:
2689+
// Thin metatypes are empty, so they look like the empty tuple type.
2690+
return C.TheEmptyTupleType;
27222691

2723-
/// Set the metatype in local data.
2724-
llvm::Value *setLocal(CanType type, MetadataResponse response) {
2725-
IGF.setScopedLocalTypeMetadataForLayout(
2726-
SILType::getPrimitiveObjectType(type),
2727-
response);
2728-
return response.getMetadata();
2692+
case MetatypeRepresentation::Thick:
2693+
case MetatypeRepresentation::ObjC:
2694+
// Thick and ObjC metatypes look like pointers with extra inhabitants.
2695+
// Get the metatype metadata from the runtime.
2696+
// FIXME: It'd be nice not to need a runtime call here; we should just
2697+
// have a standard aligned-pointer type metadata.
2698+
return ty;
27292699
}
27302700

2731-
};
2701+
llvm_unreachable("Not a valid MetatypeRepresentation.");
2702+
}
2703+
};
27322704
} // end anonymous namespace
27332705

27342706
llvm::Value *IRGenFunction::emitTypeMetadataRefForLayout(SILType type) {
27352707
return emitTypeMetadataRefForLayout(type, MetadataState::Complete);
27362708
}
27372709

27382710
llvm::Value *
2739-
IRGenFunction::emitTypeMetadataRefForLayout(SILType type,
2711+
IRGenFunction::emitTypeMetadataRefForLayout(SILType ty,
27402712
DynamicMetadataRequest request) {
27412713
assert(request.canResponseStatusBeIgnored());
2742-
return EmitTypeMetadataRefForLayout(*this).visit(type.getASTType(),
2743-
request);
2714+
2715+
if (auto response =
2716+
tryGetLocalTypeMetadataForLayout(ty.getObjectType(), request)) {
2717+
assert(request.canResponseStatusBeIgnored() || !response.isValid());
2718+
return response.getMetadata();
2719+
}
2720+
2721+
// Map to a layout equivalent AST type.
2722+
auto layoutEquivalentType =
2723+
EmitTypeMetadataRefForLayout().visit(ty.getASTType());
2724+
auto response = emitTypeMetadataRef(layoutEquivalentType, request);
2725+
setScopedLocalTypeMetadataForLayout(ty.getObjectType(), response);
2726+
return response.getMetadata();
27442727
}
27452728

27462729
namespace {

test/IRGen/class_update_callback_without_fixed_layout.sil

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,13 @@ bb0(%0 : $ClassWithResilientField):
320320
// CHECK-NEXT: [[T1:%.*]] = insertvalue %swift.metadata_response [[T0]], [[INT]] [[NEW_STATUS]], 1
321321
// CHECK-NEXT: ret %swift.metadata_response [[T1]]
322322

323+
// Make sure we cache the construction of fully bound optional types.
324+
325+
// CHECK-LABEL: define internal swiftcc %swift.metadata_response @"$s42class_update_callback_without_fixed_layout21ClassWithResilientRefCMr"
326+
// CHECK: call swiftcc %swift.metadata_response @"$s16resilient_struct12ResilientRefVSgMa"
327+
// CHECK: ret
328+
329+
// CHECK-LABEL: define linkonce_odr hidden swiftcc %swift.metadata_response @"$s16resilient_struct12ResilientRefVSgMa"
330+
// CHECK: call swiftcc %swift.metadata_response @"$s16resilient_struct12ResilientRefVMa"
331+
// CHECK: call swiftcc %swift.metadata_response @"$sSqMa"
332+
// CHECK: ret

0 commit comments

Comments
 (0)