Skip to content

Commit f840191

Browse files
committed
Emit call to old initialization function for older OSes
Add test Update raw_layout.swift Update raw_layout.swift
1 parent df17f7b commit f840191

File tree

6 files changed

+171
-6
lines changed

6 files changed

+171
-6
lines changed

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,10 @@ class ASTContext final {
937937
/// descriptors.
938938
AvailabilityContext getSignedDescriptorAvailability();
939939

940+
/// Get the runtime availability of the swift_initRawStructMetadata entrypoint
941+
/// that fixes up the value witness table of @_rawLayout dependent types.
942+
AvailabilityContext getInitRawStructMetadataAvailability();
943+
940944
/// Get the runtime availability of features introduced in the Swift 5.2
941945
/// compiler for the target platform.
942946
AvailabilityContext getSwift52Availability();

lib/AST/Availability.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,11 @@ ASTContext::getSignedDescriptorAvailability() {
540540
return getSwift59Availability();
541541
}
542542

543+
AvailabilityContext
544+
ASTContext::getInitRawStructMetadataAvailability() {
545+
return getSwiftFutureAvailability();
546+
}
547+
543548
AvailabilityContext ASTContext::getSwift52Availability() {
544549
auto target = LangOpts.Target;
545550

lib/IRGen/GenMeta.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2983,10 +2983,106 @@ static void emitInitializeFieldOffsetVectorWithLayoutString(
29832983
IGM.getPointerSize() * numFields);
29842984
}
29852985

2986+
static void emitInitializeRawLayoutOld(IRGenFunction &IGF, SILType likeType,
2987+
Size count, SILType T,
2988+
llvm::Value *metadata,
2989+
MetadataDependencyCollector *collector) {
2990+
auto &IGM = IGF.IGM;
2991+
2992+
// This is the list of field type layouts that we're going to pass to the init
2993+
// function. This will only ever hold 1 field which is the temporary one we're
2994+
// going to build up from our like type's layout.
2995+
auto fieldLayouts = IGF.createAlloca(
2996+
llvm::ArrayType::get(IGM.TypeLayoutTy->getPointerTo(), 1),
2997+
IGM.getPointerAlignment(), "fieldLayouts");
2998+
IGF.Builder.CreateLifetimeStart(fieldLayouts, IGM.getPointerSize());
2999+
3000+
// We're going to pretend that this is our field offset vector for the init to
3001+
// write to. We don't actually have fields, so we don't want to write a field
3002+
// offset in our metadata.
3003+
auto fieldOffsets = IGF.createAlloca(IGM.Int32Ty, Alignment(4), "fieldOffsets");
3004+
IGF.Builder.CreateLifetimeStart(fieldOffsets, Size(4));
3005+
3006+
// We need to make a temporary type layout with most of the same information
3007+
// from the type we're like.
3008+
auto ourTypeLayout = IGF.createAlloca(IGM.TypeLayoutTy,
3009+
IGM.getPointerAlignment(),
3010+
"ourTypeLayout");
3011+
IGF.Builder.CreateLifetimeStart(ourTypeLayout, IGM.getPointerSize());
3012+
3013+
// Put our temporary type layout in the list of layouts we're using to
3014+
// initialize.
3015+
IGF.Builder.CreateStore(ourTypeLayout.getAddress(), fieldLayouts);
3016+
3017+
// Get the like type's type layout.
3018+
auto likeTypeLayout = emitTypeLayoutRef(IGF, likeType, collector);
3019+
3020+
// Grab the size, stride, and alignmentMask out of the layout.
3021+
auto loadedTyLayout = IGF.Builder.CreateLoad(
3022+
Address(likeTypeLayout, IGM.TypeLayoutTy, IGM.getPointerAlignment()),
3023+
"typeLayout");
3024+
auto size = IGF.Builder.CreateExtractValue(loadedTyLayout, 0, "size");
3025+
auto stride = IGF.Builder.CreateExtractValue(loadedTyLayout, 1, "stride");
3026+
auto flags = IGF.Builder.CreateExtractValue(loadedTyLayout, 2, "flags");
3027+
auto xi = IGF.Builder.CreateExtractValue(loadedTyLayout, 3, "xi");
3028+
3029+
// This will zero out the other bits.
3030+
auto alignMask = IGF.Builder.CreateAnd(flags,
3031+
ValueWitnessFlags::AlignmentMask,
3032+
"alignMask");
3033+
3034+
// Set the isNonPOD bit. This is important because older runtimes will attempt
3035+
// to replace various vwt functions with more optimized ones. In this case, we
3036+
// want to preserve the fact that noncopyable types have unreachable copy vwt
3037+
// functions.
3038+
auto vwtFlags = IGF.Builder.CreateOr(alignMask,
3039+
ValueWitnessFlags::IsNonPOD,
3040+
"vwtFlags");
3041+
3042+
// Count is only ever -1 if we're not an array like layout.
3043+
if (count != Size(-1)) {
3044+
stride = IGF.Builder.CreateMul(stride, IGM.getSize(count));
3045+
size = stride;
3046+
}
3047+
3048+
llvm::Value *resultAgg = llvm::UndefValue::get(IGM.TypeLayoutTy);
3049+
resultAgg = IGF.Builder.CreateInsertValue(resultAgg, size, 0);
3050+
resultAgg = IGF.Builder.CreateInsertValue(resultAgg, stride, 1);
3051+
resultAgg = IGF.Builder.CreateInsertValue(resultAgg, vwtFlags, 2);
3052+
resultAgg = IGF.Builder.CreateInsertValue(resultAgg, xi, 3);
3053+
3054+
IGF.Builder.CreateStore(resultAgg, ourTypeLayout);
3055+
3056+
StructLayoutFlags fnFlags = StructLayoutFlags::Swift5Algorithm;
3057+
3058+
// Call swift_initStructMetadata().
3059+
IGF.Builder.CreateCall(IGM.getInitStructMetadataFunctionPointer(),
3060+
{metadata, IGM.getSize(Size(uintptr_t(fnFlags))),
3061+
IGM.getSize(Size(1)), fieldLayouts.getAddress(),
3062+
fieldOffsets.getAddress()});
3063+
3064+
IGF.Builder.CreateLifetimeEnd(ourTypeLayout, IGM.getPointerSize());
3065+
IGF.Builder.CreateLifetimeEnd(fieldOffsets, Size(4));
3066+
IGF.Builder.CreateLifetimeEnd(fieldLayouts, IGM.getPointerSize());
3067+
}
3068+
29863069
static void emitInitializeRawLayout(IRGenFunction &IGF, SILType likeType,
29873070
Size count, SILType T,
29883071
llvm::Value *metadata,
29893072
MetadataDependencyCollector *collector) {
3073+
// If our deployment target doesn't contain the new swift_initRawStructMetadata,
3074+
// emit a call to the swift_initStructMetadata tricking it into thinking
3075+
// we have a single field.
3076+
auto deploymentAvailability =
3077+
AvailabilityContext::forDeploymentTarget(IGF.IGM.Context);
3078+
auto initRawAvail = IGF.IGM.Context.getInitRawStructMetadataAvailability();
3079+
3080+
if (!IGF.IGM.Context.LangOpts.DisableAvailabilityChecking &&
3081+
!deploymentAvailability.isContainedIn(initRawAvail)) {
3082+
emitInitializeRawLayoutOld(IGF, likeType, count, T, metadata, collector);
3083+
return;
3084+
}
3085+
29903086
auto &IGM = IGF.IGM;
29913087
auto likeTypeLayout = emitTypeLayoutRef(IGF, likeType, collector);
29923088
StructLayoutFlags flags = StructLayoutFlags::Swift5Algorithm;

test/IRGen/raw_layout.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %{python} %utils/chex.py < %s > %t/raw_layout.sil
3-
// RUN: %target-swift-frontend -enable-experimental-feature RawLayout -emit-ir %t/raw_layout.sil | %FileCheck %t/raw_layout.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
3+
// RUN: %target-swift-frontend -enable-experimental-feature RawLayout -emit-ir -disable-availability-checking %t/raw_layout.sil | %FileCheck %t/raw_layout.sil --check-prefix=CHECK --check-prefix=CHECK-%target-ptrsize
44

55
import Swift
66

test/IRGen/raw_layout_old.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: %target-swift-frontend -target %target-cpu-apple-macosx13.0 -enable-experimental-feature RawLayout -emit-ir %s | %FileCheck %s
2+
3+
// REQUIRES: OS=macosx
4+
5+
// Test that when targeting older OSes
6+
7+
@_rawLayout(like: T)
8+
struct Cell<T>: ~Copyable {}
9+
10+
@_rawLayout(likeArrayOf: T, count: 1)
11+
struct PaddedCell<T>: ~Copyable {}
12+
13+
@_rawLayout(likeArrayOf: T, count: 8)
14+
struct SmallVectorBuf<T>: ~Copyable {}
15+
16+
// Dependent layout metadata initialization:
17+
18+
// Cell<T>
19+
20+
// CHECK-LABEL: define {{.*}} swiftcc %swift.metadata_response @"$s{{[A-Za-z0-9_]*}}4CellVMr"(ptr %"Cell<T>", ptr {{.*}}, ptr {{.*}})
21+
// CHECK: [[FIELD_LAYOUTS:%.*]] = alloca [1 x ptr]
22+
// CHECK-NEXT: [[FIELD_OFFSETS:%.*]] = alloca i32, align 4
23+
// CHECK-NEXT: [[OUR_LAYOUT:%.*]] = alloca %swift.type_layout
24+
// CHECK: store ptr [[OUR_LAYOUT]], ptr [[FIELD_LAYOUTS]]
25+
// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds ptr, ptr %"Cell<T>", {{i64|i32}} 2
26+
// CHECK-NEXT: [[T:%.*]] = load ptr, ptr [[T_ADDR]]
27+
// CHECK-NEXT: [[RESPONSE:%.*]] = call swiftcc %swift.metadata_response @swift_checkMetadataState({{i64|i32}} 319, ptr [[T]])
28+
// CHECK-NEXT: [[T:%.*]] = extractvalue %swift.metadata_response [[RESPONSE]], 0
29+
// CHECK: [[T_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[T]], {{i64|i32}} -1
30+
// CHECK-NEXT: [[T_VWT:%.*]] = load ptr, ptr [[T_VWT_ADDR]]
31+
// CHECK-NEXT: [[T_LAYOUT:%.*]] = getelementptr inbounds ptr, ptr [[T_VWT]], i32 8
32+
// CHECK-NEXT: [[T_LAYOUT_LOADED:%.*]] = load %swift.type_layout, ptr [[T_LAYOUT]]
33+
// CHECK-NEXT: [[T_SIZE:%.*]] = extractvalue %swift.type_layout [[T_LAYOUT_LOADED]], 0
34+
// CHECK-NEXT: [[T_STRIDE:%.*]] = extractvalue %swift.type_layout [[T_LAYOUT_LOADED]], 1
35+
// CHECK-NEXT: [[T_FLAGS:%.*]] = extractvalue %swift.type_layout [[T_LAYOUT_LOADED]], 2
36+
// CHECK-NEXT: [[T_XI:%.*]] = extractvalue %swift.type_layout [[T_LAYOUT_LOADED]], 3
37+
// CHECK-NEXT: [[T_ALIGNMASK:%.*]] = and i32 [[T_FLAGS]], 255
38+
// CHECK-NEXT: [[OUR_FLAGS:%.*]] = or i32 [[T_ALIGNMASK]], 65536
39+
// CHECK-NEXT: [[OUR_LAYOUT_0:%.*]] = insertvalue %swift.type_layout undef, {{i64|i32}} [[T_SIZE]], 0
40+
// CHECK-NEXT: [[OUR_LAYOUT_1:%.*]] = insertvalue %swift.type_layout [[OUR_LAYOUT_0]], {{i64|i32}} [[T_STRIDE]], 1
41+
// CHECK-NEXT: [[OUR_LAYOUT_2:%.*]] = insertvalue %swift.type_layout [[OUR_LAYOUT_1]], i32 [[OUR_FLAGS]], 2
42+
// CHECK-NEXT: [[OUR_LAYOUT_3:%.*]] = insertvalue %swift.type_layout [[OUR_LAYOUT_2]], i32 [[T_XI]], 3
43+
// CHECK-NEXT: store %swift.type_layout [[OUR_LAYOUT_3]], ptr [[OUR_LAYOUT]]
44+
// CHECK-NEXT: call void @swift_initStructMetadata(ptr %"Cell<T>", {{i64|i32}} 0, {{i64|i32}} 1, ptr [[FIELD_LAYOUTS]], ptr [[FIELD_OFFSETS]])
45+
46+
// PaddedCell<T>
47+
48+
// CHECK-LABEL: define {{.*}} swiftcc %swift.metadata_response @"$s{{[A-Za-z0-9_]*}}10PaddedCellVMr"(ptr %"PaddedCell<T>", ptr {{.*}}, ptr {{.*}})
49+
// CHECK: [[T_STRIDE:%.*]] = extractvalue %swift.type_layout {{%.*}}, 1
50+
// CHECK: [[OUR_STRIDE:%.*]] = mul {{i64|i32}} [[T_STRIDE]], 1
51+
// CHECK-NEXT: {{%.*}} = insertvalue %swift.type_layout undef, {{i64|i32}} [[OUR_STRIDE]], 0
52+
// CHECK-NEXT: {{%.*}} = insertvalue %swift.type_layout {{%.*}}, {{i64|i32}} [[OUR_STRIDE]], 1
53+
// CHECK: call void @swift_initStructMetadata(ptr %"PaddedCell<T>", {{i64|i32}} 0, {{i64|i32}} 1, ptr {{%.*}}, ptr {{%.*}})
54+
55+
// SmallVectorBuf<T>
56+
57+
// CHECK-LABEL: define {{.*}} swiftcc %swift.metadata_response @"$s{{[A-Za-z0-9_]*}}14SmallVectorBufVMr"(ptr %"SmallVectorBuf<T>", ptr {{.*}}, ptr {{.*}})
58+
// CHECK: [[T_STRIDE:%.*]] = extractvalue %swift.type_layout {{%.*}}, 1
59+
// CHECK: [[OUR_STRIDE:%.*]] = mul {{i64|i32}} [[T_STRIDE]], 8
60+
// CHECK-NEXT: {{%.*}} = insertvalue %swift.type_layout undef, {{i64|i32}} [[OUR_STRIDE]], 0
61+
// CHECK-NEXT: {{%.*}} = insertvalue %swift.type_layout {{%.*}}, {{i64|i32}} [[OUR_STRIDE]], 1
62+
// CHECK: call void @swift_initStructMetadata(ptr %"SmallVectorBuf<T>", {{i64|i32}} 0, {{i64|i32}} 1, ptr {{%.*}}, ptr {{%.*}})

test/Interpreter/raw_layout.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ struct Cell<T>: ~Copyable {
1414
}
1515

1616
deinit {
17-
address.deinitialize(count: 1)
17+
// FIXME: discard self should work with rawLayout types
18+
//address.deinitialize(count: 1)
1819

1920
// Note: We don't need to deallocate the address here because the memory it
2021
// points to is being destroyed within this deinit.
@@ -58,14 +59,11 @@ do {
5859

5960
let specialInt0Again = cell0.replace(with: SpecialInt(316))
6061

61-
// CHECK: Deinitializing 128!
62-
_ = consume specialInt0Again
63-
6462
// CHECK: Deinitializing 316!
6563
cell0.set(SpecialInt(592))
6664

6765
let specialInt1 = cell0.get()
6866

6967
// CHECK: Deinitializing 592!
70-
_ = consume specialInt1
68+
// CHECK: Deinitializing 128!
7169
}

0 commit comments

Comments
 (0)